void Mesh::CalculateBackfaces(const Maths::Vector4& cameraPos) { for ( int i = 0; i < m_numPolys; ++i ) { Maths::Vector4 a = ( m_transformed[ m_polys[i].Indices[0] ].Position ) - ( m_transformed[ m_polys[i].Indices[1] ].Position ); Maths::Vector4 b = ( m_transformed[ m_polys[i].Indices[2] ].Position ) - ( m_transformed[ m_polys[i].Indices[1] ].Position ); Maths::Vector4 c = b.CrossProduct(a); Maths::Vector4 d; m_polys[i].Normal = c; c.Normalize(); m_polys[i].NormalN = c; Vector4 p = m_transformed[ m_polys[i].Indices[0] ].Position - cameraPos; if ( p.DotProduct(c) > 0.0f ) { m_polys[i].IsCulled = true; m_transformed[ m_polys[i].Indices[0] ].IsCulled = true; m_transformed[ m_polys[i].Indices[1] ].IsCulled = true; m_transformed[ m_polys[i].Indices[2] ].IsCulled = true; } else { m_polys[i].IsCulled = false; m_transformed[ m_polys[i].Indices[0] ].IsCulled = false; m_transformed[ m_polys[i].Indices[1] ].IsCulled = false; m_transformed[ m_polys[i].Indices[2] ].IsCulled = false; } } }
void OcclusionBuffer::ClipVertices(const Vector4& plane, Vector4* vertices, bool* triangles, unsigned& numTriangles) { unsigned num = numTriangles; for (unsigned i = 0; i < num; ++i) { if (triangles[i]) { unsigned index = i * 3; float d0 = plane.DotProduct(vertices[index]); float d1 = plane.DotProduct(vertices[index + 1]); float d2 = plane.DotProduct(vertices[index + 2]); // If all vertices behind the plane, reject triangle if (d0 < 0.0f && d1 < 0.0f && d2 < 0.0f) { triangles[i] = false; continue; } // If 2 vertices behind the plane, create a new triangle in-place else if (d0 < 0.0f && d1 < 0.0f) { vertices[index] = ClipEdge(vertices[index], vertices[index + 2], d0, d2); vertices[index + 1] = ClipEdge(vertices[index + 1], vertices[index + 2], d1, d2); } else if (d0 < 0.0f && d2 < 0.0f) { vertices[index] = ClipEdge(vertices[index], vertices[index + 1], d0, d1); vertices[index + 2] = ClipEdge(vertices[index + 2], vertices[index + 1], d2, d1); } else if (d1 < 0.0f && d2 < 0.0f) { vertices[index + 1] = ClipEdge(vertices[index + 1], vertices[index], d1, d0); vertices[index + 2] = ClipEdge(vertices[index + 2], vertices[index], d2, d0); } // 1 vertex behind the plane: create one new triangle, and modify one in-place else if (d0 < 0.0f) { unsigned newIdx = numTriangles * 3; triangles[numTriangles] = true; ++numTriangles; vertices[newIdx] = ClipEdge(vertices[index], vertices[index + 2], d0, d2); vertices[newIdx + 1] = vertices[index] = ClipEdge(vertices[index], vertices[index + 1], d0, d1); vertices[newIdx + 2] = vertices[index + 2]; } else if (d1 < 0.0f) { unsigned newIdx = numTriangles * 3; triangles[numTriangles] = true; ++numTriangles; vertices[newIdx + 1] = ClipEdge(vertices[index + 1], vertices[index], d1, d0); vertices[newIdx + 2] = vertices[index + 1] = ClipEdge(vertices[index + 1], vertices[index + 2], d1, d2); vertices[newIdx] = vertices[index]; } else if (d2 < 0.0f) { unsigned newIdx = numTriangles * 3; triangles[numTriangles] = true; ++numTriangles; vertices[newIdx + 2] = ClipEdge(vertices[index + 2], vertices[index + 1], d2, d1); vertices[newIdx] = vertices[index + 2] = ClipEdge(vertices[index + 2], vertices[index], d2, d0); vertices[newIdx + 1] = vertices[index + 1]; } } } }
bool Mesh::CullPolygons(const ViewFrustum& frustum, const Maths::Vector4& camPos) { int cullCount = 0; for ( int i = 0; i < m_numPolys; ++i ) { if ( m_polys[i].IsCulled ) { cullCount++; continue; } int count = 0; for ( int vv = 0; vv < 3; ++vv ) { //Vector4 point = m_transformed[ m_polys[i].Indices[vv] ].Position - camPos; Vector4 point = m_transformed[ m_polys[i].Indices[vv] ].Position - m_verts[ m_polys[i].Indices[vv] ]; float result = point.DotProduct( frustum.Left.Normal ); if ( result > 0.0f ) { count++; m_transformed[ m_polys[i].Indices[vv] ].IsCulled = true; continue; } result = point.DotProduct( frustum.Right.Normal ); if ( result > 0.0f ) { count++; m_transformed[ m_polys[i].Indices[vv] ].IsCulled = true; continue; } result = point.DotProduct( frustum.Top.Normal ); if ( result > 0.0f ) { count++; m_transformed[ m_polys[i].Indices[vv] ].IsCulled = true; continue; } result = point.DotProduct( frustum.Bottom.Normal ); if ( result > 0.0f ) { count++; m_transformed[ m_polys[i].Indices[vv] ].IsCulled = true; continue; } //result = point.DotProduct( frustum.Near.Normal ); //if ( result > 0.0f ) //{ // count++; // m_transformed[ m_polys[i].Indices[vv] ].IsCulled = true; // continue; //} //result = point.DotProduct( frustum.Far.Normal ); //if ( result > 0.0f ) //{ // count++; // m_transformed[ m_polys[i].Indices[vv] ].IsCulled = true; // continue; //} } if ( count == 3 ) { cullCount++; m_polys[i].IsCulled = true; } } return ( cullCount == m_numPolys ); }
void Mesh::CalculateLightingPoint( const std::vector<LightPoint>& light, int numLight, const Maths::Vector4& camera) { Maths::Vector4 l; Maths::Vector4 temp, result, n, p; Maths::Vector4 cof( 1.0f, 1.0f, 10.0f ); BYTE r, g, b; float distance = 0; float att = 0; float a = 0.05f; float bb = 0.05f; float c = 0.05f; float dif, spec; m_noLight = false; for ( int i = 0; i < m_numVerts; ++i ) { if ( !m_transformed[i].IsCulled ) { result.X = 0; //Red result.Y = 0; //green result.Z = 0; //blue for ( int j = 0; j < numLight; ++j ) { p = light[j].Position; l = p - m_transformed[i].Position; distance = l.Length(); //calculate the attenuation value att = 1 / (a + ( distance * bb ) + ( distance * distance ) * c ); if ( att < 0 ) att = 0; temp.X = light[j].Colour.GetR(); temp.Y = light[j].Colour.GetG(); temp.Z = light[j].Colour.GetB(); n = m_transformed[i].Normal; n.Normalize(); dif = max( 0.0, l.DotProduct( n ) ) * att; // calculate the speculation //Vector4 toEye = m_transformed[i].Position - camera; //Vector4 half = camera + p / 2; //toEye.Normalize(); //half.Normalize(); //float specPower = 1.0f; //float spec = pow( max( n.DotProduct( half ), 0.0f ), specPower ) * att; Vector4 toEye = m_transformed[i].Position - camera; Vector4 reflect = ( n - l ) * ( 2 * ( n.DotProduct( l ) ) ); toEye.Normalize(); reflect.Normalize(); float specPower = 1.0f; float spec = pow( max( reflect.DotProduct( toEye ), 0.0f ), specPower ) * att; temp.X = temp.X * ( (dif + spec) * m_kd_red ); temp.Y = temp.Y * ( (dif + spec) * m_kd_green ); temp.Z = temp.Z * ( (dif + spec) * m_kd_blue ); //temp.X = temp.X * ( dif * m_kd_red ) ); //temp.Y = temp.Y * ( dif * m_kd_green ) ); //temp.Z = temp.Z * ( dif * m_kd_blue ) ); result += temp; } //set colour if ( result.X > 255.0f ) result.X = 255.0f; if ( result.Y > 255.0f ) result.Y = 255.0f; if ( result.Z > 255.0f ) result.Z = 255.0f; if ( result.X < 0.0f ) result.X = 0.0f; if ( result.Y < 0.0f ) result.Y = 0.0f; if ( result.Z < 0.0f ) result.Z = 0.0f; r = (BYTE)result.X; g = (BYTE)result.Y; b = (BYTE)result.Z; m_transformed[i].Colour = Gdiplus::Color::MakeARGB( 255, r, g, b ); } } }
void Mesh::CalculateLightingDirectional(const LightDirectional& light, int numLights, const Vector4& camera) { Maths::Vector4 total; Maths::Vector4 temp; Maths::Vector4 l( light.Position.X, light.Position.Y, light.Position.Z, 1.0f ); Maths::Vector4 n( 0, 0, 0, 0 ); BYTE r, g, b; float diff, spec = 0; m_noLight = false; l.Normalize(); for ( int i = 0; i < m_numVerts; ++i ) { if ( !m_transformed[i].IsCulled ) { //reset the colout to black total.X = 0; //Red total.Y = 0; //green total.Z = 0; //blue for ( int j = 0; j < numLights; ++j ) { Maths::Vector4 d; //modulate intensity with coresponding reflectance co-efficient values temp.X = light.Colour.GetR() * light.Intensity.X; temp.Y = light.Colour.GetG() * light.Intensity.Y; temp.Z = light.Colour.GetB() * light.Intensity.Z; n = m_transformed[i].Normal; n.Normalize(); //attentuate the rgb values with lambertian attenuation diff = max(0.0, l.DotProduct( n )); Vector4 toEye = m_transformed[i].Position - camera; Vector4 reflect = ( n - l ) * ( 2 * ( n.DotProduct( l ) ) ); toEye.Normalize(); reflect.Normalize(); float specPower = 1.0f; spec = pow( max( reflect.DotProduct( toEye ), 0.0f ), specPower ) * 0.01f; if ( diff <= 0.0f ) spec = 0.0f; temp.X = temp.X * ( (diff + spec) * m_kd_red ); temp.Y = temp.Y * ( (diff + spec) * m_kd_green ); temp.Z = temp.Z * ( (diff + spec) * m_kd_blue ); //temp.X = temp.X * ( diff * m_kd_red + spec ) ); //temp.Y = temp.Y * ( diff * m_kd_green + spec ) ); //temp.Z = temp.Z * ( diff * m_kd_blue + spec ) ); total = total + temp; } if ( total.X > 255.0f ) total.X = 255.0f; if ( total.Y > 255.0f ) total.Y = 255.0f; if ( total.Z > 255.0f ) total.Z = 255.0f; if ( total.X < 0.0f ) total.X = 0.0f; if ( total.Y < 0.0f ) total.Y = 0.0f; if ( total.Z < 0.0f ) total.Z = 0.0f; r = (BYTE)total.X; g = (BYTE)total.Y; b = (BYTE)total.Z; m_transformed[i].Colour = Gdiplus::Color::MakeARGB( 255, r, g, b ); } } }
// For Shading Purposes void RT_shade(Ray* ray, int depth) { if (depth <= MAX_DEPTH){ // Color Coefficients Vector4* diffuseCoeff = new Vector4(); Vector4* specularCoeff = new Vector4(); double shininess; // Diffuse and Specular Terms double diffuseTerm[3] = {0.0, 0.0, 0.0}; double specularTerm[3] = {0.0, 0.0, 0.0}; if (ray->intersectedObject == SPHERE) { diffuseCoeff->ReInitialize(spheres[ray->intersectID].color_diffuse); specularCoeff->ReInitialize(spheres[ray->intersectID].color_specular); shininess = spheres[ray->intersectID].shininess; } else if (ray->intersectedObject == TRIANGLE) { // Interpolate diffuse and specular coefficients double alpha, beta; ObtainIntermediateTriangleIntersection(ray->intersectID, ray->intersectPoint, &alpha, &beta); diffuseCoeff->ReInitialize(); InterpolateTriangleProperty(triangles[ray->intersectID].v[0].color_diffuse, triangles[ray->intersectID].v[1].color_diffuse, triangles[ray->intersectID].v[2].color_diffuse, alpha, beta, diffuseCoeff, false); specularCoeff->ReInitialize(); InterpolateTriangleProperty(triangles[ray->intersectID].v[0].color_specular, triangles[ray->intersectID].v[1].color_specular, triangles[ray->intersectID].v[2].color_specular, alpha, beta, specularCoeff, false); // Interpolate shininess if (alpha > 0) { double intermediateShininess = beta * triangles[ray->intersectID].v[2].shininess + (1 - beta) * triangles[ray->intersectID].v[1].shininess; shininess = ((alpha - 1) * triangles[ray->intersectID].v[0].shininess + intermediateShininess) / alpha; } else { shininess = triangles[ray->intersectID].v[0].shininess; } } // Boundary Checking assert(diffuseCoeff->HasNonNegativeEntries()); assert(!diffuseCoeff->HasGreaterThanOneEntries()); assert(specularCoeff->HasNonNegativeEntries()); assert(!specularCoeff->HasGreaterThanOneEntries()); assert(shininess >= 0); // Normal Vector: N Vector4* N = new Vector4(ray->normal); N->ConvertToUnitVector(); // Viewer Direction: V = ray->intersectedPoint - ray->source = -ray->dir Vector4* V = new Vector4(ray->dir); V->Scale(-1); V->ConvertToUnitVector(); int dontCheckObject = NONE; int dontCheckObjectID = NONE; if (ray->intersectedObject == TRIANGLE) { dontCheckObject = ray->intersectedObject; dontCheckObjectID = ray->intersectID; } unsigned int i; for (i = 0; i < num_lights; i++) { // Shoot a ray in the direction of the light Vector4* lightPos = new Vector4(lights[i].position); Ray* checkShadow = new Ray(ray->intersectPoint, lightPos); bool shadow = false; double nearestTIntersect = FindNearestTIntersection(checkShadow,dontCheckObject,dontCheckObjectID); double point2LightDistance = FindDistanceOfIntersectedPointWithLight(ray,i); if (nearestTIntersect != INFINITY && nearestTIntersect< point2LightDistance) { shadow = true; } // Point to Light Vector: L = light_pos - intersectedPoint Vector4* L = new Vector4(lights[i].position); L->Subtraction(ray->intersectPoint); L->ConvertToUnitVector(); // Reflected Ray: R = 2(N.L)N - L Vector4* R = new Vector4(ray->normal); R->Scale(2 * N->DotProduct(L)); R->Subtraction(L); R->ConvertToUnitVector(); // Dot Product of N and L: NL double NL = N->DotProduct(L); if (NL < 0) { NL = 0; } // Dot Product of R and V: RV double RV = R->DotProduct(V); if (RV < 0) { RV = 0; } assert(NL <= 1 && RV <= 1); double attenuationTerm = depth==1?1:1; if (!shadow) { unsigned int j; for (j = 0; j < 3; j++) { diffuseTerm[j] += attenuationTerm * lights[i].color[j] * diffuseCoeff->vector[j] * NL; specularTerm[j] += attenuationTerm * lights[i].color[j] * specularCoeff->vector[j] * pow(RV, shininess); } } delete(L); delete(R); delete(lightPos); delete(checkShadow); } // Adding diffused light Vector4* diffusedColor = new Vector4(diffuseTerm); // //For Debugging Purposes // if(ray->intersectedObject == SPHERE){ // ray->color->Display(); // diffusedColor->Display(); // cout<<"................................................."<<endl; // } ray->color->Addition(diffusedColor); delete(diffusedColor); // Adding specular light Vector4* specularColor = new Vector4(specularTerm); ray->color->Addition(specularColor); delete(specularColor); //R = 2*(NI)N - I ; N = N; I = V = ray->source - ray->IntersectPoint Vector4* R_ = new Vector4(ray->normal); Vector4* I = new Vector4(ray->dir); I->Scale(-1); R_->Scale(2*N->DotProduct(I)); R_->Subtraction(I); Vector4* end = new Vector4(ray->intersectPoint); end->Addition(R_); Ray* reflectedRay = new Ray(ray->intersectPoint, end); delete(R_); delete(I); delete(end); assert(dontCheckObject!=SPHERE); RT_trace(reflectedRay, depth+1, dontCheckObject, dontCheckObjectID); //For Debugging // if(ray->intersectedObject==TRIANGLE/* && ray->intersectPoint->vector[1]<-2*screenX/4 // && ray->intersectPoint->vector[1]>-3*screenX/4*/){ // cout<<ray->intersectID; // cout<<"---->"; // ray->normal->Display(); // cout<<"------>"; // I->Display(); // cout<<I->DotProduct(ray->normal)<<"\t"; // cout<<reflectedRay->dir->DotProduct(ray->normal); // reflectedRay->dir->Display(); // cout<<": "<<reflectedRay->tIntersect<<"\t"; // reflectedRay->color->Display(); // cout<<endl; // } if(reflectedRay->tIntersect!=INFINITY){ reflectedRay->color->Scale(specularCoeff->vector[0], specularCoeff->vector[1], specularCoeff->vector[2]); ray->color->Addition(reflectedRay->color); } delete(reflectedRay); delete(N); delete(V); delete(specularCoeff); delete(diffuseCoeff); } }
double FindNearestTIntersectionWithTriangle(Ray* ray, int* index, int noCheckID = NONE){ assert(noCheckID==NONE || (noCheckID>=0 && noCheckID<num_triangles)); double nearestTIntersect = INFINITY; *index = NONE; unsigned int i; for (i = 0; i < num_triangles; i++) { if (i==noCheckID){ continue; } // Vertices V0, V1 and V2 Vector4* V0 = new Vector4(triangles[i].v[0].position); Vector4* V1 = new Vector4(triangles[i].v[1].position); Vector4* V2 = new Vector4(triangles[i].v[2].position); // Edges: VOV1, V0V2 Vector4* V0V1 = new Vector4(V1); V0V1->Subtraction(V0); Vector4* V0V2 = new Vector4(V2); V0V2->Subtraction(V0); // Normal: N = V0V1 X V0V2 Vector4* N = new Vector4(V0V1); N->CrossProductPost(V0V2); N->ConvertToUnitVector(); // ray and normal should be opposite if (N->DotProduct(ray->dir)>0){ N->Scale(-1); } // N = [A B C] // AX0 + BY0 + CZ0 + D = 0 double D = -1*N->DotProduct(V0); if (N->DotProduct(ray->dir) != (double) 0) { // t = -(N.Ro + D)/ (N.Rd) double candidateT = -1 * (N->DotProduct(ray->source) + D) / N->DotProduct(ray->dir); if (candidateT > 0){ // P = Ro + tRd Vector4* point = new Vector4(ray->dir); point->Scale(candidateT); point->Addition(ray->source); // alpha*V0V1 + beta*V0V2 = V0P Vector4* V0P = new Vector4(point); V0P->Subtraction(V0); double alpha = 0.0; double beta = 0.0; //(x01)alpha + (x02)beta = x0p; //(y01)alpha + (y02)beta = y0p; //(z01)alpha + (z02)beta = z0p; double A1 = V0V1->vector[0]; double B1 = V0V2->vector[0]; double C1 = V0P->vector[0]; double A2 = V0V1->vector[1]; double B2 = V0V2->vector[1]; double C2 = V0P->vector[1]; double A3 = V0V1->vector[2]; double B3 = V0V2->vector[2]; double C3 = V0P->vector[2]; SolveLinearEquation(A1, B1, C1, A2, B2, C2, &alpha, &beta); if (alpha == NONE) { SolveLinearEquation(A2, B2, C2, A3, B3, C3, &alpha, &beta); } if (alpha == NONE) { SolveLinearEquation(A1, B1, C1, A3, B3, C3, &alpha, &beta); } // // For Debugging Purposes // printf("\nTriangle: %d ==> CandidateT: %f ==> (%f,%f)",i,candidateT,alpha,beta); if (alpha > 0 && beta > 0 && (alpha + beta) < 1) { if (nearestTIntersect > candidateT) { nearestTIntersect = candidateT; *index = i; } } delete(V0P); delete(point); } } delete(N); delete(V0V2); delete(V0V1); delete(V2); delete(V1); delete(V0); } return nearestTIntersect; }