void BaseMesh::GenerateNormals() { UINT vc = VertexCount(), ic = IndexCount(); MeshVertex *V = Vertices(); DWORD *I = Indices(); Vec3f V1, V2, Normal; for(UINT i = 0; i < vc; i++) { V[i].Normal = Vec3f::Origin; //zero each normal } for(UINT i = 0; i < ic; i += 3) //for every triangle { V1 = V[I[i+2]].Pos - V[I[i+0]].Pos; V2 = V[I[i+1]].Pos - V[I[i+0]].Pos; Normal = Vec3f::Cross(V1, V2); //compute the triangle normal V[I[i+0]].Normal += Normal; V[I[i+1]].Normal += Normal; V[I[i+2]].Normal += Normal; //each adjacent vertex adds the triangle normal to its summed normal } NormalizeNormals(); }
static void TransformTriMesh( const TQ3Matrix4x4* inMatrix, TQ3GeometryObject ioGeom ) { TQ3TriMeshData* tmData = NULL; Q3TriMesh_LockData( ioGeom, kQ3False, &tmData ); // Points Q3Point3D_To3DTransformArray( tmData->points, inMatrix, tmData->points, tmData->numPoints, sizeof(TQ3Point3D), sizeof(TQ3Point3D) ); // Normal vectors must be transformed by the inverse transpose of the // transformation matrix. TQ3Matrix4x4 normalTrans; Q3Matrix4x4_Invert( inMatrix, &normalTrans ); Q3Matrix4x4_Transpose( &normalTrans, &normalTrans ); // vertex normal vectors TQ3Vector3D* normals = FindNormals( tmData->vertexAttributeTypes, tmData->numVertexAttributeTypes ); if (normals != NULL) { Q3Vector3D_To3DTransformArray( normals, &normalTrans, normals, tmData->numPoints, sizeof(TQ3Vector3D), sizeof(TQ3Vector3D) ); NormalizeNormals( normals, tmData->numPoints ); } // face normal vectors normals = FindNormals( tmData->triangleAttributeTypes, tmData->numTriangleAttributeTypes ); if (normals != NULL) { Q3Vector3D_To3DTransformArray( normals, &normalTrans, normals, tmData->numTriangles, sizeof(TQ3Vector3D), sizeof(TQ3Vector3D) ); NormalizeNormals( normals, tmData->numTriangles ); } // Recompute the bounding box Q3BoundingBox_SetFromPoints3D( &tmData->bBox, tmData->points, tmData->numPoints, sizeof(TQ3Point3D) ); // Note: Q3TriMesh_UnlockData will automatically normalize normal vectors. Q3TriMesh_UnlockData( ioGeom ); }
void TMesh::AverageNormals(bool bNormalize) { DEBUG_VERIFY_ALLOCATION; size_t i; TVertex* pVertex; const TFace* pFace; pVertex = m_Vertices.GetDataPtr(); for(i = m_Vertices.GetN() ; i ; i--, pVertex++) pVertex->m_Normal.Set(0.0f, 0.0f, 0.0f); // Summing pFace = m_Faces.GetDataPtr(); for(i = m_Faces.GetN() ; i ; i--, pFace++) { TVertex& Vertex1 = m_Vertices[pFace->v1]; TVertex& Vertex2 = m_Vertices[pFace->v2]; TVertex& Vertex3 = m_Vertices[pFace->v3]; const TVector3& Coords1 = Vertex1.m_Coords; const TVector3& Coords2 = Vertex2.m_Coords; const TVector3& Coords3 = Vertex3.m_Coords; TVector3 FaceNormal = (Coords2 - Coords1) * (Coords3 - Coords1); Vertex1.m_Normal += FaceNormal; Vertex2.m_Normal += FaceNormal; Vertex3.m_Normal += FaceNormal; } // Normalizing if(bNormalize) NormalizeNormals(); }
IFXRESULT CIFXAuthorMeshScrub::Scrub( IFXAuthorMesh* pInAuthorMesh, IFXAuthorMesh** ppOutAuthorMesh, IFXAuthorMeshMap** ppOutMeshMap, IFXAuthorMeshScrubParams* pInParams, IFXProgressCallback* pInProgressCallback) { IFXRESULT result = IFX_OK; if(!pInAuthorMesh || !ppOutAuthorMesh) { result = IFX_E_INVALID_POINTER; } /** @todo FIXME - deallocate any update records -- should ideally be just a parameter to the copy call below indicating that no CLOD/update data is to be copied. */ m_pParams = pInParams; m_pProgressCallback = pInProgressCallback; if(IFXSUCCESS(result) && !m_pParams) { m_pParams = &s_Params; } if(IFXSUCCESS(result)) { if(m_pParams->bOperatateInPlace) { m_pScrubMesh = pInAuthorMesh; m_pScrubMesh->AddRef(); } else { result = pInAuthorMesh->Copy(IID_IFXAuthorMesh, (void**)&m_pScrubMesh); } } // Build the mapping table if(IFXSUCCESS(result)) { result = IFXCreateComponent(CID_IFXAuthorMeshMap, IID_IFXAuthorMeshMap, (void **)&m_pMeshMap); } if(IFXSUCCESS(result)) { result = m_pMeshMap->Allocate(m_pScrubMesh); } // Get the Mesh Description if(IFXSUCCESS(result)) { m_OriginalMeshDesc = *(m_pScrubMesh->GetMaxMeshDesc()); m_ScrubbedMeshDesc = *(m_pScrubMesh->GetMaxMeshDesc()); } if(IFXSUCCESS(result) && m_pProgressCallback) { CalcProgressSteps(); } // Allocate Temp storage array if(IFXSUCCESS(result) ) { m_TempBufferSize = sizeof(U32) * ( IFXMAX(m_ScrubbedMeshDesc.NumFaces, IFXMAX(m_ScrubbedMeshDesc.NumPositions, IFXMAX(m_ScrubbedMeshDesc.NumNormals, IFXMAX(m_ScrubbedMeshDesc.NumSpecularColors, IFXMAX(m_ScrubbedMeshDesc.NumDiffuseColors, IFXMAX(m_ScrubbedMeshDesc.NumTexCoords, IFXMAX(m_ScrubbedMeshDesc.NumMaterials, m_ScrubbedMeshDesc.NumBaseVertices)))))))); m_pTempBuffer = new U32[m_TempBufferSize]; } Lock(); if(IFXSUCCESS(result) && m_pParams->bInvalidIndices) { result = RemoveInvalidIndices(); if(IFXSUCCESS(result)) { result = UpdateProgress(); } } if(IFXSUCCESS(result) && m_pParams->bZeroAreaFaces) { result = RemoveZeroAreaFaces(); if(IFXSUCCESS(result)) { result = UpdateProgress(); } } if(IFXSUCCESS(result) && m_pParams->bNormalizeNormals) { result = NormalizeNormals(); if(IFXSUCCESS(result)) { result = UpdateProgress(); } } if(IFXSUCCESS(result) && m_pParams->bUnusedAttributes) { if(IFXSUCCESS(result) && m_pParams->RemoveUnusedMaterials) { result = RemoveUnusedMaterials(); } if(IFXSUCCESS(result) && m_pParams->RemoveUnusedPositions) { result = RemoveUnusedPositions(); } if(IFXSUCCESS(result) && m_pParams->RemoveUnusedNormals) { result = RemoveUnusedNormals(); } if(IFXSUCCESS(result) && m_pParams->RemoveUnusedDiffuseColors && m_ScrubbedMeshDesc.NumDiffuseColors) { result = RemoveUnusedDiffuseColors(); } if(IFXSUCCESS(result) && m_pParams->RemoveUnusedSpecularColors && m_ScrubbedMeshDesc.NumSpecularColors) { result = RemoveUnusedSpecularColors(); } if(IFXSUCCESS(result) && m_pParams->RemoveUnusedTextureCoordinates && m_ScrubbedMeshDesc.NumTexCoords) { result = RemoveUnusedTexCoords(); } if(IFXSUCCESS(result)) { result = UpdateProgress(); } } // Resize the Scrubbed Mesh - to remove wasted space if(IFXSUCCESS(result)) { result = m_pScrubMesh->Reallocate(&m_ScrubbedMeshDesc); } if(IFXSUCCESS(result)) { result = m_pScrubMesh->SetMeshDesc(m_pScrubMesh->GetMaxMeshDesc()); } if(IFXSUCCESS(result)) { BuildOutputMeshMap(); } Unlock(); if(IFXSUCCESS(result)) { // Releasing these components is left to the caller *ppOutAuthorMesh = m_pScrubMesh; *ppOutMeshMap = m_pMeshMap; } else { *ppOutAuthorMesh = NULL; *ppOutMeshMap = NULL; IFXRELEASE(m_pScrubMesh); IFXRELEASE(m_pMeshMap); } IFXDELETE_ARRAY(m_pTempBuffer); m_TempBufferSize = 0; return result; }