FbxMesh* GenerateLOD::CreateNewMesh(FbxVector4 *pControlPoints, FbxMesh *pMesh, FbxScene *pScene) { // ********************************************************************************* // // Following is Create new Mesh FbxMesh *newMesh = FbxMesh::Create(pScene, "newMesh"); newMesh->InitControlPoints((*ControlP).size()); int count = 0; std::unordered_map<int, int> RemainPoints; for (std::unordered_map<int, Point>::iterator it = (*ControlP).begin(); it != (*ControlP).end(); ++it) { newMesh->SetControlPointAt(pControlPoints[it->first], count); RemainPoints[it->first] = count; ++count; } FbxGeometryElementUV *newElementUV = newMesh->CreateElementUV("DiffuseUV"); if (!newElementUV) { MessageBox(NULL, "CreateElementUV Error!", "�ב�¾", 0); //exit(0); } newElementUV->SetMappingMode(FbxLayerElement::eByPolygonVertex); newElementUV->SetReferenceMode(FbxLayerElement::eIndexToDirect); //# copy oldElementUV.DirectArray() into newElementUV.DirectArray() FbxGeometryElementUV *oldElementUV = pMesh->GetElementUV(0); int length = oldElementUV->GetDirectArray().GetCount(); for (int i = 0; i < length; ++i) newElementUV->GetDirectArray().Add(oldElementUV->GetDirectArray()[i]); //# Now we have set the UVs as eIndexToDirect reference and //# in eByPolygonVertex mapping mode, we must Set the size of the index array. int PolygonCount = (*Triangles).size(); newElementUV->GetIndexArray().SetCount(3 * PolygonCount); //# Add new triangles to pMesh int newPolygonIndex = 0; for (std::unordered_map<int, Face>::iterator it = (*Triangles).begin(); it != (*Triangles).end(); ++it) { newMesh->BeginPolygon(-1, -1, -1, false); newMesh->AddPolygon(RemainPoints[it->second.points[0]], it->second.uvs[0]); newElementUV->GetIndexArray().SetAt(newPolygonIndex * 3 + 0, it->second.uvs[0]); newMesh->AddPolygon(RemainPoints[it->second.points[1]], it->second.uvs[1]); newElementUV->GetIndexArray().SetAt(newPolygonIndex * 3 + 1, it->second.uvs[1]); newMesh->AddPolygon(RemainPoints[it->second.points[2]], it->second.uvs[2]); newElementUV->GetIndexArray().SetAt(newPolygonIndex * 3 + 2, it->second.uvs[2]); newMesh->EndPolygon(); newPolygonIndex += 1; } //# Automatically generate edge data for the mesh. newMesh->BuildMeshEdgeArray(); return newMesh; }
FbxNode* ILDLMesh::CreateMesh( FbxScene* pScene, const char* pName ) { int nVerts = (int)m_vertex_list.size(); FbxMesh* lMesh = FbxMesh::Create(pScene,pName); lMesh->InitControlPoints( nVerts ); FbxVector4* lControlPoints = lMesh->GetControlPoints(); FbxGeometryElementNormal* lGeometryElementNormal= lMesh->CreateElementNormal(); lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); int vi = 0, glidx = 0; for( ILDLVertexIter i = m_vertex_list.begin(); i != m_vertex_list.end(); ++i, vi++ ) { ILDLVertexPtr vp = (*i); vp->m_glIdx = glidx; vec3 coords = vp->getCoords(); lControlPoints[vi] = FbxVector4( coords[0], coords[1], coords[2] ); vec3 normal = vp->getNormal(); lGeometryElementNormal->GetDirectArray().Add( FbxVector4( normal[0], normal[1], normal[2] ) ); glidx++; } for( ILDLFaceIter i = m_face_list.begin(); i != m_face_list.end(); ++i ) { ILDLFacePtr fp = *i; ILDLFaceVertexPtr fvp = fp->front(); lMesh->BeginPolygon(-1, -1, -1, false); lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx ); fvp = fvp->next(); lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx ); fvp = fvp->next(); lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx ); lMesh->EndPolygon (); } FbxNode* lNode = FbxNode::Create(pScene,pName); lNode->SetNodeAttribute(lMesh); return lNode; }
/** * Adds an Fbx Mesh to the FBX scene based on the data in the given FStaticLODModel */ FbxNode* FFbxExporter::CreateMesh(const USkeletalMesh* SkelMesh, const TCHAR* MeshName) { const FSkeletalMeshResource* SkelMeshResource = SkelMesh->GetImportedResource(); const FStaticLODModel& SourceModel = SkelMeshResource->LODModels[0]; const int32 VertexCount = SourceModel.NumVertices; // Verify the integrity of the mesh. if (VertexCount == 0) return NULL; // Copy all the vertex data from the various chunks to a single buffer. // Makes the rest of the code in this function cleaner and easier to maintain. TArray<FSoftSkinVertex> Vertices; SourceModel.GetVertices(Vertices); if (Vertices.Num() != VertexCount) return NULL; FbxMesh* Mesh = FbxMesh::Create(Scene, TCHAR_TO_UTF8(MeshName)); // Create and fill in the vertex position data source. Mesh->InitControlPoints(VertexCount); FbxVector4* ControlPoints = Mesh->GetControlPoints(); for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex) { FVector Position = Vertices[VertIndex].Position; ControlPoints[VertIndex] = Converter.ConvertToFbxPos(Position); } // Create Layer 0 to hold the normals FbxLayer* LayerZero = Mesh->GetLayer(0); if (LayerZero == NULL) { Mesh->CreateLayer(); LayerZero = Mesh->GetLayer(0); } // Create and fill in the per-face-vertex normal data source. // We extract the Z-tangent and drop the X/Y-tangents which are also stored in the render mesh. FbxLayerElementNormal* LayerElementNormal= FbxLayerElementNormal::Create(Mesh, ""); LayerElementNormal->SetMappingMode(FbxLayerElement::eByControlPoint); // Set the normal values for every control point. LayerElementNormal->SetReferenceMode(FbxLayerElement::eDirect); for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex) { FVector Normal = Vertices[VertIndex].TangentZ; FbxVector4 FbxNormal = Converter.ConvertToFbxPos(Normal); LayerElementNormal->GetDirectArray().Add(FbxNormal); } LayerZero->SetNormals(LayerElementNormal); // Create and fill in the per-face-vertex texture coordinate data source(s). // Create UV for Diffuse channel. const int32 TexCoordSourceCount = SourceModel.NumTexCoords; TCHAR UVChannelName[32]; for (int32 TexCoordSourceIndex = 0; TexCoordSourceIndex < TexCoordSourceCount; ++TexCoordSourceIndex) { FbxLayer* Layer = Mesh->GetLayer(TexCoordSourceIndex); if (Layer == NULL) { Mesh->CreateLayer(); Layer = Mesh->GetLayer(TexCoordSourceIndex); } if (TexCoordSourceIndex == 1) { FCString::Sprintf(UVChannelName, TEXT("LightMapUV")); } else { FCString::Sprintf(UVChannelName, TEXT("DiffuseUV")); } FbxLayerElementUV* UVDiffuseLayer = FbxLayerElementUV::Create(Mesh, TCHAR_TO_UTF8(UVChannelName)); UVDiffuseLayer->SetMappingMode(FbxLayerElement::eByControlPoint); UVDiffuseLayer->SetReferenceMode(FbxLayerElement::eDirect); // Create the texture coordinate data source. for (int32 TexCoordIndex = 0; TexCoordIndex < VertexCount; ++TexCoordIndex) { const FVector2D& TexCoord = Vertices[TexCoordIndex].UVs[TexCoordSourceIndex]; UVDiffuseLayer->GetDirectArray().Add(FbxVector2(TexCoord.X, -TexCoord.Y + 1.0)); } Layer->SetUVs(UVDiffuseLayer, FbxLayerElement::eTextureDiffuse); } FbxLayerElementMaterial* MatLayer = FbxLayerElementMaterial::Create(Mesh, ""); MatLayer->SetMappingMode(FbxLayerElement::eByPolygon); MatLayer->SetReferenceMode(FbxLayerElement::eIndexToDirect); LayerZero->SetMaterials(MatLayer); // Create the per-material polygons sets. TArray<uint32> Indices; SourceModel.MultiSizeIndexContainer.GetIndexBuffer(Indices); int32 SectionCount = SourceModel.Sections.Num(); for (int32 SectionIndex = 0; SectionIndex < SectionCount; ++SectionIndex) { const FSkelMeshSection& Section = SourceModel.Sections[SectionIndex]; int32 MatIndex = Section.MaterialIndex; // Static meshes contain one triangle list per element. int32 TriangleCount = Section.NumTriangles; // Copy over the index buffer into the FBX polygons set. for (int32 TriangleIndex = 0; TriangleIndex < TriangleCount; ++TriangleIndex) { Mesh->BeginPolygon(MatIndex); for (int32 PointIndex = 0; PointIndex < 3; PointIndex++) { Mesh->AddPolygon(Indices[Section.BaseIndex + ((TriangleIndex * 3) + PointIndex)]); } Mesh->EndPolygon(); } } // Create and fill in the vertex color data source. FbxLayerElementVertexColor* VertexColor = FbxLayerElementVertexColor::Create(Mesh, ""); VertexColor->SetMappingMode(FbxLayerElement::eByControlPoint); VertexColor->SetReferenceMode(FbxLayerElement::eDirect); FbxLayerElementArrayTemplate<FbxColor>& VertexColorArray = VertexColor->GetDirectArray(); LayerZero->SetVertexColors(VertexColor); for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex) { FLinearColor VertColor = Vertices[VertIndex].Color.ReinterpretAsLinear(); VertexColorArray.Add( FbxColor(VertColor.R, VertColor.G, VertColor.B, VertColor.A )); } FbxNode* MeshNode = FbxNode::Create(Scene, TCHAR_TO_UTF8(MeshName)); MeshNode->SetNodeAttribute(Mesh); // Add the materials for the mesh int32 MaterialCount = SkelMesh->Materials.Num(); for(int32 MaterialIndex = 0; MaterialIndex < MaterialCount; ++MaterialIndex) { UMaterialInterface* MatInterface = SkelMesh->Materials[MaterialIndex].MaterialInterface; FbxSurfaceMaterial* FbxMaterial = NULL; if(MatInterface && !FbxMaterials.Find(MatInterface)) { FbxMaterial = ExportMaterial(MatInterface); } else { // Note: The vertex data relies on there being a set number of Materials. // If you try to add the same material again it will not be added, so create a // default material with a unique name to ensure the proper number of materials TCHAR NewMaterialName[MAX_SPRINTF]=TEXT(""); FCString::Sprintf( NewMaterialName, TEXT("Fbx Default Material %i"), MaterialIndex ); FbxMaterial = FbxSurfaceLambert::Create(Scene, TCHAR_TO_UTF8(NewMaterialName)); ((FbxSurfaceLambert*)FbxMaterial)->Diffuse.Set(FbxDouble3(0.72, 0.72, 0.72)); } MeshNode->AddMaterial(FbxMaterial); } int32 SavedMaterialCount = MeshNode->GetMaterialCount(); check(SavedMaterialCount == MaterialCount); return MeshNode; }
// Converts a CC mesh to an FBX mesh static FbxNode* ToFbxMesh(ccGenericMesh* mesh, FbxScene* pScene) { if (!mesh) return 0; FbxMesh* lMesh = FbxMesh::Create(pScene, qPrintable(mesh->getName())); ccGenericPointCloud* cloud = mesh->getAssociatedCloud(); if (!cloud) return 0; unsigned vertCount = cloud->size(); unsigned faceCount = mesh->size(); // Create control points. { lMesh->InitControlPoints(vertCount); FbxVector4* lControlPoints = lMesh->GetControlPoints(); for (unsigned i=0; i<vertCount; ++i) { const CCVector3* P = cloud->getPoint(i); lControlPoints[i] = FbxVector4(P->x,P->y,P->z); } } ccMesh* asCCMesh = 0; if (mesh->isA(CC_MESH)) asCCMesh = static_cast<ccMesh*>(mesh); // normals if (mesh->hasNormals()) { FbxGeometryElementNormal* lGeometryElementNormal = lMesh->CreateElementNormal(); if (mesh->hasTriNormals()) { // We want to have one normal per vertex of each polygon, // so we set the mapping mode to eByPolygonVertex. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect); lGeometryElementNormal->GetIndexArray().SetCount(faceCount*3); if (asCCMesh) { NormsIndexesTableType* triNorms = asCCMesh->getTriNormsTable(); assert(triNorms); for (unsigned i=0; i<triNorms->currentSize(); ++i) { const PointCoordinateType* N = ccNormalVectors::GetNormal(triNorms->getValue(i)); FbxVector4 Nfbx(N[0],N[1],N[2]); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } for (unsigned j=0; j<faceCount; ++j) { int i1,i2,i3; asCCMesh->getTriangleNormalIndexes(j,i1,i2,i3); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, i1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, i2); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, i3); } } else { for (unsigned j=0; j<faceCount; ++j) { //we can't use the 'NormsIndexesTable' so we save all the normals of all the vertices CCVector3 Na,Nb,Nc; lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Na.x,Na.y,Na.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nb.x,Nb.y,Nb.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nc.x,Nc.y,Nc.z)); mesh->getTriangleNormals(j,Na,Nb,Nc); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, static_cast<int>(j)*3+0); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, static_cast<int>(j)*3+1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, static_cast<int>(j)*3+2); } } } else { // We want to have one normal for each vertex (or control point), // so we set the mapping mode to eByControlPoint. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); // The first method is to set the actual normal value // for every control point. lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); for (unsigned i=0; i<vertCount; ++i) { const PointCoordinateType* N = cloud->getPointNormal(i); FbxVector4 Nfbx(N[0],N[1],N[2]); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } } } else { ccLog::Warning("[FBX] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")"); } // colors if (cloud->hasColors()) { FbxGeometryElementVertexColor* lGeometryElementVertexColor = lMesh->CreateElementVertexColor(); lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect); for (unsigned i=0; i<vertCount; ++i) { const colorType* C = cloud->getPointColor(i); FbxColor col( FbxDouble3( static_cast<double>(C[0])/MAX_COLOR_COMP, static_cast<double>(C[1])/MAX_COLOR_COMP, static_cast<double>(C[2])/MAX_COLOR_COMP ) ); lGeometryElementVertexColor->GetDirectArray().Add(col); } } // Set material mapping. //FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial(); //lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon); //lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect); // Create polygons. Assign material indices. { for (unsigned j=0; j<faceCount; ++j) { const CCLib::TriangleSummitsIndexes* tsi = mesh->getTriangleIndexes(j); lMesh->BeginPolygon(static_cast<int>(j)); lMesh->AddPolygon(tsi->i1); lMesh->AddPolygon(tsi->i2); lMesh->AddPolygon(tsi->i3); lMesh->EndPolygon(); } } FbxNode* lNode = FbxNode::Create(pScene,qPrintable(mesh->getName())); lNode->SetNodeAttribute(lMesh); //CreateMaterials(pScene, lMesh); return lNode; }
// Converts a CC mesh to an FBX mesh static FbxNode* ToFbxMesh(ccGenericMesh* mesh, FbxScene* pScene, QString filename, size_t meshIndex) { if (!mesh) return 0; FbxNode* lNode = FbxNode::Create(pScene,qPrintable(mesh->getName())); FbxMesh* lMesh = FbxMesh::Create(pScene, qPrintable(mesh->getName())); lNode->SetNodeAttribute(lMesh); ccGenericPointCloud* cloud = mesh->getAssociatedCloud(); if (!cloud) return 0; unsigned vertCount = cloud->size(); unsigned faceCount = mesh->size(); // Create control points. { lMesh->InitControlPoints(vertCount); FbxVector4* lControlPoints = lMesh->GetControlPoints(); for (unsigned i=0; i<vertCount; ++i) { const CCVector3* P = cloud->getPoint(i); lControlPoints[i] = FbxVector4(P->x,P->y,P->z); //lControlPoints[i] = FbxVector4(P->x,P->z,-P->y); //DGM: see loadFile (Y and Z are inverted) } } ccMesh* asCCMesh = 0; if (mesh->isA(CC_TYPES::MESH)) asCCMesh = static_cast<ccMesh*>(mesh); // normals if (mesh->hasNormals()) { FbxGeometryElementNormal* lGeometryElementNormal = lMesh->CreateElementNormal(); if (mesh->hasTriNormals()) { // We want to have one normal per vertex of each polygon, // so we set the mapping mode to eByPolygonVertex. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect); lGeometryElementNormal->GetIndexArray().SetCount(faceCount*3); if (asCCMesh) { NormsIndexesTableType* triNorms = asCCMesh->getTriNormsTable(); assert(triNorms); for (unsigned i=0; i<triNorms->currentSize(); ++i) { const CCVector3& N = ccNormalVectors::GetNormal(triNorms->getValue(i)); FbxVector4 Nfbx(N.x,N.y,N.z); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } for (unsigned j=0; j<faceCount; ++j) { int i1,i2,i3; asCCMesh->getTriangleNormalIndexes(j,i1,i2,i3); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, i1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, i2); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, i3); } } else { for (unsigned j=0; j<faceCount; ++j) { //we can't use the 'NormsIndexesTable' so we save all the normals of all the vertices CCVector3 Na,Nb,Nc; lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Na.x,Na.y,Na.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nb.x,Nb.y,Nb.z)); lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nc.x,Nc.y,Nc.z)); mesh->getTriangleNormals(j,Na,Nb,Nc); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, static_cast<int>(j)*3+0); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, static_cast<int>(j)*3+1); lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, static_cast<int>(j)*3+2); } } } else { // We want to have one normal for each vertex (or control point), // so we set the mapping mode to eByControlPoint. lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); // The first method is to set the actual normal value // for every control point. lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); for (unsigned i=0; i<vertCount; ++i) { const CCVector3& N = cloud->getPointNormal(i); FbxVector4 Nfbx(N.x,N.y,N.z); lGeometryElementNormal->GetDirectArray().Add(Nfbx); } } } else { ccLog::Warning("[FBX] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")"); } // Set material mapping. bool hasMaterial = false; if (asCCMesh && asCCMesh->hasMaterials()) { const ccMaterialSet* matSet = asCCMesh->getMaterialSet(); size_t matCount = matSet->size(); //check if we have textures bool hasTextures = asCCMesh->hasTextures(); if (hasTextures) { //check that we actually have materials with textures as well! hasTextures = false; for (size_t i=0; i<matCount; ++i) { ccMaterial::CShared mat = matSet->at(i); if (mat->hasTexture()) { hasTextures = true; break; } } } static const char gDiffuseElementName[] = "DiffuseUV"; // Create UV for Diffuse channel if (hasTextures) { FbxGeometryElementUV* lUVDiffuseElement = lMesh->CreateElementUV(gDiffuseElementName); assert(lUVDiffuseElement != 0); lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex); lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect); //fill Direct Array const TextureCoordsContainer* texCoords = asCCMesh->getTexCoordinatesTable(); assert(texCoords); if (texCoords) { unsigned count = texCoords->currentSize(); lUVDiffuseElement->GetDirectArray().SetCount(static_cast<int>(count)); for (unsigned i=0; i<count; ++i) { const float* uv = texCoords->getValue(i); lUVDiffuseElement->GetDirectArray().SetAt(i,FbxVector2(uv[0],uv[1])); } } //fill Indexes Array assert(asCCMesh->hasPerTriangleTexCoordIndexes()); if (asCCMesh->hasPerTriangleTexCoordIndexes()) { unsigned triCount = asCCMesh->size(); lUVDiffuseElement->GetIndexArray().SetCount(static_cast<int>(3*triCount)); for (unsigned j=0; j<triCount; ++j) { int t1=0, t2=0, t3=0; asCCMesh->getTriangleTexCoordinatesIndexes(j, t1, t2, t3); lUVDiffuseElement->GetIndexArray().SetAt(j*3+0,t1); lUVDiffuseElement->GetIndexArray().SetAt(j*3+1,t2); lUVDiffuseElement->GetIndexArray().SetAt(j*3+2,t3); } } } //Textures used in this file QMap<QString,QString> texFilenames; //directory to save textures (if any) QFileInfo info(filename); QString textDirName = info.baseName() + QString(".fbm"); QDir baseDir = info.absoluteDir(); QDir texDir = QDir(baseDir.absolutePath() + QString("/") + textDirName); for (size_t i=0; i<matCount; ++i) { ccMaterial::CShared mat = matSet->at(i); FbxSurfacePhong *lMaterial = FbxSurfacePhong::Create(pScene, qPrintable(mat->getName())); const ccColor::Rgbaf& emission = mat->getEmission(); const ccColor::Rgbaf& ambient = mat->getAmbient(); const ccColor::Rgbaf& diffuse = mat->getDiffuseFront(); const ccColor::Rgbaf& specular = mat->getDiffuseFront(); lMaterial->Emissive.Set(FbxDouble3(emission.r,emission.g,emission.b)); lMaterial->Ambient .Set(FbxDouble3( ambient.r, ambient.g, ambient.b)); lMaterial->Diffuse .Set(FbxDouble3( diffuse.r, diffuse.g, diffuse.b)); lMaterial->Specular.Set(FbxDouble3(specular.r,specular.g,specular.b)); lMaterial->Shininess = mat->getShininessFront(); lMaterial->ShadingModel.Set("Phong"); if (hasTextures && mat->hasTexture()) { QString texFilename = mat->getTextureFilename(); //texture has not already been processed if (!texFilenames.contains(texFilename)) { //if necessary, we (try to) create a subfolder to store textures if (!texDir.exists()) { texDir = baseDir; if (texDir.mkdir(textDirName)) { texDir.cd(textDirName); } else { textDirName = QString(); ccLog::Warning("[FBX] Failed to create subfolder '%1' to store texture files (files will be stored next to the .fbx file)"); } } QFileInfo fileInfo(texFilename); QString baseTexName = fileInfo.fileName(); //add extension QString extension = QFileInfo(texFilename).suffix(); if (fileInfo.suffix().isEmpty()) baseTexName += QString(".png"); QString absoluteFilename = texDir.absolutePath() + QString("/") + baseTexName; ccLog::PrintDebug(QString("[FBX] Material '%1' texture: %2").arg(mat->getName()).arg(absoluteFilename)); texFilenames[texFilename] = absoluteFilename; } //mat.texture.save(absoluteFilename); // Set texture properties. FbxFileTexture* lTexture = FbxFileTexture::Create(pScene,"DiffuseTexture"); assert(!texFilenames[texFilename].isEmpty()); lTexture->SetFileName(qPrintable(texFilenames[texFilename])); lTexture->SetTextureUse(FbxTexture::eStandard); lTexture->SetMappingType(FbxTexture::eUV); lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial); lTexture->SetSwapUV(false); lTexture->SetTranslation(0.0, 0.0); lTexture->SetScale(1.0, 1.0); lTexture->SetRotation(0.0, 0.0); lTexture->UVSet.Set(FbxString(gDiffuseElementName)); // Connect texture to the proper UV // don't forget to connect the texture to the corresponding property of the material lMaterial->Diffuse.ConnectSrcObject(lTexture); } int matIndex = lNode->AddMaterial(lMaterial); assert(matIndex == static_cast<int>(i)); } //don't forget to save the texture files { for (QMap<QString,QString>::ConstIterator it = texFilenames.begin(); it != texFilenames.end(); ++it) { const QImage image = ccMaterial::GetTexture(it.key()); image.mirrored().save(it.value()); } texFilenames.clear(); //don't need this anymore! } // Create 'triangle to material index' mapping { FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial(); lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon); lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect); } hasMaterial = true; } // colors if (cloud->hasColors()) { FbxGeometryElementVertexColor* lGeometryElementVertexColor = lMesh->CreateElementVertexColor(); lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect); lGeometryElementVertexColor->GetDirectArray().SetCount(vertCount); for (unsigned i=0; i<vertCount; ++i) { const colorType* C = cloud->getPointColor(i); FbxColor col( static_cast<double>(C[0])/ccColor::MAX, static_cast<double>(C[1])/ccColor::MAX, static_cast<double>(C[2])/ccColor::MAX ); lGeometryElementVertexColor->GetDirectArray().SetAt(i,col); } if (!hasMaterial) { //it seems that we have to create a fake material in order for the colors to be displayed (in Unity and FBX Review at least)! FbxSurfacePhong *lMaterial = FbxSurfacePhong::Create(pScene, "ColorMaterial"); lMaterial->Emissive.Set(FbxDouble3(0,0,0)); lMaterial->Ambient.Set(FbxDouble3(0,0,0)); lMaterial->Diffuse.Set(FbxDouble3(1,1,1)); lMaterial->Specular.Set(FbxDouble3(0,0,0)); lMaterial->Shininess = 0; lMaterial->ShadingModel.Set("Phong"); FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial(); lMaterialElement->SetMappingMode(FbxGeometryElement::eAllSame); lMaterialElement->SetReferenceMode(FbxGeometryElement::eDirect); lNode->AddMaterial(lMaterial); } } // Create polygons { for (unsigned j=0; j<faceCount; ++j) { const CCLib::TriangleSummitsIndexes* tsi = mesh->getTriangleIndexes(j); int matIndex = hasMaterial ? asCCMesh->getTriangleMtlIndex(j) : -1; lMesh->BeginPolygon(matIndex); lMesh->AddPolygon(tsi->i1); lMesh->AddPolygon(tsi->i2); lMesh->AddPolygon(tsi->i3); lMesh->EndPolygon(); } } return lNode; }
void ExportFbxMesh(const Value& obj) { string name = obj["Name"].GetString(); FbxNode* pNode = FbxNode::Create(pManager, name.c_str()); FbxMesh* pMesh = FbxMesh::Create(pManager, name.c_str()); pNode->AddNodeAttribute(pMesh); pScene->GetRootNode()->AddChild(pNode); int numVertex = obj["NumVertex"].GetInt(); { pMesh->InitControlPoints(numVertex); FbxVector4* lControlPoints = pMesh->GetControlPoints(); const Value& pos = obj["Position"]; for (int i = 0; i < numVertex; i++) { double x = pos[i * 3 + 0].GetDouble(); x = -x; double y = pos[i * 3 + 1].GetDouble(); double z = pos[i * 3 + 2].GetDouble(); lControlPoints[i] = FbxVector4(x, y, z); } } { FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal(); lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint); lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect); FbxLayerElementArrayTemplate<FbxVector4>& array = lGeometryElementNormal->GetDirectArray(); const Value& normal = obj["Normal"]; for (int i = 0; i < numVertex; i++) { double x = normal[i * 3 + 0].GetDouble(); x = -x; double y = normal[i * 3 + 1].GetDouble(); double z = normal[i * 3 + 2].GetDouble(); array.Add(FbxVector4(x, y, z)); } } { FbxGeometryElementUV* lUVDiffuseElement = pMesh->CreateElementUV("DiffuseUV"); FBX_ASSERT(lUVDiffuseElement != NULL); lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByControlPoint); lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eDirect); FbxLayerElementArrayTemplate<FbxVector2>& array = lUVDiffuseElement->GetDirectArray(); const Value& v = obj["UV0"]; for (int i = 0; i < numVertex; i++) { double x = v[i * 2 + 0].GetDouble(); double y = v[i * 2 + 1].GetDouble(); array.Add(FbxVector2(x, y)); } } { const Value& color = obj["Color"]; if (!color.IsNull()) { FbxGeometryElementVertexColor* pColorElement = pMesh->CreateElementVertexColor(); FBX_ASSERT(pColorElement != NULL); pColorElement->SetMappingMode(FbxGeometryElement::eByControlPoint); pColorElement->SetReferenceMode(FbxGeometryElement::eDirect); FbxLayerElementArrayTemplate<FbxColor>& array = pColorElement->GetDirectArray(); for (int i = 0; i < numVertex; i++) { double r = color[i * 4 + 0].GetDouble(); double g = color[i * 4 + 1].GetDouble(); double b = color[i * 4 + 2].GetDouble(); double a = color[i * 4 + 3].GetDouble(); array.Add(FbxColor(r, g, b, a)); } } } { const Value& Indeices = obj["Indeices"]; for (uint32_t subMesh = 0; subMesh < Indeices.Size(); subMesh++) { const Value& index0 = Indeices[subMesh]; int numIndex = index0.Size(); printf("index %d\n", numIndex); for (int i = 0; i < numIndex / 3; i++) { pMesh->BeginPolygon(-1, -1, subMesh); int index[3] = { index0[i * 3 + 0].GetInt(), index0[i * 3 + 1].GetInt(), index0[i * 3 + 2].GetInt(), }; pMesh->AddPolygon(index[0]); pMesh->AddPolygon(index[2]); pMesh->AddPolygon(index[1]); pMesh->EndPolygon(); } } } ////////////////////////////////////////////////////////////////////////// // export skin const Value& boneIndex = obj["BoneIndex"]; if (!boneIndex.IsNull()) { if (fbxBones.empty()) { printf("no bones, can not export skin"); return; } const Value& boneWeight = obj["BoneWeight"]; vector<FbxCluster*> clusters(fbxBones.size(), NULL); for (uint32_t i = 0; i < fbxBones.size(); i++) { FbxCluster* pCluster = FbxCluster::Create(pScene, ""); pCluster->SetLink(fbxBones[i]); pCluster->SetLinkMode(FbxCluster::eTotalOne); clusters[i] = pCluster; } for (int i = 0; i < numVertex; i++) { for (int j = 0; j < 4; j++) { int bone = boneIndex[i * 4 + j].GetInt(); double weight = boneWeight[i * 4 + j].GetDouble(); clusters[bone]->AddControlPointIndex(i, weight); } } FbxSkin* lSkin = FbxSkin::Create(pScene, ""); FbxScene* p = pNode->GetScene(); FbxAMatrix modelMatrix = pNode->EvaluateGlobalTransform(); for (uint32_t i = 0; i < clusters.size(); i++) { clusters[i]->SetTransformMatrix(modelMatrix); FbxAMatrix boneMatrix = fbxBones[i]->EvaluateGlobalTransform(); clusters[i]->SetTransformLinkMatrix(boneMatrix); lSkin->AddCluster(clusters[i]); } pMesh->AddDeformer(lSkin); } }