const Triangle& FullEdge::GetOtherTriangle(const Triangle &TCompare) const { if(GetTriangle(0) == TCompare) { return GetTriangle(1); } if(GetTriangle(1) == TCompare) { return GetTriangle(0); } SignalError("FullEdge::GetOtherTriangle failed"); return Triangle::Invalid; }
Vec3f FullEdge::ComputeLoopSubdivisionPos() { if(Boundary()) { return 0.5f * (GetVertex(0).Pos() + GetVertex(1).Pos()); } else { Vertex &VOpposite0 = GetTriangle(0).GetOtherVertex(*this); Vertex &VOpposite1 = GetTriangle(1).GetOtherVertex(*this); return (1.0f / 8.0f) * (VOpposite0.Pos() + VOpposite1.Pos()) + (3.0f / 8.0f) * (GetVertex(0).Pos() + GetVertex(1).Pos()); } }
double Mesh::ComputeVolume() const { const size_t nV = GetNPoints(); const size_t nT = GetNTriangles(); if (nV == 0 || nT == 0) { return 0.0; } Vec3<double> bary(0.0, 0.0, 0.0); for (size_t v = 0; v < nV; v++) { bary += GetPoint(v); } bary /= static_cast<double>(nV); Vec3<double> ver0, ver1, ver2; double totalVolume = 0.0; for(size_t t = 0; t < nT; t++) { const Vec3<int> & tri = GetTriangle(t); ver0 = GetPoint(tri[0]); ver1 = GetPoint(tri[1]); ver2 = GetPoint(tri[2]); totalVolume += ComputeVolume4(ver0, ver1, ver2, bary); } return totalVolume/6.0; }
void Convert_shape_line_polygon_to_triangles( SHAPE_POLY_SET &aPolyList, CGENERICCONTAINER2D &aDstContainer, float aBiuTo3DunitsScale , const BOARD_ITEM &aBoardItem ) { aPolyList.CacheTriangulation(); const double conver_d = (double)aBiuTo3DunitsScale; for( unsigned int j = 0; j < aPolyList.TriangulatedPolyCount(); j++ ) { auto triPoly = aPolyList.TriangulatedPolygon( j ); for( size_t i = 0; i < triPoly->GetTriangleCount(); i++ ) { VECTOR2I a; VECTOR2I b; VECTOR2I c; triPoly->GetTriangle( i, a, b, c ); aDstContainer.Add( new CTRIANGLE2D( SFVEC2F( a.x * conver_d, -a.y * conver_d ), SFVEC2F( b.x * conver_d, -b.y * conver_d ), SFVEC2F( c.x * conver_d, -c.y * conver_d ), aBoardItem ) ); } } }
void SubMesh::DrawImmediate() { if (!loaded) return; glBegin(GL_TRIANGLES); for (int i = 0; i < meshInfo.triCount; ++i) { Triangle t = GetTriangle(i); if (HasTextureCoords()) { for (int j = 0; j < 3; ++j) { VertexPositionTexcoord* vpt = GetVertexData<VertexPositionTexcoord>(t.index[j]); glVertex3fv(vpt->position); glTexCoord2fv(vpt->texCoord); } } else { for (int j = 0; j < 3; ++j) { VertexPositionNormalTexcoord* vpnt = GetVertexData<VertexPositionNormalTexcoord>(t.index[j]); glVertex3fv(vpnt->position); if (HasNormals()) glNormal3fv(vpnt->normal); if (HasTextureCoords()) glTexCoord2fv(vpnt->texCoord); } } } glEnd(); }
int DelaunayTriangle::NeighbourReference(int t) { DelaunayTriangle* pNeighbourTriangle = GetTriangle(t); if (pNeighbourTriangle == 0) { return -1; } if (pNeighbourTriangle->GetTriangle(0) == this) { return 0; } else if (pNeighbourTriangle->GetTriangle(1) == this) { return 1; } else if (pNeighbourTriangle->GetTriangle(2) == this) { return 2; } else { assert(false); return -1; } }
LTriangle2 LMesh::GetTriangle2(uint index) { LTriangle2 f; LTriangle t = GetTriangle(index); f.vertices[0] = GetVertex(t.a); f.vertices[1] = GetVertex(t.b); f.vertices[2] = GetVertex(t.c); f.vertexNormals[0] = GetNormal(t.a); f.vertexNormals[1] = GetNormal(t.b); f.vertexNormals[2] = GetNormal(t.c); f.textureCoords[0] = GetUV(t.a); f.textureCoords[1] = GetUV(t.b); f.textureCoords[2] = GetUV(t.c); LVector3 a, b; a = SubtractVectors(_4to3(f.vertices[1]), _4to3(f.vertices[0])); b = SubtractVectors(_4to3(f.vertices[1]), _4to3(f.vertices[2])); f.faceNormal = CrossProduct(b, a); f.faceNormal = NormalizeVector(f.faceNormal); f.materialId = m_tris[index].materialId; return f; }
void STLTopology :: SaveBinary (const char* filename, const char* aname) const { ofstream ost(filename); PrintFnStart("Write STL binary file '",filename,"'"); if (sizeof(int) != 4 || sizeof(float) != 4) {PrintWarning("for stl-binary compatibility only use 32 bit compilation!!!");} //specific settings for stl-binary format const int namelen = 80; //length of name of header in file const int nospaces = 2; //number of spaces after a triangle //write header: aname int i, j; char buf[namelen+1]; int strend = 0; for(i = 0; i <= namelen; i++) { if (aname[i] == 0) {strend = 1;} if (!strend) {buf[i] = aname[i];} else {buf[i] = 0;} } FIOWriteString(ost,buf,namelen); PrintMessage(5,"header = ",buf); //RWrite Number of facets int nofacets = GetNT(); FIOWriteInt(ost,nofacets); PrintMessage(5,"NO facets = ", nofacets); float f; char spaces[nospaces+1]; for (i = 0; i < nospaces; i++) {spaces[i] = ' ';} spaces[nospaces] = 0; for (i = 1; i <= GetNT(); i++) { const STLTriangle & t = GetTriangle(i); const Vec<3> & n = t.Normal(); f = n(0); FIOWriteFloat(ost,f); f = n(1); FIOWriteFloat(ost,f); f = n(2); FIOWriteFloat(ost,f); for (j = 1; j <= 3; j++) { const Point3d p = GetPoint(t.PNum(j)); f = p.X(); FIOWriteFloat(ost,f); f = p.Y(); FIOWriteFloat(ost,f); f = p.Z(); FIOWriteFloat(ost,f); } FIOWriteString(ost,spaces,nospaces); } PrintMessage(5,"done"); }
int TriMesh::ClosestPoint(const Vector3& pt,Vector3& cp) const { int tmin=-1; Real dmin=Inf; Vector3 temp; Triangle3D tri; for(size_t i=0;i<tris.size();i++) { GetTriangle(i,tri); temp = tri.closestPoint(pt); Real d2=temp.distanceSquared(pt); if(d2 < dmin) { tmin = (int)i; dmin = d2; cp = temp; } } return tmin; }
int TriMesh::RayCast(const Ray3D& r,Vector3& pt) const { int tmin=-1; Real dmin=Inf; Real d; Vector2 uv; Triangle3D tri; for(size_t i=0;i<tris.size();i++) { GetTriangle(i,tri); if(tri.rayIntersects(r,&d,&uv.x,&uv.y)) { if(d < dmin) { tmin = (int)i; dmin = d; pt = tri.planeCoordsToPoint(uv); } } } return tmin; }
bool MeshDecimator::ManifoldConstraint(long v1, long v2) const { std::set<long> vertices; long a, b; long idEdge1; long idEdge2; long idEdgeV1V2 = 0; for(size_t itE1 = 0; itE1 < m_vertices[v1].m_edges.Size(); ++itE1) { idEdge1 = m_vertices[v1].m_edges[itE1]; a = (m_edges[idEdge1].m_v1 == v1) ? m_edges[idEdge1].m_v2 : m_edges[idEdge1].m_v1; vertices.insert(a); if (a != v2) { for(size_t itE2 = 0; itE2 < m_vertices[v2].m_edges.Size(); ++itE2) { idEdge2 = m_vertices[v2].m_edges[itE2]; b = (m_edges[idEdge2].m_v1 == v2) ? m_edges[idEdge2].m_v2 : m_edges[idEdge2].m_v1; vertices.insert(b); if ( a==b ) { if (GetTriangle(v1, v2, a) == -1) { return false; } } } } else { idEdgeV1V2 = idEdge1; } } if (vertices.size() <= 4 || ( m_vertices[v1].m_onBoundary && m_vertices[v2].m_onBoundary && !m_edges[idEdgeV1V2].m_onBoundary)) { return false; } return true; }
void STLTopology :: SaveSTLE (const char* filename) const { ofstream outf (filename); int i, j; outf << GetNT() << endl; for (i = 1; i <= GetNT(); i++) { const STLTriangle & t = GetTriangle(i); for (j = 1; j <= 3; j++) { const Point3d p = GetPoint(t.PNum(j)); outf << p.X() << " " << p.Y() << " " << p.Z() << endl; } } int ned = 0; for (i = 1; i <= GetNTE(); i++) { if (GetTopEdge (i).GetStatus() == ED_CONFIRMED) ned++; } outf << ned << endl; for (i = 1; i <= GetNTE(); i++) { const STLTopEdge & edge = GetTopEdge (i); if (edge.GetStatus() == ED_CONFIRMED) for (j = 1; j <= 2; j++) { const Point3d p = GetPoint(edge.PNum(j)); outf << p.X() << " " << p.Y() << " " << p.Z() << endl; } } }
bool Mesh::IsInside(const Vec3<double> & pt) const { const size_t nV = GetNPoints(); const size_t nT = GetNTriangles(); if (nV == 0 || nT == 0) { return false; } Vec3<double> ver0, ver1, ver2; double volume; for (size_t t = 0; t < nT; t++) { const Vec3<int> & tri = GetTriangle(t); ver0 = GetPoint(tri[0]); ver1 = GetPoint(tri[1]); ver2 = GetPoint(tri[2]); volume = ComputeVolume4(ver0, ver1, ver2, pt); if (volume < 0.0) { return false; } } return true; }
Plane Mesh::GetPlane(int index) { Triangle T; T = GetTriangle(index); return Plane(T.normal, T.vertexes[0]); }
bool FullEdge::Boundary() const { return (GetTriangle(1) == Triangle::Boundary); }
void MeshDecimator::EdgeCollapse(long v1, long v2) { long u, w; int shift; long idTriangle; for(size_t itT = 0; itT < m_vertices[v2].m_triangles.Size(); ++itT) { idTriangle = m_vertices[v2].m_triangles[itT]; if (m_triangles[idTriangle].X() == v2) { shift = 0; u = m_triangles[idTriangle].Y(); w = m_triangles[idTriangle].Z(); } else if (m_triangles[idTriangle].Y() == v2) { shift = 1; u = m_triangles[idTriangle].X(); w = m_triangles[idTriangle].Z(); } else { shift = 2; u = m_triangles[idTriangle].X(); w = m_triangles[idTriangle].Y(); } if ((u == v1) || (w == v1)) { m_trianglesTags[idTriangle] = false; m_vertices[u].m_triangles.Erase(idTriangle); m_vertices[w].m_triangles.Erase(idTriangle); m_nTriangles--; } else if (GetTriangle(v1, u, w) == -1) { m_vertices[v1].m_triangles.Insert(idTriangle); m_triangles[idTriangle][shift] = v1; } else { m_trianglesTags[idTriangle] = false; m_vertices[u].m_triangles.Erase(idTriangle); m_vertices[w].m_triangles.Erase(idTriangle); m_nTriangles--; } } long idEdge = 0; for(size_t itE = 0; itE < m_vertices[v2].m_edges.Size(); ++itE) { idEdge = m_vertices[v2].m_edges[itE]; w = (m_edges[idEdge].m_v1 == v2)? m_edges[idEdge].m_v2 : m_edges[idEdge].m_v1; if (w==v1) { m_edges[idEdge].m_tag = false; m_vertices[w].m_edges.Erase(idEdge); m_nEdges--; } else if ( GetEdge(v1, w) == -1) { if (m_edges[idEdge].m_v1 == v2) m_edges[idEdge].m_v1 = v1; else m_edges[idEdge].m_v2 = v1; m_vertices[v1].m_edges.Insert(idEdge); } else { m_edges[idEdge].m_tag = false; m_vertices[w].m_edges.Erase(idEdge); m_nEdges--; } } m_vertices[v2].m_tag = false; m_nVertices--; // update boundary edges SArray<long, 64> incidentVertices; incidentVertices.PushBack(v1); for(size_t itE = 0; itE < m_vertices[v1].m_edges.Size(); ++itE) { incidentVertices.PushBack((m_edges[idEdge].m_v1!= v1)?m_edges[idEdge].m_v1:m_edges[idEdge].m_v2); idEdge = m_vertices[v1].m_edges[itE]; m_edges[idEdge].m_onBoundary = (IsBoundaryEdge(m_edges[idEdge].m_v1, m_edges[idEdge].m_v2) != -1); } // update boundary vertices long idVertex; for(size_t itV = 0; itV < incidentVertices.Size(); ++itV) { idVertex = incidentVertices[itV]; m_vertices[idVertex].m_onBoundary = false; for(size_t itE = 0; itE < m_vertices[idVertex].m_edges.Size(); ++itE) { idEdge = m_vertices[idVertex].m_edges[itE]; if (m_edges[idEdge].m_onBoundary) { m_vertices[idVertex].m_onBoundary = true; break; } } } }
Void TriangleMesh::_ComputeDerivateNormals( Matrix4 * outDerivateNormals, UInt iVertexCount, UInt iTriangleCount, const Byte * arrPositions, const Byte * arrNormals, UInt iVertexSize ) const { // Create temp storage Matrix4 * arrProjTangents = New Matrix4[iVertexCount]; Matrix4 * arrDeltaTangents = New Matrix4[iVertexCount]; MemZero( arrProjTangents, iVertexCount * sizeof(Matrix4) ); MemZero( arrDeltaTangents, iVertexCount * sizeof(Matrix4) ); // Compute projected & delta tangents UInt i, iRow, iCol; UInt iTriangle[3]; UInt iA, iB, iC; const Vertex4 *pA, *pB, *pC; const Vector4 *pNormA, *pNormB, *pNormC; Vector3 vEdge, vProj, vDelta; Matrix4 matInverse; for( i = 0; i < iTriangleCount; ++i ) { GetTriangle( i, iTriangle[0], iTriangle[1], iTriangle[2] ); iTriangle[0] *= iVertexSize; iTriangle[1] *= iVertexSize; iTriangle[2] *= iVertexSize; for( UInt j = 0; j < 3; ++j ) { iA = iTriangle[j]; iB = iTriangle[(j+1)%3]; iC = iTriangle[(j+2)%3]; pA = (const Vertex4 *)( arrPositions + iA ); pB = (const Vertex4 *)( arrPositions + iB ); pC = (const Vertex4 *)( arrPositions + iC ); pNormA = (const Vector4 *)( arrNormals + iA ); pNormB = (const Vector4 *)( arrNormals + iB ); pNormC = (const Vector4 *)( arrNormals + iC ); // Edge AB, project on tangent plane at A then // compute delta of adjacent normals vEdge = ( *pB - *pA ); vProj = vEdge - ( (*pNormA) * (vEdge * (*pNormA)) ); vDelta = ( (*pNormB) - (*pNormA) ); for( iRow = 0; iRow < 3; ++iRow ) { for( iCol = 0; iCol < 3; ++iCol ) { arrProjTangents[iA](iRow, iCol) += ( vProj[iRow] * vProj[iCol] ); arrDeltaTangents[iA](iRow, iCol) += ( vDelta[iRow] * vProj[iCol] ); } } // Edge AC, project on tangent plane at A then // compute delta of adjacent normals vEdge = ( *pC - *pA ); vProj = vEdge - ( (*pNormA) * (vEdge * (*pNormA)) ); vDelta = ( (*pNormC) - (*pNormA) ); for( iRow = 0; iRow < 3; ++iRow ) { for( iCol = 0; iCol < 3; ++iCol ) { arrProjTangents[iA](iRow, iCol) += ( vProj[iRow] * vProj[iCol] ); arrDeltaTangents[iA](iRow, iCol) += ( vDelta[iRow] * vProj[iCol] ); } } } } // Compute derivate normals for( i = 0; i < iVertexCount; ++i ) { pNormA = (const Vector4 *)( arrNormals + (i * iVertexSize) ); // Add N*N^T to W*W^T for numerical stability. // In theory 0*0^T is added to D*W^T. for( iRow = 0; iRow < 3; ++iRow ) { for( iCol = 0; iCol < 3; ++iCol ) { arrProjTangents[i](iRow, iCol) *= 0.5f; arrProjTangents[i](iRow, iCol) += ( (*pNormA)[iRow] * (*pNormA)[iCol] ); arrDeltaTangents[i](iRow, iCol) *= 0.5f; } } arrProjTangents[i].Invert( matInverse ); outDerivateNormals[i] = ( arrDeltaTangents[i] * matInverse ); } // Destroy temp storage DeleteA( arrProjTangents ); DeleteA( arrDeltaTangents ); }
Void TriangleMesh::UpdateTangentsFromTexCoords( GPUDeferredContext * pContext ) { Assert( m_pIL != NULL && m_pVB != NULL ); Assert( m_pIL->IsBound() && m_pVB->IsBound() ); Bool bHasNormals = m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_NORMAL, 0 ); Bool bHasTexCoords = m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_TEXCOORD, 0 ); if ( !bHasNormals || !bHasTexCoords ) return; Bool bHasTangents = m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_TANGENT, 0 ); Bool bHasBiNormals = m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_BINORMAL, 0 ); if ( !bHasTangents && !bHasBiNormals ) return; // Begin update Byte * pFirstVertex = NULL; if ( m_pVB->CanUpdate() ) { Assert( m_pVB->HasCPUData() ); pFirstVertex = m_pVB->GetData( m_iVertexOffset ); } else { Assert( m_pVB->CanLock() ); UInt iByteSize = 0; pFirstVertex = (Byte*)( m_pVB->Lock( GPURESOURCE_LOCK_WRITE, 0, &iByteSize, pContext ) ); Assert( iByteSize == m_pVB->GetSize() ); } // Update UInt iVertexSize = m_pVB->GetElementSize(); UInt iOffset, iSize; const Byte * arrPositions = NULL; const Byte * arrNormals = NULL; const Byte * arrTexCoords = NULL; Byte * arrTangents = NULL; Byte * arrBiNormals = NULL; m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_POSITION, 0 ); arrPositions = ( pFirstVertex + iOffset ); m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_NORMAL, 0 ); arrNormals = ( pFirstVertex + iOffset ); m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_TEXCOORD, 0 ); arrTexCoords = ( pFirstVertex + iOffset ); if ( bHasTangents ) { m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_TANGENT, 0 ); arrTangents = ( pFirstVertex + iOffset ); } if ( bHasBiNormals ) { m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_BINORMAL, 0 ); arrBiNormals = ( pFirstVertex + iOffset ); } UInt i, iTriangleCount = GetTriangleCount(); // Set all to null vector Byte *pCurTangent, *pCurBiNormal; Vector4 *pTangent, *pBiNormal; if ( bHasTangents ) { pCurTangent = arrTangents; for( i = 0; i < m_iVertexCount; ++i ) { pTangent = (Vector4*)pCurTangent; *pTangent = Vector4::Null; pCurTangent += iVertexSize; } } if ( bHasBiNormals ) { pCurBiNormal = arrBiNormals; for( i = 0; i < m_iVertexCount; ++i ) { pBiNormal = (Vector4*)pCurBiNormal; *pBiNormal = Vector4::Null; pCurBiNormal += iVertexSize; } } // Visit all vertices UInt iA, iB, iC; const Vertex4 * arrPositionABC[3]; const Vector4 * arrNormalABC[3]; const TextureCoord2 * arrTexCoordABC[3]; Vector4 * arrTangentABC[3]; Vector4 * arrBiNormalABC[3]; UInt j, iNext, iPrev; Vector4 vCur; Vector4 vNormal, vTangent, vBiNormal; for( i = 0; i < iTriangleCount; ++i ) { GetTriangle( i, iA, iB, iC ); iA *= iVertexSize; iB *= iVertexSize; iC *= iVertexSize; arrPositionABC[0] = (const Vertex4 *)( arrPositions + iA ); arrPositionABC[1] = (const Vertex4 *)( arrPositions + iB ); arrPositionABC[2] = (const Vertex4 *)( arrPositions + iC ); arrNormalABC[0] = (const Vector4 *)( arrNormals + iA ); arrNormalABC[1] = (const Vector4 *)( arrNormals + iB ); arrNormalABC[2] = (const Vector4 *)( arrNormals + iC ); arrTexCoordABC[0] = (const TextureCoord2 *)( arrTexCoords + iA ); arrTexCoordABC[1] = (const TextureCoord2 *)( arrTexCoords + iB ); arrTexCoordABC[2] = (const TextureCoord2 *)( arrTexCoords + iC ); if ( bHasTangents ) { arrTangentABC[0] = (Vector4 *)( arrTangents + iA ); arrTangentABC[1] = (Vector4 *)( arrTangents + iB ); arrTangentABC[2] = (Vector4 *)( arrTangents + iC ); } if ( bHasBiNormals ) { arrBiNormalABC[0] = (Vector4 *)( arrBiNormals + iA ); arrBiNormalABC[1] = (Vector4 *)( arrBiNormals + iB ); arrBiNormalABC[2] = (Vector4 *)( arrBiNormals + iC ); } for( j = 0; j < 3; ++j ) { vCur = ( bHasTangents ) ? *(arrTangentABC[j]) : *(arrBiNormalABC[j]); if ( vCur.X != 0.0f || vCur.Y != 0.0f || vCur.Z != 0.0f ) continue; // already visited iNext = (j+1) % 3; iPrev = (j+2) % 3; // Compute tangent & binormal vNormal = *( arrNormalABC[j] ); vTangent = _ComputeTexCoordTangent( *(arrPositionABC[j]), *(arrTexCoordABC[j]), *(arrPositionABC[iNext]), *(arrTexCoordABC[iNext]), *(arrPositionABC[iPrev]), *(arrTexCoordABC[iPrev]) ); vTangent -= ( vNormal * (vNormal * vTangent) ); vTangent.Normalize(); vBiNormal = ( vNormal ^ vTangent ); // Update if ( bHasTangents ) *( arrTangentABC[j] ) = vTangent; if ( bHasBiNormals ) *( arrBiNormalABC[j] ) = vBiNormal; } } // End update if ( m_pVB->CanUpdate() ) m_pVB->Update( 0, INVALID_OFFSET, pContext ); else m_pVB->UnLock( pContext ); }
Void TriangleMesh::UpdateNormals( GPUDeferredContext * pContext ) { Assert( m_pIL != NULL && m_pVB != NULL ); Assert( m_pIL->IsBound() && m_pVB->IsBound() ); Bool bHasNormals = m_pIL->HasField( GPUINPUTFIELD_SEMANTIC_NORMAL, 0 ); if ( !bHasNormals ) return; // Begin update Byte * pFirstVertex = NULL; if ( m_pVB->CanUpdate() ) { Assert( m_pVB->HasCPUData() ); pFirstVertex = m_pVB->GetData( m_iVertexOffset ); } else { Assert( m_pVB->CanLock() ); UInt iByteSize = 0; pFirstVertex = (Byte*)( m_pVB->Lock( GPURESOURCE_LOCK_WRITE, 0, &iByteSize, pContext ) ); Assert( iByteSize == m_pVB->GetSize() ); } // Update normals UInt iVertexSize = m_pVB->GetElementSize(); UInt iOffset, iSize; const Byte * arrPositions = NULL; Byte * arrNormals = NULL; m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_POSITION, 0 ); arrPositions = ( pFirstVertex + iOffset ); m_pIL->GetFieldRange( &iOffset, &iSize, GPUINPUTFIELD_SEMANTIC_NORMAL, 0 ); arrNormals = ( pFirstVertex + iOffset ); UInt i, iTriangleCount = GetTriangleCount(); // Set all normals to null vector Byte * pCurNormal = arrNormals; Vector4 * pNormal; for( i = 0; i < m_iVertexCount; ++i ) { pNormal = (Vector4*)pCurNormal; pNormal->X = 0.0f; pNormal->Y = 0.0f; pNormal->Z = 0.0f; pCurNormal += iVertexSize; } // Weighted sum of facet normals UInt iA, iB, iC; const Vertex4 *pA, *pB, *pC; Vector4 vAB, vAC, vFaceNormal; for( i = 0; i < iTriangleCount; ++i ) { GetTriangle( i, iA, iB, iC ); iA *= iVertexSize; iB *= iVertexSize; iC *= iVertexSize; pA = (const Vertex4 *)( arrPositions + iA ); pB = (const Vertex4 *)( arrPositions + iB ); pC = (const Vertex4 *)( arrPositions + iC ); vAB = ( *pB - *pA ); vAC = ( *pC - *pA ); vFaceNormal = ( vAB ^ vAC ); vFaceNormal.Normalize(); pNormal = (Vector4*)( arrNormals + iA ); *pNormal += vFaceNormal; pNormal = (Vector4*)( arrNormals + iB ); *pNormal += vFaceNormal; pNormal = (Vector4*)( arrNormals + iC ); *pNormal += vFaceNormal; } // Normalize all again pCurNormal = arrNormals; for( i = 0; i < m_iVertexCount; ++i ) { pNormal = (Vector4*)pCurNormal; pNormal->Normalize(); pCurNormal += iVertexSize; } // End update if ( m_pVB->CanUpdate() ) m_pVB->Update( 0, INVALID_OFFSET, pContext ); else m_pVB->UnLock( pContext ); }