void CAOGenerator::RenderSetupSceneNode(CConversionSceneNode* pNode, tvector<tvector<float>>& aaflVerts) { if (!pNode) return; for (size_t c = 0; c < pNode->GetNumChildren(); c++) RenderSetupSceneNode(pNode->GetChild(c), aaflVerts); for (size_t m = 0; m < pNode->GetNumMeshInstances(); m++) { CConversionMeshInstance* pMeshInstance = pNode->GetMeshInstance(m); CConversionMesh* pMesh = pMeshInstance->GetMesh(); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); size_t iMaterial = pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial; while (aaflVerts.size() <= iMaterial) aaflVerts.push_back(); CConversionVertex* pVertex0 = pFace->GetVertex(0); for (size_t k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); AddRenderedVertex(aaflVerts[iMaterial], pMeshInstance->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddRenderedVertex(aaflVerts[iMaterial], pMeshInstance->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddRenderedVertex(aaflVerts[iMaterial], pMeshInstance->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); } } } }
void CGeppetto::LoadMeshInstanceIntoToyPhysics(CConversionScene* pScene, CConversionMeshInstance* pMeshInstance, const Matrix4x4& mParentTransformations, CToyUtil* pToy) { if (!pMeshInstance->IsVisible()) return; CConversionMesh* pMesh = pMeshInstance->GetMesh(); size_t iVertsSize = pToy->GetNumPhysVerts(); for (size_t v = 0; v < pMesh->GetNumVertices(); v++) pToy->AddPhysVertex(mParentTransformations * pMesh->GetVertex(v)); for (size_t j = 0; j < pMesh->GetNumFaces(); j++) { size_t k; CConversionFace* pFace = pMesh->GetFace(j); CConversionVertex* pVertex0 = pFace->GetVertex(0); for (k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); pToy->AddPhysTriangle(iVertsSize + pVertex0->v, iVertsSize + pVertex1->v, iVertsSize + pVertex2->v); } } }
void CTexelNormalMethod::GenerateTexel(size_t iTexel, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, CConversionVertex* pV1, CConversionVertex* pV2, CConversionVertex* pV3, raytrace::CTraceResult* tr, const Vector& vecUVPosition, raytrace::CRaytracer* pTracer) { CConversionFace* pHitFace = tr->m_pMeshInstance->GetMesh()->GetFace(tr->m_iFace); Vector vecHitNormal = pHitFace->GetNormal(tr->m_vecHit, tr->m_pMeshInstance); // Build rotation matrix Matrix4x4 mObjectToTangent; Vector t = pFace->GetBaseVector(vecUVPosition, 0, pMeshInstance); Vector b = pFace->GetBaseVector(vecUVPosition, 1, pMeshInstance); Vector n = pFace->GetBaseVector(vecUVPosition, 2, pMeshInstance); mObjectToTangent.SetForwardVector(t); mObjectToTangent.SetUpVector(b); mObjectToTangent.SetRightVector(n); mObjectToTangent.InvertRT(); Vector vecTangentNormal = mObjectToTangent*vecHitNormal; m_pGenerator->GetParallelizer()->LockData(); m_avecNormalValues[iTexel] += vecTangentNormal; m_pGenerator->MarkTexelUsed(iTexel); m_pGenerator->GetParallelizer()->UnlockData(); }
void CAOGenerator::GenerateNodeByTexel(CConversionSceneNode* pNode, raytrace::CRaytracer* pTracer, size_t& iRendered) { for (size_t c = 0; c < pNode->GetNumChildren(); c++) GenerateNodeByTexel(pNode->GetChild(c), pTracer, iRendered); for (size_t m = 0; m < pNode->GetNumMeshInstances(); m++) { CConversionMeshInstance* pMeshInstance = pNode->GetMeshInstance(m); CConversionMesh* pMesh = pMeshInstance->GetMesh(); if (!pMesh->GetNumUVs()) continue; for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); if (pFace->m != ~0) { if (!pMeshInstance->GetMappedMaterial(pFace->m)->IsVisible()) continue; CConversionMaterial* pMaterial = m_pScene->GetMaterial(pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial); if (pMaterial && !pMaterial->IsVisible()) continue; } tvector<Vector> avecPoints; tvector<size_t> aiPoints; for (size_t t = 0; t < pFace->GetNumVertices(); t++) { avecPoints.push_back(pMeshInstance->GetVertex(pFace->GetVertex(t)->v)); aiPoints.push_back(t); } while (avecPoints.size() > 3) { size_t iEar = FindEar(avecPoints); size_t iLast = iEar==0?avecPoints.size()-1:iEar-1; size_t iNext = iEar==avecPoints.size()-1?0:iEar+1; GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[iLast], aiPoints[iEar], aiPoints[iNext], pTracer, iRendered); avecPoints.erase(avecPoints.begin()+iEar); aiPoints.erase(aiPoints.begin()+iEar); if (m_bStopGenerating) break; } GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[0], aiPoints[1], aiPoints[2], pTracer, iRendered); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } }
void LoadMeshInstanceIntoToy(CConversionScene* pScene, CConversionMeshInstance* pMeshInstance, const Matrix4x4& mParentTransformations) { if (!pMeshInstance->IsVisible()) return; CConversionMesh* pMesh = pMeshInstance->GetMesh(); for (size_t m = 0; m < pScene->GetNumMaterials(); m++) { for (size_t j = 0; j < pMesh->GetNumFaces(); j++) { size_t k; CConversionFace* pFace = pMesh->GetFace(j); if (pFace->m == ~0) continue; CConversionMaterial* pMaterial = NULL; CConversionMaterialMap* pConversionMaterialMap = pMeshInstance->GetMappedMaterial(pFace->m); if (!pConversionMaterialMap) continue; if (!pConversionMaterialMap->IsVisible()) continue; if (pConversionMaterialMap->m_iMaterial != m) continue; while (g_asTextures.size() <= pConversionMaterialMap->m_iMaterial) { g_asTextures.push_back(pScene->GetMaterial(pConversionMaterialMap->m_iMaterial)->GetDiffuseTexture()); g_aaflData.push_back(); } size_t iMaterial = pConversionMaterialMap->m_iMaterial; CConversionVertex* pVertex0 = pFace->GetVertex(0); for (k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); AddVertex(iMaterial, mParentTransformations * pMesh->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddVertex(iMaterial, mParentTransformations * pMesh->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddVertex(iMaterial, mParentTransformations * pMesh->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); } } } }
void CAOGenerator::GenerateByTexel() { if (m_eAOMethod == AOMETHOD_RAYTRACE) RaytraceSetupThreads(); float flTotalArea = 0; for (size_t m = 0; m < m_pScene->GetNumMeshes(); m++) { CConversionMesh* pMesh = m_pScene->GetMesh(m); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); flTotalArea += pFace->GetUVArea(); } } raytrace::CRaytracer* pTracer = NULL; if (m_eAOMethod == AOMETHOD_RAYTRACE) { m_pWorkListener->SetAction("Building tree", 0); pTracer = new raytrace::CRaytracer(m_pScene); pTracer->AddMeshesFromNode(m_pScene->GetScene(0)); pTracer->BuildTree(); srand((unsigned int)time(0)); } if (m_eAOMethod == AOMETHOD_RAYTRACE && GetNumberOfProcessors() > 1) m_pWorkListener->SetAction("Dispatching jobs", (size_t)(flTotalArea*m_iWidth*m_iHeight)); else m_pWorkListener->SetAction("Rendering", (size_t)(flTotalArea*m_iWidth*m_iHeight)); size_t iRendered = 0; if (m_pScene->GetNumScenes()) GenerateNodeByTexel(m_pScene->GetScene(0), pTracer, iRendered); if (m_eAOMethod == AOMETHOD_RAYTRACE) { RaytraceJoinThreads(); RaytraceCleanupThreads(); delete pTracer; } }
void CAOGenerator::ShadowMapSetupSceneNode(CConversionSceneNode* pNode, tvector<float>& aflVerts, bool bDepth) { if (!pNode) return; for (size_t c = 0; c < pNode->GetNumChildren(); c++) ShadowMapSetupSceneNode(pNode->GetChild(c), aflVerts, bDepth); for (size_t m = 0; m < pNode->GetNumMeshInstances(); m++) { CConversionMeshInstance* pMeshInstance = pNode->GetMeshInstance(m); CConversionMesh* pMesh = pMeshInstance->GetMesh(); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); if (!bDepth) { // Allow this in the depth model so that it still projects a shadow, but we don't produce a map for it. if (pFace->m != ~0 && pMeshInstance->GetMappedMaterial(pFace->m)) { if (!pMeshInstance->GetMappedMaterial(pFace->m)->IsVisible()) continue; CConversionMaterial* pMaterial = m_pScene->GetMaterial(pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial); if (pMaterial && !pMaterial->IsVisible()) continue; } } CConversionVertex* pVertex0 = pFace->GetVertex(0); for (size_t k = 2; k < pFace->GetNumVertices(); k++) { CConversionVertex* pVertex1 = pFace->GetVertex(k-1); CConversionVertex* pVertex2 = pFace->GetVertex(k); AddShadowMapVertex(aflVerts, pMeshInstance->GetVertex(pVertex0->v), pMeshInstance->GetNormal(pVertex0->vn), pMesh->GetUV(pVertex0->vu)); AddShadowMapVertex(aflVerts, pMeshInstance->GetVertex(pVertex1->v), pMeshInstance->GetNormal(pVertex1->vn), pMesh->GetUV(pVertex1->vu)); AddShadowMapVertex(aflVerts, pMeshInstance->GetVertex(pVertex2->v), pMeshInstance->GetNormal(pVertex2->vn), pMesh->GetUV(pVertex2->vu)); } } } }
void CModelConverter::SaveSIA(const tstring& sFilename) { tstring sSIAFileName = tstring(GetDirectory(sFilename).c_str()) + _T("/") + GetFilename(sFilename).c_str() + _T(".sia"); std::wofstream sFile(convertstring<tchar, char>(sSIAFileName).c_str()); if (!sFile.is_open()) return; sFile.precision(8); sFile.setf(std::ios::fixed, std::ios::floatfield); if (m_pWorkListener) { m_pWorkListener->BeginProgress(); m_pWorkListener->SetAction(_T("Writing materials..."), 0); } sFile << _T("-Version 1.0") << std::endl; for (size_t i = 0; i < m_pScene->GetNumMaterials(); i++) { sFile << _T("-Mat") << std::endl; CConversionMaterial* pMaterial = m_pScene->GetMaterial(i); sFile << "-amb " << pMaterial->m_vecAmbient.x << _T(" ") << pMaterial->m_vecAmbient.y << _T(" ") << pMaterial->m_vecAmbient.z << _T(" 0") << std::endl; sFile << "-dif " << pMaterial->m_vecDiffuse.x << _T(" ") << pMaterial->m_vecDiffuse.y << _T(" ") << pMaterial->m_vecDiffuse.z << _T(" 0") << std::endl; sFile << "-spec " << pMaterial->m_vecSpecular.x << _T(" ") << pMaterial->m_vecSpecular.y << _T(" ") << pMaterial->m_vecSpecular.z << _T(" 0") << std::endl; sFile << "-emis " << pMaterial->m_vecEmissive.x << _T(" ") << pMaterial->m_vecEmissive.y << _T(" ") << pMaterial->m_vecEmissive.z << _T(" 0") << std::endl; sFile << "-shin " << pMaterial->m_flShininess << std::endl; sFile << "-name \"" << pMaterial->GetName().c_str() << _T("\"") << std::endl; if (pMaterial->GetDiffuseTexture().length() > 0) sFile << "-tex \"" << pMaterial->GetDiffuseTexture().c_str() << _T("\"") << std::endl; sFile << _T("-endMat") << std::endl; } for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { CConversionMesh* pMesh = m_pScene->GetMesh(i); size_t iAddV = pMesh->GetNumVertices(); size_t iAddE = pMesh->GetNumEdges(); size_t iAddUV = pMesh->GetNumUVs(); size_t iAddN = pMesh->GetNumNormals(); // Find the default scene for this mesh. CConversionSceneNode* pScene = NULL; for (size_t j = 0; j < m_pScene->GetNumScenes(); j++) { if (m_pScene->GetScene(j)->GetName() == pMesh->GetName() + _T(".sia")) { pScene = m_pScene->GetScene(j); break; } } tstring sNodeName = pMesh->GetName(); sFile << _T("-Shape") << std::endl; sFile << _T("-snam \"") << sNodeName.c_str() << _T("\"") << std::endl; sFile << _T("-shad 0") << std::endl; sFile << _T("-shadw 1") << std::endl; if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" vertices...")).c_str(), pMesh->GetNumVertices()); for (size_t iVertices = 0; iVertices < pMesh->GetNumVertices(); iVertices++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iVertices); Vector vecVertex = pMesh->GetVertex(iVertices); sFile << _T("-vert ") << vecVertex.x << _T(" ") << vecVertex.y << _T(" ") << vecVertex.z << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" edges...")).c_str(), pMesh->GetNumEdges()); tstring sCreases; for (size_t iEdges = 0; iEdges < pMesh->GetNumEdges(); iEdges++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iEdges); CConversionEdge* pEdge = pMesh->GetEdge(iEdges); sFile << _T("-edge ") << pEdge->v1 << _T(" ") << pEdge->v2 << std::endl; if (pEdge->m_bCreased) sCreases += sprintf(tstring(" %d"), iEdges); } if (sCreases.length()) sFile << _T("-creas") << sCreases.c_str() << std::endl; if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" faces...")).c_str(), pMesh->GetNumFaces()); size_t iMaterial = 0; for (size_t iFaces = 0; iFaces < pMesh->GetNumFaces(); iFaces++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iFaces); CConversionFace* pFace = pMesh->GetFace(iFaces); if (iFaces == 0 || iMaterial != pFace->m) { iMaterial = pFace->m; if (iMaterial == ~0) sFile << _T("-setmat -1") << std::endl; else { CConversionSceneNode* pNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh, false); if (!pNode || pNode->GetNumMeshInstances() != 1) sFile << _T("-setmat -1") << std::endl; else { CConversionMaterialMap* pMap = pNode->GetMeshInstance(0)->GetMappedMaterial(iMaterial); if (pMap) sFile << _T("-setmat -1") << std::endl; else sFile << _T("-setmat ") << pMap->m_iMaterial << std::endl; } } } sFile << _T("-face ") << pFace->GetNumVertices(); TAssert(pFace->GetNumEdges() == pFace->GetNumVertices()); for (size_t iVertsInFace = 0; iVertsInFace < pFace->GetNumVertices(); iVertsInFace++) { CConversionVertex* pVertex = pFace->GetVertex(iVertsInFace); CConversionVertex* pNextVertex = pFace->GetVertex((iVertsInFace+1)%pFace->GetNumVertices()); // Find the edge that heads in a counter-clockwise direction. size_t iEdge = ~0; for (size_t i = 0; i < pFace->GetNumEdges(); i++) { size_t iEdgeCandidate = pFace->GetEdge(i); CConversionEdge* pEdge = pMesh->GetEdge(iEdgeCandidate); if ((pEdge->v1 == pVertex->v && pEdge->v2 == pNextVertex->v) || (pEdge->v2 == pVertex->v && pEdge->v1 == pNextVertex->v)) { iEdge = iEdgeCandidate; break; } } TAssert(iEdge != ~0); Vector vecUV = pMesh->GetUV(pVertex->vu); sFile << _T(" ") << pVertex->v << _T(" ") << iEdge << _T(" ") << vecUV.x << _T(" ") << vecUV.y; } sFile << std::endl; } sFile << _T("-axis 0 0.5 0 1 0 0 0 1 0 0 0 1") << std::endl; sFile << _T("-mirp 0 0 0 1 0 0") << std::endl; sFile << _T("-endShape") << std::endl; } if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::SaveOBJ(const tstring& sFilename) { tstring sMaterialFileName = tstring(GetDirectory(sFilename).c_str()) + _T("/") + GetFilename(sFilename).c_str() + _T(".mtl"); std::wofstream sMaterialFile(convertstring<tchar, char>(sMaterialFileName).c_str()); if (!sMaterialFile.is_open()) return; if (m_pWorkListener) { m_pWorkListener->BeginProgress(); m_pWorkListener->SetAction(_T("Writing materials file"), 0); } for (size_t i = 0; i < m_pScene->GetNumMaterials(); i++) { CConversionMaterial* pMaterial = m_pScene->GetMaterial(i); sMaterialFile << "newmtl " << pMaterial->GetName().c_str() << std::endl; sMaterialFile << "Ka " << pMaterial->m_vecAmbient.x << _T(" ") << pMaterial->m_vecAmbient.y << _T(" ") << pMaterial->m_vecAmbient.z << std::endl; sMaterialFile << "Kd " << pMaterial->m_vecDiffuse.x << _T(" ") << pMaterial->m_vecDiffuse.y << _T(" ") << pMaterial->m_vecDiffuse.z << std::endl; sMaterialFile << "Ks " << pMaterial->m_vecSpecular.x << _T(" ") << pMaterial->m_vecSpecular.y << _T(" ") << pMaterial->m_vecSpecular.z << std::endl; sMaterialFile << "d " << pMaterial->m_flTransparency << std::endl; sMaterialFile << "Ns " << pMaterial->m_flShininess << std::endl; sMaterialFile << "illum " << pMaterial->m_eIllumType << std::endl; if (pMaterial->GetDiffuseTexture().length() > 0) sMaterialFile << "map_Kd " << pMaterial->GetDiffuseTexture().c_str() << std::endl; sMaterialFile << std::endl; } sMaterialFile.close(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); i++) { CConversionMesh* pMesh = m_pScene->GetMesh(i); // Find the default scene for this mesh. CConversionSceneNode* pScene = NULL; for (size_t j = 0; j < m_pScene->GetNumScenes(); j++) { if (m_pScene->GetScene(j)->GetName() == pMesh->GetName() + _T(".obj")) { pScene = m_pScene->GetScene(j); break; } } tstring sNodeName = pMesh->GetName(); tstring sOBJFilename = tstring(GetDirectory(sFilename).c_str()) + _T("/") + GetFilename(sNodeName).c_str() + _T(".obj"); tstring sMTLFilename = tstring(GetFilename(sFilename).c_str()) + _T(".mtl"); if (m_pScene->GetNumMeshes() == 1) sOBJFilename = sFilename; std::wofstream sOBJFile(convertstring<tchar, char>(sOBJFilename).c_str()); sOBJFile.precision(8); sOBJFile.setf(std::ios::fixed, std::ios::floatfield); sOBJFile << _T("mtllib ") << sMTLFilename.c_str() << std::endl; sOBJFile << std::endl; sOBJFile << _T("o ") << sNodeName.c_str() << std::endl; if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" vertices...")).c_str(), pMesh->GetNumVertices()); for (size_t iVertices = 0; iVertices < pMesh->GetNumVertices(); iVertices++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iVertices); Vector vecVertex = pMesh->GetVertex(iVertices); sOBJFile << _T("v ") << vecVertex.x << _T(" ") << vecVertex.y << _T(" ") << vecVertex.z << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" normals...")).c_str(), pMesh->GetNumNormals()); for (size_t iNormals = 0; iNormals < pMesh->GetNumNormals(); iNormals++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iNormals); Vector vecNormal = pMesh->GetNormal(iNormals); sOBJFile << _T("vn ") << vecNormal.x << _T(" ") << vecNormal.y << _T(" ") << vecNormal.z << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" UVs...")).c_str(), pMesh->GetNumUVs()); for (size_t iUVs = 0; iUVs < pMesh->GetNumUVs(); iUVs++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iUVs); Vector vecUV = pMesh->GetUV(iUVs); sOBJFile << _T("vt ") << vecUV.x << _T(" ") << vecUV.y << std::endl; } if (m_pWorkListener) m_pWorkListener->SetAction((tstring(_T("Writing ")) + sNodeName + _T(" faces...")).c_str(), pMesh->GetNumFaces()); size_t iLastMaterial = ~0; for (size_t iFaces = 0; iFaces < pMesh->GetNumFaces(); iFaces++) { if (m_pWorkListener) m_pWorkListener->WorkProgress(iFaces); CConversionFace* pFace = pMesh->GetFace(iFaces); if (pFace->m != iLastMaterial) { iLastMaterial = pFace->m; CConversionSceneNode* pNode = m_pScene->GetDefaultSceneMeshInstance(pScene, pMesh, false); if (!pNode || pNode->GetNumMeshInstances() != 1) sOBJFile << "usemtl " << iLastMaterial << std::endl; else { CConversionMaterialMap* pMap = pNode->GetMeshInstance(0)->GetMappedMaterial(iLastMaterial); if (!pMap) sOBJFile << "usemtl " << iLastMaterial << std::endl; else sOBJFile << "usemtl " << m_pScene->GetMaterial(pMap->m_iMaterial)->GetName().c_str() << std::endl; } } sOBJFile << _T("f"); for (size_t iVertsInFace = 0; iVertsInFace < pFace->GetNumVertices(); iVertsInFace++) { CConversionVertex* pVertex = pFace->GetVertex(iVertsInFace); sOBJFile << _T(" ") << pVertex->v+1 << _T("/") << pVertex->vu+1 << _T("/") << pVertex->vn+1; } sOBJFile << std::endl; } sOBJFile << std::endl; sOBJFile.close(); } if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CTexelAOMethod::GenerateTexel(size_t iTexel, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, CConversionVertex* pV1, CConversionVertex* pV2, CConversionVertex* pV3, raytrace::CTraceResult* tr, const Vector& vecUVPosition, raytrace::CRaytracer* pTracer) { CConversionFace* pHitFace = tr->m_pMeshInstance->GetMesh()->GetFace(tr->m_iFace); Vector vecHitNormal = pHitFace->GetNormal(tr->m_vecHit, tr->m_pMeshInstance); // Build rotation matrix Matrix4x4 m; m.SetOrientation(vecHitNormal); // Turn it sideways so that pitch 90 is up Matrix4x4 m2; m2.SetAngles(EAngle(-90, 0, 0)); m *= m2; //SMAKWindow()->AddDebugLine(vecUVPosition + pFace->GetNormal()*0.01f, vecUVPosition + vecNormal*0.5f, Color(0, 0, 255)); float flHits = 0; float flTotalHits = 0; for (size_t x = 0; x < m_iSamples/2; x++) { float flRandom = 0; if (m_bRandomize) flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5f, 0.5f); float flPitch = RemapVal(cos(RemapVal((float)x+flRandom, 0, (float)m_iSamples/2, 0, (float)M_PI/2)), 0, 1, 90, 0); float flWeight = sin(flPitch * M_PI/180); for (size_t y = 0; y <= m_iSamples; y++) { flRandom = 0; if (m_bRandomize) flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5f, 0.5f); float flYaw = RemapVal((float)y+flRandom, 0, (float)m_iSamples, -180, 180); Vector vecDir = AngleVector(EAngle(flPitch, flYaw, 0)); // Transform relative to the triangle's normal Vector vecRay = m * vecDir; flTotalHits += flWeight; //SMAKWindow()->AddDebugLine(vecUVPosition + pFace->GetNormal()*0.01f, vecUVPosition + vecRay.Normalized()*0.1f, vecDir); raytrace::CTraceResult tr2; if (pTracer->Raytrace(Ray(tr->m_vecHit + vecHitNormal*0.01f, vecRay), &tr2)) { float flDistance = (tr2.m_vecHit - tr->m_vecHit).Length(); if (m_flRayFalloff < 0) flHits += flWeight; else flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff)); } else if (m_bGroundOcclusion && vecRay.y < 0) { // The following math is basically a plane-ray intersection algorithm, // with shortcuts made for the assumption of an infinite plane facing straight up. Vector n = Vector(0,1,0); float a = -(vecUVPosition.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y); float b = vecRay.y; float flDistance = a/b; if (flDistance < 1e-4f || m_flRayFalloff < 0) flHits += flWeight; else flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff)); } } } // One last ray directly up, it is skipped in the above loop so it's not done 10 times. Vector vecDir = AngleVector(EAngle(90, 0, 0)); // Transform relative to the triangle's normal Vector vecRay = m * vecDir; //RenderSceneFromPosition(vecUVPosition, vecRay, pFace); flTotalHits++; //SMAKWindow()->AddDebugLine(vecUVPosition + pFace->GetNormal()*0.01f, vecUVPosition + vecRay.Normalized()*0.2f, vecDir); raytrace::CTraceResult tr2; if (pTracer->Raytrace(Ray(tr->m_vecHit + vecHitNormal*0.01f, vecRay), &tr2)) { float flDistance = (tr2.m_vecHit - tr->m_vecHit).Length(); if (m_flRayFalloff < 0) flHits += 1; else flHits += (1/pow(2, flDistance/m_flRayFalloff)); } else if (m_bGroundOcclusion && vecRay.y < 0) { // The following math is basically a plane-ray intersection algorithm, // with shortcuts made for the assumption of an infinite plane facing straight up. float a = -(tr->m_vecHit.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y); float b = vecRay.y; float flDistance = a/b; if (flDistance < 1e-4f || m_flRayFalloff < 0) flHits += 1; else flHits += (1/pow(2, flDistance/m_flRayFalloff)); } float flShadowValue = 1 - ((float)flHits / (float)flTotalHits); // Mutex may be dead, try to bail before. if (m_pGenerator->IsStopped()) return; m_pGenerator->GetParallelizer()->LockData(); m_avecShadowValues[iTexel] += Vector(flShadowValue, flShadowValue, flShadowValue); m_aiShadowReads[iTexel]++; m_pGenerator->MarkTexelUsed(iTexel); m_pGenerator->GetParallelizer()->UnlockData(); }
void CTexelDiffuseMethod::GenerateTexel(size_t iTexel, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, CConversionVertex* pV1, CConversionVertex* pV2, CConversionVertex* pV3, raytrace::CTraceResult* tr, const Vector& vecUVPosition, raytrace::CRaytracer* pTracer) { CConversionFace* pHitFace = tr->m_pMeshInstance->GetMesh()->GetFace(tr->m_iFace); CTexture& oTexture = m_aTextures[tr->m_pMeshInstance->GetMappedMaterial(pHitFace->m)->m_iMaterial]; if (!oTexture.m_pclrData) return; CConversionMesh* pHitMesh = tr->m_pMeshInstance->GetMesh(); // TODO: Use the nearest triangle in this face. CConversionVertex* pHitV1 = pHitFace->GetVertex(0); CConversionVertex* pHitV2 = pHitFace->GetVertex(1); CConversionVertex* pHitV3 = pHitFace->GetVertex(2); Vector2D vu1 = pHitMesh->GetUV(pHitV1->vu); Vector2D vu2 = pHitMesh->GetUV(pHitV2->vu); Vector2D vu3 = pHitMesh->GetUV(pHitV3->vu); Vector v1 = tr->m_pMeshInstance->GetVertex(pHitV1->v); Vector v2 = tr->m_pMeshInstance->GetVertex(pHitV2->v); Vector v3 = tr->m_pMeshInstance->GetVertex(pHitV3->v); // Find where the world point is in UV space. // First convert to barycentric coordinates. Vector u = v2 - v1; Vector v = v3 - v1; float uu = u.Dot(u); float uv = u.Dot(v); float vv = v.Dot(v); Vector w = tr->m_vecHit - v1; float wu = w.Dot(u); float wv = w.Dot(v); float D = uv * uv - uu * vv; float b1, b2, b3; b1 = (uv * wu - uu * wv) / D; b2 = (uv * wv - vv * wu) / D; b3 = 1 - b1 - b2; // The position of the traceline's hit in (u, v) texture space Vector2D vecWorldPosition = vu1 * b1 + vu2 * b2 + vu3 * b3; // Mutex may be dead, try to bail before. if (m_pGenerator->IsStopped()) return; size_t iU = (size_t)((vecWorldPosition.x * oTexture.m_iWidth) - 0.5f); size_t iV = (size_t)((vecWorldPosition.y * oTexture.m_iHeight) - 0.5f); iU %= oTexture.m_iWidth; iV %= oTexture.m_iHeight; size_t iColorTexel; m_pGenerator->Texel(iU, iV, iColorTexel, oTexture.m_iWidth, oTexture.m_iHeight); Color clrData = oTexture.m_pclrData[iColorTexel]; m_pGenerator->GetParallelizer()->LockData(); m_avecDiffuseValues[iTexel] += Vector(clrData); m_aiDiffuseReads[iTexel]++; m_pGenerator->MarkTexelUsed(iTexel); m_pGenerator->GetParallelizer()->UnlockData(); }
void CTexelGenerator::Generate() { for (size_t i = 0; i < m_apMethods.size(); i++) m_apMethods[i]->PreGenerate(); if (m_pWorkListener) { m_pWorkListener->BeginProgress(); m_pWorkListener->SetAction("Building tree", 0); } if (SMAKWindow()) SMAKWindow()->ClearDebugLines(); memset(&m_abTexelMask[0], 0, m_iWidth*m_iHeight*sizeof(bool)); m_bIsGenerating = true; m_bStopGenerating = false; m_bDoneGenerating = false; raytrace::CRaytracer* pTracer = NULL; pTracer = new raytrace::CRaytracer(m_pScene); for (size_t m = 0; m < m_apHiRes.size(); m++) pTracer->AddMeshInstance(m_apHiRes[m]); pTracer->BuildTree(); m_pWorkParallelizer = new CParallelizer((JobCallback)::ComputeAtTexel); m_pWorkParallelizer->Start(); float flTotalArea = 0; for (size_t m = 0; m < m_pScene->GetNumMeshes(); m++) { CConversionMesh* pMesh = m_pScene->GetMesh(m); for (size_t f = 0; f < pMesh->GetNumFaces(); f++) { CConversionFace* pFace = pMesh->GetFace(f); flTotalArea += pFace->GetUVArea(); } } if (m_pWorkListener) m_pWorkListener->SetAction("Dispatching jobs", (size_t)(flTotalArea*m_iWidth*m_iHeight)); size_t iRendered = 0; tvector<Vector> avecPoints; tvector<size_t> aiPoints; for (size_t i = 0; i < m_apLoRes.size(); i++) { CConversionMeshInstance* pMeshInstance = m_apLoRes[i]; if (!pMeshInstance->GetMesh()->GetNumUVs()) continue; for (size_t f = 0; f < pMeshInstance->GetMesh()->GetNumFaces(); f++) { CConversionFace* pFace = pMeshInstance->GetMesh()->GetFace(f); if (pFace->m != ~0) { if (!pMeshInstance->GetMappedMaterial(pFace->m)->IsVisible()) continue; CConversionMaterial* pMaterial = m_pScene->GetMaterial(pMeshInstance->GetMappedMaterial(pFace->m)->m_iMaterial); if (pMaterial && !pMaterial->IsVisible()) continue; } avecPoints.clear(); aiPoints.clear(); for (size_t t = 0; t < pFace->GetNumVertices(); t++) { avecPoints.push_back(pMeshInstance->GetVertex(pFace->GetVertex(t)->v)); aiPoints.push_back(t); } while (avecPoints.size() > 3) { size_t iEar = FindEar(avecPoints); size_t iLast = iEar==0?avecPoints.size()-1:iEar-1; size_t iNext = iEar==avecPoints.size()-1?0:iEar+1; GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[iLast], aiPoints[iEar], aiPoints[iNext], pTracer, iRendered); avecPoints.erase(avecPoints.begin()+iEar); aiPoints.erase(aiPoints.begin()+iEar); if (m_bStopGenerating) break; } GenerateTriangleByTexel(pMeshInstance, pFace, aiPoints[0], aiPoints[1], aiPoints[2], pTracer, iRendered); if (m_bStopGenerating) break; } if (m_bStopGenerating) break; } m_pWorkParallelizer->FinishJobs(); if (m_pWorkListener) m_pWorkListener->SetAction("Rendering", m_pWorkParallelizer->GetJobsTotal()); while (true) { if (m_pWorkParallelizer->AreAllJobsDone()) break; if (m_pWorkListener) m_pWorkListener->WorkProgress(m_pWorkParallelizer->GetJobsDone()); if (m_bStopGenerating) break; } delete m_pWorkParallelizer; delete pTracer; for (size_t i = 0; i < m_apMethods.size(); i++) m_apMethods[i]->PostGenerate(); if (!m_bStopGenerating) m_bDoneGenerating = true; m_bIsGenerating = false; // One last call to let them know we're done. if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void CModelConverter::WriteSMD(size_t iMesh, const tstring& sFilename) { CConversionMesh* pMesh = m_pScene->GetMesh(iMesh); tstring sFile; if (sFilename.length()) { sFile.append(sFilename); sFile.append(_T("_")); } sFile.append(pMesh->GetBoneName(0)); sFile = GetFilename(sFile.c_str()); sFile.append(_T(".smd")); FILE* fp = tfopen(sFile, _T("w")); // SMD file format: http://developer.valvesoftware.com/wiki/SMD // Header section fprintf(fp, "version 1\n\n"); // Nodes section fprintf(fp, "nodes\n"); // Only bothering with one node, we're only doing static props with this code for now. fprintf(fp, "0 \"%s\" -1\n", convertstring<tchar, char>(pMesh->GetBoneName(0)).c_str()); fprintf(fp, "end\n\n"); // Skeleton section fprintf(fp, "skeleton\n"); fprintf(fp, "time 0\n"); fprintf(fp, "0 0.000000 0.000000 0.000000 1.570796 0.000000 0.0000001\n"); fprintf(fp, "end\n\n"); fprintf(fp, "triangles\n"); for (size_t i = 0; i < pMesh->GetNumFaces(); i++) { CConversionFace* pFace = pMesh->GetFace(i); if (!pFace->GetNumVertices()) { printf("WARNING! Found a face with no vertices.\n"); continue; } CConversionVertex* pV1 = pFace->GetVertex(0); for (size_t j = 0; j < pFace->GetNumVertices()-2; j++) { CConversionVertex* pV2 = pFace->GetVertex(j+1); CConversionVertex* pV3 = pFace->GetVertex(j+2); Vector v1 = pMesh->GetVertex(pV1->v); Vector v2 = pMesh->GetVertex(pV2->v); Vector v3 = pMesh->GetVertex(pV3->v); Vector n1 = pMesh->GetNormal(pV1->vn); Vector n2 = pMesh->GetNormal(pV2->vn); Vector n3 = pMesh->GetNormal(pV3->vn); Vector uv1 = pMesh->GetUV(pV1->vu); Vector uv2 = pMesh->GetUV(pV2->vu); Vector uv3 = pMesh->GetUV(pV3->vu); // Material name size_t iMaterial = pFace->m; if (iMaterial == ((size_t)~0) || !m_pScene->GetMaterial(iMaterial)) { printf("ERROR! Can't find a material for a triangle.\n"); fprintf(fp, "error\n"); } else fprintf(fp, "%s\n", convertstring<tchar, char>(m_pScene->GetMaterial(iMaterial)->GetName()).c_str()); // <int|Parent bone> <float|PosX PosY PosZ> <normal|NormX NormY NormZ> <normal|U V> // Studio coordinates are not the same as game coordinates. Studio (x, y, z) is game (x, -z, y) and vice versa. fprintf(fp, "0 \t %f %f %f \t %f %f %f \t %f %f\n", v1.x, -v1.z, v1.y, n1.x, -n1.z, n1.y, uv1.x, uv1.y); fprintf(fp, "0 \t %f %f %f \t %f %f %f \t %f %f\n", v2.x, -v2.z, v2.y, n2.x, -n2.z, n2.y, uv2.x, uv2.y); fprintf(fp, "0 \t %f %f %f \t %f %f %f \t %f %f\n", v3.x, -v3.z, v3.y, n3.x, -n3.z, n3.y, uv3.x, uv3.y); } } fprintf(fp, "end\n"); fclose(fp); }
void CModelConverter::SaveDAE(const tstring& sFilename) { if (m_pWorkListener) m_pWorkListener->BeginProgress(); FCollada::Initialize(); FCDocument* pDoc = FCollada::NewTopDocument(); FCDocumentTools::StandardizeUpAxisAndLength(pDoc, FMVector3(0, 1, 0)); FCDAsset* pAsset = pDoc->GetAsset(); FCDAssetContributor* pContributor = pAsset->AddContributor(); pContributor->SetAuthoringTool(fstring_literal("Created by SMAK using FCollada")); FCDMaterialLibrary* pMatLib = pDoc->GetMaterialLibrary(); if (m_pWorkListener) m_pWorkListener->SetAction("Saving materials", m_pScene->GetNumMaterials()); for (size_t iMaterial = 0; iMaterial < m_pScene->GetNumMaterials(); iMaterial++) { CConversionMaterial* pConversionMaterial = m_pScene->GetMaterial(iMaterial); FCDMaterial* pColladaMaterial = pMatLib->AddEntity(); pColladaMaterial->SetName(convert_to_fstring(pConversionMaterial->GetName())); FCDEffect* pEffect = pMatLib->GetDocument()->GetEffectLibrary()->AddEntity(); pColladaMaterial->SetEffect(pEffect); FCDEffectProfile* pEffectProfile = pEffect->AddProfile(FUDaeProfileType::COMMON); pEffect->SetName(convert_to_fstring(pConversionMaterial->GetName())); FCDEffectStandard* pStandardProfile = dynamic_cast<FCDEffectStandard*>(pEffectProfile); if (pStandardProfile) { pStandardProfile->SetLightingType(FCDEffectStandard::PHONG); pStandardProfile->SetAmbientColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecAmbient), 1)); pStandardProfile->SetDiffuseColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecDiffuse), 1)); pStandardProfile->SetSpecularColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecSpecular), 1)); pStandardProfile->SetEmissionColor(FMVector4(FMVector3((float*)pConversionMaterial->m_vecEmissive), 1)); pStandardProfile->SetShininess(pConversionMaterial->m_flShininess); } if (pConversionMaterial->GetDiffuseTexture().length()) { FCDEffectParameter* pEffectParameterSampler = pEffectProfile->AddEffectParameter(FCDEffectParameter::SAMPLER); FCDEffectParameter* pEffectParameterSurface = pEffectProfile->AddEffectParameter(FCDEffectParameter::SURFACE); FCDEffectParameterSampler* pSampler = dynamic_cast<FCDEffectParameterSampler*>(pEffectParameterSampler); FCDEffectParameterSurface* pSurface = dynamic_cast<FCDEffectParameterSurface*>(pEffectParameterSurface); FCDImage* pSurfaceImage = pMatLib->GetDocument()->GetImageLibrary()->AddEntity(); pSurfaceImage->SetFilename(convert_to_fstring(pConversionMaterial->GetDiffuseTexture())); pSurface->SetInitMethod(new FCDEffectParameterSurfaceInitFrom()); pSurface->AddImage(pSurfaceImage); pSurface->SetReference((pConversionMaterial->GetName() + "-surface").c_str()); pSampler->SetSurface(pSurface); } if (m_pWorkListener) m_pWorkListener->WorkProgress(iMaterial); } if (m_pWorkListener) m_pWorkListener->SetAction("Saving geometry", m_pScene->GetNumMeshes()); FCDGeometryLibrary* pGeoLib = pDoc->GetGeometryLibrary(); for (size_t i = 0; i < m_pScene->GetNumMeshes(); ++i) { CConversionMesh* pConversionMesh = m_pScene->GetMesh(i); FCDGeometry* pGeometry = pGeoLib->AddEntity(); pGeometry->SetName(convert_to_fstring(pConversionMesh->GetName())); pGeometry->CreateMesh(); FCDGeometryMesh* pMesh = pGeometry->GetMesh(); FCDGeometrySource* pPositionSource = pMesh->AddSource(FUDaeGeometryInput::POSITION); pPositionSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-position")); pPositionSource->SetStride(3); pPositionSource->SetValueCount(pConversionMesh->GetNumVertices()); for (size_t j = 0; j < pConversionMesh->GetNumVertices(); j++) pPositionSource->SetValue(j, pConversionMesh->GetVertex(j)); pMesh->AddVertexSource(pPositionSource); FCDGeometrySource* pNormalSource = pMesh->AddSource(FUDaeGeometryInput::NORMAL); pNormalSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-normal")); pNormalSource->SetStride(3); pNormalSource->SetValueCount(pConversionMesh->GetNumNormals()); for (size_t j = 0; j < pConversionMesh->GetNumNormals(); j++) pNormalSource->SetValue(j, pConversionMesh->GetNormal(j)); FCDGeometrySource* pUVSource = NULL; if (pConversionMesh->GetNumUVs()) { pUVSource = pMesh->AddSource(FUDaeGeometryInput::TEXCOORD); pUVSource->SetName(convert_to_fstring(pConversionMesh->GetName() + "-texcoord")); pUVSource->SetStride(2); pUVSource->SetValueCount(pConversionMesh->GetNumUVs()); for (size_t j = 0; j < pConversionMesh->GetNumUVs(); j++) pUVSource->SetValue(j, pConversionMesh->GetUV(j)); } for (size_t iMaterials = 0; iMaterials < pConversionMesh->GetNumMaterialStubs(); iMaterials++) { CConversionMaterialStub* pStub = pConversionMesh->GetMaterialStub(iMaterials); FCDGeometryPolygons* pPolygons = pMesh->AddPolygons(); pPolygons->SetMaterialSemantic(convert_to_fstring(pStub->GetName())); pPolygons->AddInput(pPositionSource, 0); pPolygons->AddInput(pNormalSource, 1); if (pConversionMesh->GetNumUVs()) pPolygons->AddInput(pUVSource, 2); FCDGeometryPolygonsInput* pPositionInput = pPolygons->FindInput(pPositionSource); FCDGeometryPolygonsInput* pNormalInput = pPolygons->FindInput(pNormalSource); FCDGeometryPolygonsInput* pUVInput = pPolygons->FindInput(pUVSource); for (size_t iFace = 0; iFace < pConversionMesh->GetNumFaces(); iFace++) { CConversionFace* pFace = pConversionMesh->GetFace(iFace); if (pFace->m != iMaterials) continue; pPolygons->AddFaceVertexCount(pFace->GetNumVertices()); for (size_t iVertex = 0; iVertex < pFace->GetNumVertices(); iVertex++) { pPositionInput->AddIndex(pFace->GetVertex(iVertex)->v); pNormalInput->AddIndex(pFace->GetVertex(iVertex)->vn); if (pConversionMesh->GetNumUVs()) pUVInput->AddIndex(pFace->GetVertex(iVertex)->vu); } } } if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } if (m_pWorkListener) m_pWorkListener->SetAction("Saving scenes", m_pScene->GetNumScenes()); FCDVisualSceneNodeLibrary* pVisualScenes = pDoc->GetVisualSceneLibrary(); for (size_t i = 0; i < m_pScene->GetNumScenes(); ++i) { FCDSceneNode* pNode = pVisualScenes->AddEntity(); SaveDAEScene(pNode, m_pScene->GetScene(i)); if (m_pWorkListener) m_pWorkListener->WorkProgress(i); } if (m_pWorkListener) m_pWorkListener->SetAction("Writing to disk...", 0); FCollada::SaveDocument(pDoc, convert_to_fstring(sFilename)); pDoc->Release(); FCollada::Release(); if (m_pWorkListener) m_pWorkListener->EndProgress(); }
void LoadMesh(CConversionScene* pScene, size_t iMesh) { TAssert(iMesh < pScene->GetNumMeshes()); if (iMesh >= pScene->GetNumMeshes()) return; // Reserve space for n+1, the last one represents the default material. g_aaflData.resize(pScene->GetNumMaterials()+1); tvector<Vector> avecPoints; tvector<size_t> aiPoints; CConversionMesh* pMesh = pScene->GetMesh(iMesh); for (size_t j = 0; j < pMesh->GetNumFaces(); j++) { CConversionFace* pFace = pMesh->GetFace(j); size_t iMaterial = pFace->m; if (iMaterial == ~0) iMaterial = pScene->GetNumMaterials(); CConversionVertex* pVertex0 = pFace->GetVertex(0); CConversionVertex* pVertex1 = pFace->GetVertex(1); CConversionVertex* pLastVertex = pFace->GetVertex(pFace->GetNumVertices()-1); avecPoints.clear(); aiPoints.clear(); for (size_t t = 0; t < pFace->GetNumVertices(); t++) { avecPoints.push_back(pMesh->GetVertex(pFace->GetVertex(t)->v)); aiPoints.push_back(t); } CConversionVertex* pVertex2; while (avecPoints.size() > 3) { size_t iEar = FindEar(avecPoints); size_t iLast = iEar==0?avecPoints.size()-1:iEar-1; size_t iNext = iEar==avecPoints.size()-1?0:iEar+1; pVertex0 = pFace->GetVertex(aiPoints[iLast]); pVertex1 = pFace->GetVertex(aiPoints[iEar]); pVertex2 = pFace->GetVertex(aiPoints[iNext]); AddVertex(iMaterial, pMesh->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); avecPoints.erase(avecPoints.begin()+iEar); aiPoints.erase(aiPoints.begin()+iEar); } TAssert(aiPoints.size() == 3); if (aiPoints.size() != 3) continue; pVertex0 = pFace->GetVertex(aiPoints[0]); pVertex1 = pFace->GetVertex(aiPoints[1]); pVertex2 = pFace->GetVertex(aiPoints[2]); AddVertex(iMaterial, pMesh->GetVertex(pVertex0->v), pMesh->GetUV(pVertex0->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex1->v), pMesh->GetUV(pVertex1->vu)); AddVertex(iMaterial, pMesh->GetVertex(pVertex2->v), pMesh->GetUV(pVertex2->vu)); } }