void Mesh::GetUV(FbxMesh* pMesh, MeshInfo& pMeshInfo) { FbxGeometryElementUV* lUvElement = pMesh->GetElementUV(); if (lUvElement) { if (lUvElement->GetReferenceMode() == FbxGeometryElement::eDirect) { for (int lVertexIndex = 0; lVertexIndex < pMesh->GetLayer(0)->GetUVs()->GetDirectArray().GetCount(); lVertexIndex++) { int lUvIndex = 0; lUvIndex = lVertexIndex; pMeshInfo.uv.push_back(lUvElement->GetDirectArray().GetAt(lUvIndex)); } } if (lUvElement->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) { for (int lVertexIndex = 0; lVertexIndex < pMesh->GetLayer(0)->GetUVs()->GetIndexArray().GetCount(); lVertexIndex++) { int lUvIndex = 0; lUvIndex = lUvElement->GetIndexArray().GetAt(lVertexIndex); pMeshInfo.uv.push_back(lUvElement->GetDirectArray().GetAt(lUvIndex)); } } } }
void FBXImporter::ReadUVs(FBXMeshData* fbxMeshData, int controlPointIndex, int index, int textureUVIndex, int uvLayer) { FbxMesh* mesh = fbxMeshData->mMesh; vector<XMFLOAT2>& uvs = fbxMeshData->mUVs; if (uvLayer >= 2 || mesh->GetElementUVCount() <= uvLayer) { return; } FbxGeometryElementUV* vertexUV = mesh->GetElementUV(0); switch (vertexUV->GetMappingMode()) { case FbxGeometryElement::eByControlPoint: switch (vertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { XMFLOAT2 uv; FbxVector2 fbxUV = vertexUV->GetDirectArray().GetAt(controlPointIndex); uv.x = static_cast<float>(fbxUV[0]); uv.y = static_cast<float>(fbxUV[1]); uvs.push_back(uv); } break; case FbxGeometryElement::eIndexToDirect: { int id = vertexUV->GetIndexArray().GetAt(controlPointIndex); FbxVector2 fbxUV = vertexUV->GetDirectArray().GetAt(id); XMFLOAT2 uv; uv.x = static_cast<float>(fbxUV[0]); uv.y = static_cast<float>(fbxUV[1]); uvs.push_back(uv); } break; default: break; } case FbxGeometryElement::eByPolygonVertex: switch (vertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: case FbxGeometryElement::eIndexToDirect: #if USE_RIGHT_HAND uvs[index].x = static_cast<float>(vertexUV->GetDirectArray().GetAt(textureUVIndex)[0]); #else uvs[index].x = 1.0f - static_cast<float>(vertexUV->GetDirectArray().GetAt(textureUVIndex)[0]); #endif uvs[index].y = 1.0f - static_cast<float>(vertexUV->GetDirectArray().GetAt(textureUVIndex)[1]); break; default: break; } break; } }
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; }
void ReadUV(FbxMesh* pMesh , int ctrlPointIndex , int textureUVIndex , int uvLayer , D3DXVECTOR2* pUV) { if(uvLayer >= 2 || pMesh->GetElementUVCount() <= uvLayer) { printf("uv read error\n"); return ; } FbxGeometryElementUV* pVertexUV = pMesh->GetElementUV(uvLayer); switch(pVertexUV->GetMappingMode()) { case FbxGeometryElement::eByControlPoint: { switch(pVertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { pUV->x = pVertexUV->GetDirectArray().GetAt(ctrlPointIndex)[0]; pUV->y = pVertexUV->GetDirectArray().GetAt(ctrlPointIndex)[1]; } break; case FbxGeometryElement::eIndexToDirect: { int id = pVertexUV->GetIndexArray().GetAt(ctrlPointIndex); pUV->x = pVertexUV->GetDirectArray().GetAt(id)[0]; pUV->y = pVertexUV->GetDirectArray().GetAt(id)[1]; } break; default: break; } } break; case FbxGeometryElement::eByPolygonVertex: { switch (pVertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: case FbxGeometryElement::eIndexToDirect: { pUV->x = pVertexUV->GetDirectArray().GetAt(textureUVIndex)[0]; pUV->y = pVertexUV->GetDirectArray().GetAt(textureUVIndex)[1]; } break; default: break; } } break; } }
reVec2 reFBXAsset::getUV( FbxMesh* fmesh, int vi, int i, int j ) { for (int l = 0; l < fmesh->GetElementUVCount(); ++l) { FbxGeometryElementUV* leUV = fmesh->GetElementUV(l); switch (leUV->GetMappingMode()) { case FbxGeometryElement::eByControlPoint: switch (leUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { FbxVector2 uv = leUV->GetDirectArray().GetAt(vi); return reVec2(uv[0], uv[1]); break; } case FbxGeometryElement::eIndexToDirect: { int id = leUV->GetIndexArray().GetAt(vi); FbxVector2 uv = leUV->GetDirectArray().GetAt(id); return reVec2(uv[0], uv[1]); } break; default: break; // other reference modes not shown here! } break; case FbxGeometryElement::eByPolygonVertex: { int lTextureUVIndex = fmesh->GetTextureUVIndex(i, j); switch (leUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: case FbxGeometryElement::eIndexToDirect: { FbxVector2 uv = leUV->GetDirectArray().GetAt(lTextureUVIndex); return reVec2(uv[0], uv[1]); } break; default: break; // other reference modes not shown here! } } break; case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs case FbxGeometryElement::eAllSame: // doesn't make much sense for UVs case FbxGeometryElement::eNone: // doesn't make much sense for UVs break; } } }
void FBXSceneImporter::read_mesh(FbxNode *pNode, FbxMesh* pMesh) { std::vector<Mesh::Vertex> vertices; std::vector<int> indices; //pMesh->GenerateTangentsDataForAllUVSets(); Mesh *new_mesh = new Mesh(); new_mesh->set_name(pNode->GetName()); int polygonCount = pMesh->GetPolygonCount(); FbxVector4* controlPoints = pMesh->GetControlPoints(); int controlPointCount = pMesh->GetControlPointsCount(); int vertexID = 0; for (int polygon = polygonCount - 1; polygon > -1; polygon--) { int polyVertCount = pMesh->GetPolygonSize(polygon); assert(polyVertCount == 3); for (int polyVert = 0; polyVert < polyVertCount; polyVert++) { Mesh::Vertex vertex; int cpIndex = pMesh->GetPolygonVertex(polygon, polyVert); // Grab our CP index as well our position information //uniqueVert.m_nControlPointIndex = cpIndex; vertex.position[0] = controlPoints[cpIndex].mData[0]; vertex.position[1] = controlPoints[cpIndex].mData[1]; vertex.position[2] = controlPoints[cpIndex].mData[2]; vertex.position[3] = 1; // Grab UVs int uvElementCount = pMesh->GetElementUVCount(); int ctrlPointIndex = pMesh->GetPolygonVertex(polygon, polyVert); for (int uvElement = 0; uvElement < uvElementCount; uvElement++) { FbxGeometryElementUV* geomElementUV = pMesh->GetElementUV(uvElement); FbxLayerElement::EMappingMode mapMode = geomElementUV->GetMappingMode(); FbxLayerElement::EReferenceMode refMode = geomElementUV->GetReferenceMode(); if (FbxGeometryElement::eByControlPoint == mapMode) { switch (geomElementUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vertex.texture_coord.x = static_cast<float>(geomElementUV->GetDirectArray().GetAt(ctrlPointIndex).mData[0]); vertex.texture_coord.y = static_cast<float>(geomElementUV->GetDirectArray().GetAt(ctrlPointIndex).mData[1]); } break; case FbxGeometryElement::eIndexToDirect: { int index = geomElementUV->GetIndexArray().GetAt(ctrlPointIndex); vertex.texture_coord.x = static_cast<float>(geomElementUV->GetDirectArray().GetAt(index).mData[0]); vertex.texture_coord.y = static_cast<float>(geomElementUV->GetDirectArray().GetAt(index).mData[1]); } break; default: throw std::exception("Invalid Reference"); } } if (FbxGeometryElement::eByPolygonVertex == mapMode) { int directIndex = -1; if (FbxGeometryElement::eDirect == refMode) { directIndex = vertexID; } else if (FbxGeometryElement::eIndexToDirect == refMode) { directIndex = geomElementUV->GetIndexArray().GetAt(vertexID); } // If we got an index if (directIndex != -1) { FbxVector4 texture_coord = geomElementUV->GetDirectArray().GetAt(directIndex); vertex.texture_coord = D3DXVECTOR4((float)texture_coord.mData[0], (float)texture_coord.mData[1], 0, 0); } } } // Grab normals int normElementCount = pMesh->GetElementNormalCount(); for (int normalElement = 0; normalElement < normElementCount; normalElement++) { FbxGeometryElementNormal* geomElementNormal = pMesh->GetElementNormal(normalElement); FbxLayerElement::EMappingMode mapMode = geomElementNormal->GetMappingMode(); FbxLayerElement::EReferenceMode refMode = geomElementNormal->GetReferenceMode(); FbxVector4 fbxNormal; pMesh->GetPolygonVertexNormal(polygon, polyVert, fbxNormal); fbxNormal.Normalize(); vertex.normal = D3DXVECTOR4(fbxNormal.mData[0], fbxNormal.mData[1], fbxNormal.mData[2], 0); //if (FbxGeometryElement::eByControlPoint == mapMode) //{ // switch (geomElementNormal->GetReferenceMode()) // { // case FbxGeometryElement::eDirect: // { // vertex.normal.x = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(ctrlPointIndex).mData[0]); // vertex.normal.y = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(ctrlPointIndex).mData[1]); // vertex.normal.z = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(ctrlPointIndex).mData[2]); // D3DXVec4Normalize(&vertex.normal, &vertex.normal); // } // break; // // case FbxGeometryElement::eIndexToDirect: // { // int index = geomElementNormal->GetIndexArray().GetAt(ctrlPointIndex); // vertex.normal.x = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(index).mData[0]); // vertex.normal.y = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(index).mData[1]); // vertex.normal.z = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(index).mData[2]); // D3DXVec4Normalize(&vertex.normal, &vertex.normal); // } // break; // // default: // throw std::exception("Invalid Reference"); // } //} //if (FbxGeometryElement::eByPolygonVertex == mapMode) //{ // int directIndex = -1; // if (FbxGeometryElement::eDirect == refMode) // { // directIndex = vertexID; // } // else if (FbxGeometryElement::eIndexToDirect == refMode) // { // directIndex = geomElementNormal->GetIndexArray().GetAt(vertexID); // } // // // If we got an index // if (directIndex != -1) // { // FbxVector4 norm = geomElementNormal->GetDirectArray().GetAt(directIndex); // // D3DXVECTOR4 normal_final((float)norm.mData[0], (float)norm.mData[1], (float)norm.mData[2], 0); // D3DXVec4Normalize(&vertex.normal, &normal_final); // } //} } // grab tangents int tangentElementCount = pMesh->GetElementTangentCount(); for (int normalElement = 0; normalElement < tangentElementCount; normalElement++) { FbxGeometryElementTangent* geomElementTangent = pMesh->GetElementTangent(normalElement); FbxLayerElement::EMappingMode mapMode = geomElementTangent->GetMappingMode(); FbxLayerElement::EReferenceMode refMode = geomElementTangent->GetReferenceMode(); int directIndex = -1; if (FbxGeometryElement::eByPolygonVertex == mapMode) { if (FbxGeometryElement::eDirect == refMode) { directIndex = vertexID; } else if (FbxGeometryElement::eIndexToDirect == refMode) { directIndex = geomElementTangent->GetIndexArray().GetAt(vertexID); } } // If we got an index if (directIndex != 1) { FbxVector4 tangent = geomElementTangent->GetDirectArray().GetAt(directIndex); vertex.tangent = D3DXVECTOR4((float)tangent.mData[0], (float)tangent.mData[1], (float)tangent.mData[2], 0); } } size_t size = vertices.size(); size_t i = size; //for (i = 0; i < size; i++) //{ // if (vertex == vertices[i]) // { // break; // } //} // if (i == size) { vertices.push_back(vertex); } indices.push_back(i); ++vertexID; } //int cur_size = indices.size(); //int temp = indices[cur_size - 3]; //indices[cur_size - 3] = indices[cur_size - 1]; //indices[cur_size - 1] = temp; } int materialCount = pNode->GetSrcObjectCount<FbxSurfaceMaterial>(); new_mesh->create_from_buffers(vertices, indices); scene_to_fill->add_mesh(new_mesh); if (materialCount > 0) { FbxSurfaceMaterial* material = (FbxSurfaceMaterial*)pNode->GetSrcObject<FbxSurfaceMaterial>(0); new_mesh->set_material(read_material(pNode, material)); } get_transformation_matrix(pNode, new_mesh); cout << "Read mesh : " << new_mesh->get_name() << "\n"; }
std::shared_ptr<Mesh> FbxUtil::CreateMesh(FbxMesh *fbxMesh) { Mesh::Ptr mesh = Mesh::Create(fbxMesh->GetName()); // read physical data. int polygonCount = fbxMesh->GetPolygonCount(); int indicesCount = polygonCount * 3; mesh->Positions.Data.reserve(indicesCount * 3); mesh->Indices.Data.reserve(indicesCount); if ((m_Options & Options::UV) && fbxMesh->GetElementUVCount() > 0) mesh->UVs.Data.reserve(indicesCount * 2); if ((m_Options & Options::NORMAL) && fbxMesh->GetElementNormalCount() > 0) mesh->Normals.Data.reserve(indicesCount * 3); if ((m_Options & Options::TANGENT) && fbxMesh->GetElementTangent() > 0) mesh->Tangents.Data.reserve(indicesCount * 3); int normalCounter = 0, uvCounter = 0, tangentCounter = 0; for (int i = 0; i < polygonCount; i++) { for (int j = 0; j < 3; j++) { int ctrPtrIndex = fbxMesh->GetPolygonVertex(i, j); auto position = fbxMesh->GetControlPointAt(ctrPtrIndex); mesh->Positions.Data.push_back((float)position.mData[0]); mesh->Positions.Data.push_back((float)position.mData[1]); mesh->Positions.Data.push_back((float)position.mData[2]); // uv if ((m_Options & Options::UV) && fbxMesh->GetElementUVCount() > 0) { int uvIndex = 0; FbxGeometryElementUV* vertexUV = fbxMesh->GetElementUV(); if (vertexUV->GetMappingMode() == FbxGeometryElement::eByControlPoint) { if (vertexUV->GetReferenceMode() == FbxGeometryElement::eDirect) uvIndex = ctrPtrIndex; else if (vertexUV->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) uvIndex = vertexUV->GetIndexArray().GetAt(ctrPtrIndex); else ASSERT_MSG(false, "Error: Invalid Reference Mode!"); } else if (vertexUV->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { if (vertexUV->GetReferenceMode() == FbxGeometryElement::eDirect) uvIndex = uvCounter; else if (vertexUV->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) uvIndex = vertexUV->GetIndexArray().GetAt(uvCounter); else ASSERT_MSG(false, "Error: Invalid Reference Mode!"); uvCounter++; } auto uv = vertexUV->GetDirectArray().GetAt(uvIndex); mesh->UVs.Data.push_back((float)uv.mData[0]); mesh->UVs.Data.push_back(1.0f - (float)uv.mData[1]); } // normal if ((m_Options & Options::NORMAL) && fbxMesh->GetElementNormalCount() > 0) { int normalIndex = 0; FbxGeometryElementNormal* vertexNormal = fbxMesh->GetElementNormal(); if (vertexNormal->GetMappingMode() == FbxGeometryElement::eByControlPoint) { if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eDirect) normalIndex = ctrPtrIndex; else if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) normalIndex = vertexNormal->GetIndexArray().GetAt(ctrPtrIndex); else ASSERT_MSG(false, "Error: Invalid Reference Mode!"); } else if (vertexNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eDirect) normalIndex = normalCounter; else if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) normalIndex = vertexNormal->GetIndexArray().GetAt(normalCounter); else ASSERT_MSG(false, "Error: Invalid Reference Mode!"); normalCounter++; } auto normal = vertexNormal->GetDirectArray().GetAt(normalIndex); mesh->Normals.Data.push_back((float)normal.mData[0]); mesh->Normals.Data.push_back((float)normal.mData[1]); mesh->Normals.Data.push_back((float)normal.mData[2]); } // tangent if ((m_Options & Options::TANGENT) && fbxMesh->GetElementNormalCount() > 0) { int tangentIndex = 0; FbxGeometryElementTangent* vertexTangent = fbxMesh->GetElementTangent(); if (vertexTangent->GetMappingMode() == FbxGeometryElement::eByControlPoint) { if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eDirect) tangentIndex = ctrPtrIndex; else if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) tangentIndex = vertexTangent->GetIndexArray().GetAt(ctrPtrIndex); else ASSERT_MSG(false, "Error: Invalid Reference Mode!"); } else if (vertexTangent->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eDirect) tangentIndex = tangentCounter; else if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) tangentIndex = vertexTangent->GetIndexArray().GetAt(tangentCounter); else ASSERT_MSG(false, "Error: Invalid Reference Mode!"); tangentCounter++; } auto tangent = vertexTangent->GetDirectArray().GetAt(tangentIndex); mesh->Tangents.Data.push_back((float)tangent.mData[0]); mesh->Tangents.Data.push_back((float)tangent.mData[1]); mesh->Tangents.Data.push_back((float)tangent.mData[2]); } mesh->Indices.Data.push_back(i * 3 + j); } } LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]"; if(m_Options & Options::OPTIMIZE_MESH) MeshUtil::Instance()->OptimizeMesh(mesh); mesh->CalculateAABB(); return mesh; }
BabylonMesh::BabylonMesh(BabylonNode* node) : BabylonAbstractMesh(node), _isEnabled(true), _isVisible(true), _billboardMode(0), _visibility(1), _skeletonId(-1), _pickable(true), _hasVertexAlpha(false), _checkCollision(false), _receiveShadows(false), _infiniteDistance(false), _autoAnimate(false), _autoAnimateFrom(0), _autoAnimateTo(0), _autoAnimateLoop(false), _showBoundingBox(false), _showSubMeshesBoundingBox(false), _applyFog(false), _alphaIndex(0) { pivotMatrix.SetIdentity(); auto fbxNode = node->fbxNode(); std::string ansiName = fbxNode->GetName(); name(std::wstring(ansiName.begin(), ansiName.end())); id(getNodeId(fbxNode)); auto parent = fbxNode->GetParent(); if (parent) { parentId(getNodeId(parent)); } pivotMatrix = ConvertToBabylonCoordinateSystem( GetGeometryTransformation(fbxNode)); auto animStack = fbxNode->GetScene()->GetSrcObject<FbxAnimStack>(0); FbxString animStackName = animStack->GetName(); FbxTakeInfo* takeInfo = fbxNode->GetScene()->GetTakeInfo(animStackName); auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode; auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate(); auto startFrame = takeInfo->mLocalTimeSpan.GetStart().GetFrameCount(animTimeMode); auto endFrame = takeInfo->mLocalTimeSpan.GetStop().GetFrameCount(animTimeMode); auto animLengthInFrame = endFrame - startFrame + 1; _visibility = static_cast<float>(node->fbxNode()->Visibility.Get()); auto posAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"position", L"position", true, 0, static_cast<int>(animLengthInFrame), true); auto rotAnim = std::make_shared<BabylonAnimation<babylon_vector4>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"rotationQuaternion", L"rotationQuaternion", true, 0, static_cast<int>(animLengthInFrame), true); auto scaleAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"scaling", L"scaling", true, 0, static_cast<int>(animLengthInFrame), true); auto visibilityAnim = std::make_shared<BabylonAnimation<float>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"visibility", L"visibility", true, 0, static_cast<int>(animLengthInFrame), true); auto mesh = fbxNode->GetMesh(); _isVisible = fbxNode->Show.Get(); auto rotCurveNode = fbxNode->LclRotation.GetCurveNode(); auto translateCurveNode = fbxNode->LclTranslation.GetCurveNode(); auto scalingCurveNode = fbxNode->LclScaling.GetCurveNode(); auto visibilityCurveNode = fbxNode->Visibility.GetCurveNode(); if (rotCurveNode || translateCurveNode || scalingCurveNode) { for (auto ix = 0; ix < animLengthInFrame; ix++) { FbxTime currTime; currTime.SetFrame(startFrame + ix, animTimeMode); babylon_animation_key<babylon_vector3> poskey; babylon_animation_key<babylon_vector4> rotkey; babylon_animation_key<babylon_vector3> scalekey; poskey.frame = ix; rotkey.frame = ix; scalekey.frame = ix; auto currTransform = node->GetLocal(currTime); poskey.values = currTransform.translation(); rotkey.values = currTransform.rotationQuaternion(); scalekey.values = currTransform.scaling(); posAnim->appendKey(poskey); rotAnim->appendKey(rotkey); scaleAnim->appendKey(scalekey); } } if (visibilityCurveNode) { for (auto ix = 0; ix < animLengthInFrame; ix++) { FbxTime currTime; currTime.SetFrame(startFrame + ix, animTimeMode); babylon_animation_key<float> visibilityKey; visibilityKey.frame = ix; visibilityKey.values = static_cast<float>(node->fbxNode()->Visibility.EvaluateValue(currTime)); visibilityAnim->appendKey(visibilityKey); } } if (!posAnim->isConstant()){ animations.push_back(posAnim); } if (!rotAnim->isConstant()){ animations.push_back(rotAnim); } if (!scaleAnim->isConstant()){ animations.push_back(scaleAnim); } if (!visibilityAnim->isConstant()) { animations.push_back(visibilityAnim); } if (!mesh) { return; } if (mesh->GetPolygonCount() == 0){ return; } _receiveShadows = mesh->ReceiveShadow.Get(); FbxGeometryConverter conv(mesh->GetFbxManager()); conv.ComputePolygonSmoothingFromEdgeSmoothing(mesh); if (!mesh->IsTriangleMesh()) { mesh = (FbxMesh*) conv.Triangulate(mesh, true); } mesh->RemoveBadPolygons(); mesh->GenerateNormals(); FbxStringList uvSetNameList; mesh->GetUVSetNames(uvSetNameList); std::vector<std::string> uniqueUVSets; int uvCount = uvSetNameList.GetCount(); for (int i = 0; i < uvCount; ++i) { std::string value = uvSetNameList.GetStringAt(i); if (std::find(uniqueUVSets.begin(), uniqueUVSets.end(), value) == uniqueUVSets.end()) { uniqueUVSets.push_back(value); } } uvsets = uniqueUVSets; bool hasUv = uniqueUVSets.size() > 0; bool hasUv2 = uniqueUVSets.size() > 1; bool hasUv3 = uniqueUVSets.size() > 2; bool hasUv4 = uniqueUVSets.size() > 3; bool hasUv5 = uniqueUVSets.size() > 4; bool hasUv6 = uniqueUVSets.size() > 5; std::string uvSetName; std::string uv2SetName; std::string uv3SetName; std::string uv4SetName; std::string uv5SetName; std::string uv6SetName; if (hasUv) { uvSetName = uniqueUVSets[0]; } if (hasUv2) { uv2SetName = uniqueUVSets[1]; } if (hasUv3) { uv3SetName = uniqueUVSets[2]; } if (hasUv4) { uv4SetName = uniqueUVSets[3]; } if (hasUv5) { uv5SetName = uniqueUVSets[4]; } if (hasUv6) { uv6SetName = uniqueUVSets[5]; } auto colors = mesh->GetElementVertexColor(); FbxLayerElement::EMappingMode colorMappingMode; FbxLayerElement::EReferenceMode colorReferenceMode; if (colors) { colorMappingMode = colors->GetMappingMode(); colorReferenceMode = colors->GetReferenceMode(); } auto normals = mesh->GetElementNormal(); FbxGeometryElementUV* uvs = nullptr; FbxGeometryElementUV* uvs2 = nullptr; FbxGeometryElementUV* uvs3 = nullptr; FbxGeometryElementUV* uvs4 = nullptr; FbxGeometryElementUV* uvs5 = nullptr; FbxGeometryElementUV* uvs6 = nullptr; FbxLayerElement::EMappingMode uvsMappingMode; FbxLayerElement::EReferenceMode uvsReferenceMode; FbxLayerElement::EMappingMode uvs2MappingMode; FbxLayerElement::EReferenceMode uvs2ReferenceMode; FbxLayerElement::EMappingMode uvs3MappingMode; FbxLayerElement::EReferenceMode uvs3ReferenceMode; FbxLayerElement::EMappingMode uvs4MappingMode; FbxLayerElement::EReferenceMode uvs4ReferenceMode; FbxLayerElement::EMappingMode uvs5MappingMode; FbxLayerElement::EReferenceMode uvs5ReferenceMode; FbxLayerElement::EMappingMode uvs6MappingMode; FbxLayerElement::EReferenceMode uvs6ReferenceMode; if (hasUv) { uvs = mesh->GetElementUV(uvSetName.c_str()); uvsMappingMode = uvs->GetMappingMode(); uvsReferenceMode = uvs->GetReferenceMode(); } if (hasUv2) { uvs2 = mesh->GetElementUV(uv2SetName.c_str()); uvs2MappingMode = uvs2->GetMappingMode(); uvs2ReferenceMode = uvs2->GetReferenceMode(); } if (hasUv3) { uvs3 = mesh->GetElementUV(uv3SetName.c_str()); uvs3MappingMode = uvs3->GetMappingMode(); uvs3ReferenceMode = uvs3->GetReferenceMode(); } if (hasUv4) { uvs4 = mesh->GetElementUV(uv4SetName.c_str()); uvs4MappingMode = uvs4->GetMappingMode(); uvs4ReferenceMode = uvs4->GetReferenceMode(); } if (hasUv5) { uvs5 = mesh->GetElementUV(uv5SetName.c_str()); uvs5MappingMode = uvs5->GetMappingMode(); uvs5ReferenceMode = uvs5->GetReferenceMode(); } if (hasUv6) { uvs6 = mesh->GetElementUV(uv6SetName.c_str()); uvs6MappingMode = uvs6->GetMappingMode(); uvs6ReferenceMode = uvs6->GetReferenceMode(); } auto normalMappingMode = normals->GetMappingMode(); auto normalReferenceMode = normals->GetReferenceMode(); std::vector<SubmeshData> submeshes; auto materialCount = node->fbxNode()->GetMaterialCount(); if (materialCount == 0) { materialCount = 1; } submeshes.resize(materialCount); auto baseLayer = mesh->GetLayer(0); auto materials = baseLayer->GetMaterials(); FbxLayerElement::EMappingMode materialMappingMode = materials ? materials->GetMappingMode() : FbxLayerElement::eByPolygon; // extract deformers SkinInfo skinInfo(fbxNode); if (skinInfo.hasSkin()){ associatedSkeleton = std::make_shared<BabylonSkeleton>(); skinInfo.buildBabylonSkeleton(*associatedSkeleton); } auto triangleCount = mesh->GetPolygonCount(); for (int triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex) { int materialIndex = 0; if (materialCount > 0 && materials) { switch (materialMappingMode) { case FbxLayerElement::eAllSame: materialIndex = materials->GetIndexArray().GetAt(0); break; case FbxLayerElement::eByPolygon: materialIndex = materials->GetIndexArray().GetAt(triangleIndex); } } auto& submesh = submeshes[materialIndex]; triangle t; for (int cornerIndex = 0; cornerIndex < 3; ++cornerIndex) { auto controlPointIndex = mesh->GetPolygonVertex(triangleIndex, cornerIndex); auto vertexIndex = triangleIndex * 3 + cornerIndex; auto position = mesh->GetControlPoints()[controlPointIndex]; position[2] = -position[2]; BabylonVertex v; v.position = position; if (normals) { int normalMapIndex = (normalMappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int normalValueIndex = (normalReferenceMode == FbxLayerElement::eDirect) ? normalMapIndex : normals->GetIndexArray().GetAt(normalMapIndex); v.normal = normals->GetDirectArray().GetAt(normalValueIndex); v.normal.z = -v.normal.z; } if (colors) { int mappingIndex = (colorMappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (colorReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : colors->GetIndexArray().GetAt(mappingIndex); v.color = colors->GetDirectArray().GetAt(valueIndex); } if (uvs) { int mappingIndex = (uvsMappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvsReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs->GetIndexArray().GetAt(mappingIndex); v.uv = uvs->GetDirectArray().GetAt(valueIndex); //v.uv.y = 1 - v.uv.y; } if (uvs2) { int mappingIndex = (uvs2MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs2ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs2->GetIndexArray().GetAt(mappingIndex); v.uv2 = uvs2->GetDirectArray().GetAt(valueIndex); } if (uvs3) { int mappingIndex = (uvs3MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs3ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs3->GetIndexArray().GetAt(mappingIndex); v.uv3 = uvs3->GetDirectArray().GetAt(valueIndex); } if (uvs4) { int mappingIndex = (uvs4MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs4ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs4->GetIndexArray().GetAt(mappingIndex); v.uv4 = uvs4->GetDirectArray().GetAt(valueIndex); } if (uvs5) { int mappingIndex = (uvs5MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs5ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs5->GetIndexArray().GetAt(mappingIndex); v.uv5 = uvs5->GetDirectArray().GetAt(valueIndex); } if (uvs6) { int mappingIndex = (uvs6MappingMode == FbxLayerElement::eByControlPoint) ? controlPointIndex : vertexIndex; int valueIndex = (uvs6ReferenceMode == FbxLayerElement::eDirect) ? mappingIndex : uvs6->GetIndexArray().GetAt(mappingIndex); v.uv6 = uvs6->GetDirectArray().GetAt(valueIndex); } if (skinInfo.hasSkin()){ auto& skinData = skinInfo.controlPointBoneIndicesAndWeights(controlPointIndex); for (auto boneix = 0; boneix < skinData.size()&&boneix<4; ++boneix){ v.boneIndices[boneix] = skinData[boneix].index; v.boneWeights[boneix] = static_cast<float>(skinData[boneix].weight); } for (auto boneix = skinData.size(); boneix < 4; ++boneix){ v.boneIndices[boneix] = skinInfo.bonesCount(); v.boneWeights[boneix] = 0; } } auto foundVertex = submesh.knownVertices.find(v); if (foundVertex != submesh.knownVertices.end()) { //submesh.indices.push_back(foundVertex->second); t.indices[cornerIndex] = foundVertex->second; } else { auto index = static_cast<int>(submesh.vertices.size()); submesh.vertices.push_back(v); //submesh.indices.push_back(index); submesh.knownVertices[v] = index; t.indices[cornerIndex] = index; } } if (submesh.knownTriangles.insert(t).second) { submesh.indices.push_back(t.indices[0]); submesh.indices.push_back(t.indices[1]); submesh.indices.push_back(t.indices[2]); } else { std::cout << "duplicate triangle found (and eliminated) in " << fbxNode->GetName() << std::endl; } } std::uint32_t vertexOffset = 0; for (auto matIndex = 0u; matIndex < submeshes.size(); ++matIndex) { auto& submesh = submeshes[matIndex]; BabylonSubmesh babsubmesh; babsubmesh.indexCount = static_cast<int>(submesh.indices.size()); babsubmesh.indexStart = static_cast<int>(_indices.size()); babsubmesh.materialIndex = matIndex; babsubmesh.verticesCount = static_cast<int>(submesh.vertices.size()); babsubmesh.verticesStart = static_cast<int>(_positions.size()); for (auto& v : submesh.vertices) { _positions.push_back(v.position); if (normals) { _normals.push_back(v.normal); } if (colors) { _colors.push_back(v.color); } if (uvs) { _uvs.push_back(v.uv); } if (uvs2) { _uvs2.push_back(v.uv2); } if (uvs3) { _uvs3.push_back(v.uv3); } if (uvs4) { _uvs4.push_back(v.uv4); } if (uvs5) { _uvs5.push_back(v.uv5); } if (uvs6) { _uvs6.push_back(v.uv6); } if (skinInfo.hasSkin()){ float weight0 = v.boneWeights[0]; float weight1 = v.boneWeights[1]; float weight2 = v.boneWeights[2]; int bone0 = v.boneIndices[0]; int bone1 = v.boneIndices[1]; int bone2 = v.boneIndices[2]; int bone3 = v.boneIndices[3]; _boneWeights.push_back(babylon_vector4( weight0, weight1, weight2, 1.0f - weight0 - weight1 - weight2)); _boneIndices.push_back((bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0); } } for (auto i : submesh.indices) { _indices.push_back(i + vertexOffset); } vertexOffset = static_cast<int>(_positions.size()); _submeshes.push_back(babsubmesh); } }
//converts a FBX mesh to a CC mesh static ccMesh* FromFbxMesh(FbxMesh* fbxMesh, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, CCVector3d* coordinatesShift/*=0*/) { if (!fbxMesh) return 0; int polyCount = fbxMesh->GetPolygonCount(); //fbxMesh->GetLayer( unsigned triCount = 0; unsigned polyVertCount = 0; //different from vertCount (vertices can be counted multiple times here!) //as we can't load all polygons (yet ;) we already look if we can load any! { unsigned skipped = 0; for (int i=0; i<polyCount; ++i) { int pSize = fbxMesh->GetPolygonSize(i); if (pSize == 3) { ++triCount; polyVertCount += 3; } else if (pSize == 4) { triCount += 2; polyVertCount += 4; } else { ++skipped; } } if (triCount == 0) { ccLog::Warning(QString("[FBX] No triangle or quad found in mesh '%1'! (polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName())); return 0; } else if (skipped != 0) { ccLog::Warning(QString("[FBX] Some polygons in mesh '%1' were ignored (%2): polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName()).arg(skipped)); return 0; } } int vertCount = fbxMesh->GetControlPointsCount(); if (vertCount <= 0) { ccLog::Warning(QString("[FBX] Mesh '%1' has no vetex or no polygon?!").arg(fbxMesh->GetName())); return 0; } ccPointCloud* vertices = new ccPointCloud("vertices"); ccMesh* mesh = new ccMesh(vertices); mesh->setName(fbxMesh->GetName()); mesh->addChild(vertices); vertices->setEnabled(false); if (!mesh->reserve(static_cast<unsigned>(triCount)) || !vertices->reserve(vertCount)) { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1'!").arg(fbxMesh->GetName())); delete mesh; return 0; } //colors { for (int l=0; l<fbxMesh->GetElementVertexColorCount(); l++) { FbxGeometryElementVertexColor* vertColor = fbxMesh->GetElementVertexColor(l); //CC can only handle per-vertex colors if (vertColor->GetMappingMode() == FbxGeometryElement::eByControlPoint) { if (vertColor->GetReferenceMode() == FbxGeometryElement::eDirect || vertColor->GetReferenceMode() == FbxGeometryElement::eIndexToDirect) { if (vertices->reserveTheRGBTable()) { switch (vertColor->GetReferenceMode()) { case FbxGeometryElement::eDirect: { for (int i=0; i<vertCount; ++i) { FbxColor c = vertColor->GetDirectArray().GetAt(i); vertices->addRGBColor( static_cast<colorType>(c.mRed * MAX_COLOR_COMP), static_cast<colorType>(c.mGreen * MAX_COLOR_COMP), static_cast<colorType>(c.mBlue * MAX_COLOR_COMP) ); } } break; case FbxGeometryElement::eIndexToDirect: { for (int i=0; i<vertCount; ++i) { int id = vertColor->GetIndexArray().GetAt(i); FbxColor c = vertColor->GetDirectArray().GetAt(id); vertices->addRGBColor( static_cast<colorType>(c.mRed * MAX_COLOR_COMP), static_cast<colorType>(c.mGreen * MAX_COLOR_COMP), static_cast<colorType>(c.mBlue * MAX_COLOR_COMP) ); } } break; default: assert(false); break; } vertices->showColors(true); mesh->showColors(true); break; //no need to look for other color fields (we won't be able to handle them! } else { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' colors!").arg(fbxMesh->GetName())); } } else { ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName())); } } else { ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName())); } } } //normals can be per vertices or per-triangle int perPointNormals = -1; int perVertexNormals = -1; int perPolygonNormals = -1; { for (int j=0; j<fbxMesh->GetElementNormalCount(); j++) { FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(j); switch(leNormals->GetMappingMode()) { case FbxGeometryElement::eByControlPoint: perPointNormals = j; break; case FbxGeometryElement::eByPolygonVertex: perVertexNormals = j; break; case FbxGeometryElement::eByPolygon: perPolygonNormals = j; break; default: //not handled break; } } } //per-point normals if (perPointNormals >= 0) { FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(perPointNormals); FbxLayerElement::EReferenceMode refMode = leNormals->GetReferenceMode(); const FbxLayerElementArrayTemplate<FbxVector4>& normals = leNormals->GetDirectArray(); assert(normals.GetCount() == vertCount); if (normals.GetCount() != vertCount) { ccLog::Warning(QString("[FBX] Wrong number of normals on mesh '%1'!").arg(fbxMesh->GetName())); perPointNormals = -1; } else if (!vertices->reserveTheNormsTable()) { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName())); perPointNormals = -1; } else { //import normals for (int i=0; i<vertCount; ++i) { int id = refMode != FbxGeometryElement::eDirect ? leNormals->GetIndexArray().GetAt(i) : i; FbxVector4 N = normals.GetAt(id); //convert to CC-structure CCVector3 Npc( static_cast<PointCoordinateType>(N.Buffer()[0]), static_cast<PointCoordinateType>(N.Buffer()[1]), static_cast<PointCoordinateType>(N.Buffer()[2]) ); vertices->addNorm(Npc.u); } vertices->showNormals(true); mesh->showNormals(true); //no need to import the other normals (if any) perVertexNormals = -1; perPolygonNormals = -1; } } //per-triangle normals NormsIndexesTableType* normsTable = 0; if (perVertexNormals >= 0 || perPolygonNormals >= 0) { normsTable = new NormsIndexesTableType(); if (!normsTable->reserve(polyVertCount) || !mesh->reservePerTriangleNormalIndexes()) { ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName())); normsTable->release(); normsTable = 0; } else { mesh->setTriNormsTable(normsTable); mesh->addChild(normsTable); vertices->showNormals(true); mesh->showNormals(true); } } //import textures UV int perVertexUV = -1; bool hasTexUV = false; { for (int l=0; l<fbxMesh->GetElementUVCount(); ++l) { FbxGeometryElementUV* leUV = fbxMesh->GetElementUV(l); //per-point UV coordinates if (leUV->GetMappingMode() == FbxGeometryElement::eByControlPoint) { TextureCoordsContainer* vertTexUVTable = new TextureCoordsContainer(); if (!vertTexUVTable->reserve(vertCount) || !mesh->reservePerTriangleTexCoordIndexes()) { vertTexUVTable->release(); ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' UV coordinates!").arg(fbxMesh->GetName())); } else { FbxLayerElement::EReferenceMode refMode = leUV->GetReferenceMode(); for (int i=0; i<vertCount; ++i) { int id = refMode != FbxGeometryElement::eDirect ? leUV->GetIndexArray().GetAt(i) : i; FbxVector2 uv = leUV->GetDirectArray().GetAt(id); //convert to CC-structure float uvf[2] = {static_cast<float>(uv.Buffer()[0]), static_cast<float>(uv.Buffer()[1])}; vertTexUVTable->addElement(uvf); } mesh->addChild(vertTexUVTable); hasTexUV = true; } perVertexUV = -1; break; //no need to look to the other UV fields (can't handle them!) } else if (leUV->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { //per-vertex UV coordinates perVertexUV = l; } } } //per-vertex UV coordinates TextureCoordsContainer* texUVTable = 0; if (perVertexUV >= 0) { texUVTable = new TextureCoordsContainer(); if (!texUVTable->reserve(polyVertCount) || !mesh->reservePerTriangleTexCoordIndexes()) { texUVTable->release(); ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' UV coordinates!").arg(fbxMesh->GetName())); } else { mesh->addChild(texUVTable); hasTexUV = true; } } //import polygons { for (int i=0; i<polyCount; ++i) { int pSize = fbxMesh->GetPolygonSize(i); if (pSize > 4) { //not handled for the moment continue; } //we split quads into two triangles //vertex indices int i1 = fbxMesh->GetPolygonVertex(i, 0); int i2 = fbxMesh->GetPolygonVertex(i, 1); int i3 = fbxMesh->GetPolygonVertex(i, 2); mesh->addTriangle(i1,i2,i3); int i4 = -1; if (pSize == 4) { i4 = fbxMesh->GetPolygonVertex(i, 3); mesh->addTriangle(i1,i3,i4); } if (hasTexUV) { if (texUVTable) { assert(perVertexUV >= 0); int uvIndex = static_cast<int>(texUVTable->currentSize()); for (int j=0; j<pSize; ++j) { int lTextureUVIndex = fbxMesh->GetTextureUVIndex(i, j); FbxGeometryElementUV* leUV = fbxMesh->GetElementUV(perVertexUV); FbxVector2 uv = leUV->GetDirectArray().GetAt(lTextureUVIndex); //convert to CC-structure float uvf[2] = {static_cast<float>(uv.Buffer()[0]), static_cast<float>(uv.Buffer()[1])}; texUVTable->addElement(uvf); } mesh->addTriangleTexCoordIndexes(uvIndex,uvIndex+1,uvIndex+2); if (pSize == 4) mesh->addTriangleTexCoordIndexes(uvIndex,uvIndex+2,uvIndex+3); } else { mesh->addTriangleTexCoordIndexes(i1,i2,i3); if (pSize == 4) mesh->addTriangleTexCoordIndexes(i1,i3,i4); } } //per-triangle normals if (normsTable) { int nIndex = static_cast<int>(normsTable->currentSize()); for (int j=0; j<pSize; ++j) { FbxVector4 N; fbxMesh->GetPolygonVertexNormal(i, j, N); CCVector3 Npc( static_cast<PointCoordinateType>(N.Buffer()[0]), static_cast<PointCoordinateType>(N.Buffer()[1]), static_cast<PointCoordinateType>(N.Buffer()[2]) ); normsTable->addElement(ccNormalVectors::GetNormIndex(Npc.u)); } mesh->addTriangleNormalIndexes(nIndex,nIndex+1,nIndex+2); if (pSize == 4) mesh->addTriangleNormalIndexes(nIndex,nIndex+2,nIndex+3); } } if (mesh->size() == 0) { ccLog::Warning(QString("[FBX] No triangle found in mesh '%1'! (only triangles are supported for the moment)").arg(fbxMesh->GetName())); delete mesh; return 0; } } //import vertices { const FbxVector4* fbxVertices = fbxMesh->GetControlPoints(); assert(vertices && fbxVertices); CCVector3d Pshift(0,0,0); for (int i=0; i<vertCount; ++i, ++fbxVertices) { const double* P = fbxVertices->Buffer(); assert(P[3] == 0); //coordinate shift management if (i == 0) { bool shiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift); if (shiftAlreadyEnabled) Pshift = *coordinatesShift; bool applyAll = false; if ( sizeof(PointCoordinateType) < 8 && ccCoordinatesShiftManager::Handle(P,0,alwaysDisplayLoadDialog,shiftAlreadyEnabled,Pshift,0,applyAll)) { vertices->setGlobalShift(Pshift); ccLog::Warning("[FBX] Mesh has been recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z); //we save coordinates shift information if (applyAll && coordinatesShiftEnabled && coordinatesShift) { *coordinatesShiftEnabled = true; *coordinatesShift = Pshift; } } } CCVector3 PV( static_cast<PointCoordinateType>(P[0] + Pshift.x), static_cast<PointCoordinateType>(P[1] + Pshift.y), static_cast<PointCoordinateType>(P[2] + Pshift.z) ); vertices->addPoint(PV); } } //import textures { //TODO } return mesh; }
HRESULT CStaticMesh::Load_StaticMesh(const char* szFilePath,const char* szFileName, FbxManager* _pFBXManager, FbxIOSettings* _pIOsettings, FbxScene* _pFBXScene, FbxImporter* _pImporter) { HRESULT hr = E_FAIL; vector<UINT> vecIndeces; string strFullPath; strFullPath.clear(); strFullPath = szFilePath; strFullPath += szFileName;//경로에 파일이름 추가 if (!(_pImporter->Initialize(strFullPath.c_str(), -1, _pFBXManager->GetIOSettings()))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Init Failed"); if (!(_pImporter->Import(_pFBXScene))) FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Import Failed"); FbxGeometryConverter clsConverter(_pFBXManager); clsConverter.Triangulate(_pFBXScene, false); FbxNode* pRootNode = _pFBXScene->GetRootNode(); if (!pRootNode) return E_FAIL; vector<VTXTEX> vecVTXTEX; for (int i = 0; i < pRootNode->GetChildCount(); ++i) { FbxNode* pChildNode = pRootNode->GetChild(i); if (pChildNode->GetNodeAttribute() == NULL) continue; FbxNodeAttribute::EType AttributeType = pChildNode->GetNodeAttribute()->GetAttributeType(); if (AttributeType != FbxNodeAttribute::eMesh) continue; FbxMesh* pMesh = (FbxMesh*)pChildNode->GetNodeAttribute(); // 임폴트 하려는 메쉬의 데이터 D3DXVECTOR3 vPos; D3DXVECTOR2 vOutUV; D3DXVECTOR3 vOutNormal; FbxVector4* mControlPoints = pMesh->GetControlPoints(); int iVTXCounter = 0; for (int j = 0; j < pMesh->GetPolygonCount(); j++) // 폴리곤의 인덱스 { int iNumVertices = pMesh->GetPolygonSize(j); assert(iNumVertices == 3); FbxGeometryElementUV* VtxUV = pMesh->GetElementUV(0); FbxGeometryElementNormal* VtxNormal = pMesh->GetElementNormal(0); for (int k = 0; k < iNumVertices; k++) // 폴리곤을 구성하는 버텍스의 인덱스 { //정점 데이터 얻는곳 int iControlPointIndex = pMesh->GetPolygonVertex(j, k); // 컨트롤 포인트 = 하나의 버텍스 int iTextureUVIndex = pMesh->GetTextureUVIndex(j, k); // Control = Vertex //int iNormalIndex = pMesh->GetPolygonVertexIndex(j, k); ++iVTXCounter; vPos.x = (float)mControlPoints[iControlPointIndex].mData[0]; vPos.y = -(float)mControlPoints[iControlPointIndex].mData[1]; vPos.z = (float)mControlPoints[iControlPointIndex].mData[2]; //uv 얻기 switch (VtxUV->GetMappingMode()) // UV값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[1]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxUV->GetIndexArray().GetAt(iControlPointIndex); vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[0]); vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[1]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } case FbxGeometryElement::eIndexToDirect: { vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]); vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } //노멀얻기 switch (VtxNormal->GetMappingMode()) // 노멀값 추출 { case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[2]); } break; case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iControlPointIndex); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("Invalid Reference"); } break; case FbxGeometryElement::eByPolygonVertex: // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳 switch (VtxNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } case FbxGeometryElement::eIndexToDirect: { int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter); vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]); vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]); vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]); } break; default: throw std::exception("invalid Reference"); } break; default: throw std::exception("Invalid Reference"); break; } VTXTEX vtxtex; vtxtex.vPos = vPos; vtxtex.vNormal = vOutNormal; vtxtex.vTexUV = vOutUV; vecVTXTEX.push_back(vtxtex); //int index = VtxUV->GetIndexArray().GetAt(iTextureUVIndex); vecIndeces.push_back(VtxUV->GetIndexArray().GetAt(iTextureUVIndex)); } } } unsigned int n = vecVTXTEX.size(); VTXTEX* pVTXTex = new VTXTEX[n]; for (unsigned int i = 0; i < vecVTXTEX.size(); ++i) { pVTXTex[i].vPos = vecVTXTEX[i].vPos; pVTXTex[i].vNormal = vecVTXTEX[i].vNormal; pVTXTex[i].vTexUV = vecVTXTEX[i].vTexUV; } m_iVertices = vecVTXTEX.size(); m_iVertexStrides = sizeof(VTXTEX); m_iVertexOffsets = 0; MakeVertexNormal((BYTE*)pVTXTex, NULL); D3D11_BUFFER_DESC tBufferDesc; ZeroMemory(&tBufferDesc, sizeof(D3D11_BUFFER_DESC)); tBufferDesc.Usage = D3D11_USAGE_DEFAULT; tBufferDesc.ByteWidth = m_iVertexStrides * m_iVertices; tBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; tBufferDesc.CPUAccessFlags = 0; D3D11_SUBRESOURCE_DATA tData; ZeroMemory(&tData, sizeof(D3D11_SUBRESOURCE_DATA)); tData.pSysMem = pVTXTex; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&tBufferDesc, &tData, &m_VertexBuffer); ::Safe_Delete(pVTXTex); if (FAILED(hr)) return E_FAIL; D3D11_BUFFER_DESC cbd; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.ByteWidth = sizeof(ConstantBuffer); cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cbd.CPUAccessFlags = 0; cbd.MiscFlags = 0; cbd.StructureByteStride = 0; hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&cbd, NULL, &m_ConstantBuffer); if (FAILED(hr)) { MessageBox(NULL, L"System Message", L"Constant Buffer Error", MB_OK); return hr; } return S_OK; }
void fbxLoader2::readUV(FbxMesh* mesh, int controlPointIndex, int uvLayer, D3DXVECTOR2* uv) { if (uvLayer >= 2 || mesh->GetElementUVCount() <= uvLayer) { return; } FbxGeometryElementUV* vertexUV = mesh->GetElementUV(uvLayer); switch(vertexUV->GetMappingMode()) { case FbxGeometryElement::eByControlPoint: { switch(vertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { uv->x = (float)vertexUV->GetDirectArray().GetAt(controlPointIndex).mData[0]; uv->y = (float)vertexUV->GetDirectArray().GetAt(controlPointIndex).mData[1]; } break; case FbxGeometryElement::eIndexToDirect: { int id = vertexUV->GetIndexArray().GetAt(controlPointIndex); uv->x = (float)vertexUV->GetDirectArray().GetAt(id).mData[0]; uv->y = (float)vertexUV->GetDirectArray().GetAt(id).mData[1]; } break; } } break; case FbxGeometryElement::ePolygonGroup: { switch(vertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { uv->x = (float)vertexUV->GetDirectArray().GetAt(controlPointIndex).mData[0]; uv->y = (float)vertexUV->GetDirectArray().GetAt(controlPointIndex).mData[1]; } break; case FbxGeometryElement::eIndexToDirect: { int id = vertexUV->GetIndexArray().GetAt(controlPointIndex); uv->x = (float)vertexUV->GetDirectArray().GetAt(id).mData[0]; uv->y = (float)vertexUV->GetDirectArray().GetAt(id).mData[1]; } break; } } break; default: int id = vertexUV->GetIndexArray().GetAt(controlPointIndex); uv->x = (float)vertexUV->GetDirectArray().GetAt(id).mData[0]; uv->y = (float)vertexUV->GetDirectArray().GetAt(id).mData[1]; //vertexUV->GetIndexArray().GetAt(controlPointIndex).mData[0]; } }
// 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; }
//=============================================================================================================================== bool FBXLoader::LoadVertexTexture(FbxMesh* mesh, int inCtrlPointIndex, int inTextureIndex, int inTextureLayer, XMFLOAT2& outTexture) { if (inTextureLayer >= 2 || mesh->GetElementUVCount() <= inTextureLayer) { throw std::exception("Invalid UV Layer Number"); } int directIndex = -1; FbxGeometryElementUV* vertexUV = mesh->GetElementUV(inTextureLayer); switch (vertexUV->GetMappingMode()) { case FbxGeometryElement::eByControlPoint: { switch (vertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: { directIndex = inCtrlPointIndex; //outTexture.x = static_cast<float>(vertexUV->GetDirectArray().GetAt(inCtrlPointIndex).mData[0]); //outTexture.y = static_cast<float>(vertexUV->GetDirectArray().GetAt(inCtrlPointIndex).mData[1]); } break; case FbxGeometryElement::eIndexToDirect: { directIndex = vertexUV->GetIndexArray().GetAt(inCtrlPointIndex); //int index = vertexUV->GetIndexArray().GetAt(inCtrlPointIndex); //outTexture.x = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[0]); //outTexture.y = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[1]); } break; default: throw std::exception("Invalid Reference"); } } break; case FbxGeometryElement::eByPolygonVertex: { switch (vertexUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: case FbxGeometryElement::eIndexToDirect: { directIndex = inTextureIndex; //outTexture.x = static_cast<float>(vertexUV->GetDirectArray().GetAt(inTextureIndex).mData[0]); //outTexture.y = static_cast<float>(vertexUV->GetDirectArray().GetAt(inTextureIndex).mData[1]); } break; default: throw std::exception("Invalid Reference"); } } break; } if (directIndex != -1) { FbxVector2 uv = vertexUV->GetDirectArray().GetAt(directIndex); outTexture = XMFLOAT2((float)uv.mData[0], (float)uv.mData[1]); return true; } return false; }
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); } }
//-------------------------------------------------------------------------- void SaveMesh(FbxNode* pNode, const VeDirectoryPtr& spDest) noexcept { Mesh kMesh; FbxMesh* pMesh = (FbxMesh*)pNode->GetNodeAttribute(); kMesh.m_kName = pNode->GetName(); kMesh.m_stFaces = pMesh->GetPolygonCount(); kMesh.m_stVerts = kMesh.m_stFaces * 3; kMesh.m_kIndices.resize(kMesh.m_stVerts); kMesh.m_kPosition.resize(kMesh.m_stVerts); kMesh.m_kNormals.resize(pMesh->GetElementNormalCount()); for (auto& v : kMesh.m_kNormals) { v.resize(kMesh.m_stVerts); } kMesh.m_kTexcoords.resize(pMesh->GetElementUVCount()); for (auto& v : kMesh.m_kTexcoords) { v.resize(kMesh.m_stVerts); } kMesh.m_kColors.resize(pMesh->GetElementVertexColorCount()); for (auto& v : kMesh.m_kColors) { v.resize(kMesh.m_stVerts); } int element_mat = -1; for (int i(0); i < pMesh->GetElementMaterialCount(); ++i) { FbxGeometryElementMaterial* lMaterialElement = pMesh->GetElementMaterial(i); if (lMaterialElement->GetMappingMode() == FbxGeometryElement::eByPolygon) { element_mat = i; break; } } if (element_mat >= 0) { kMesh.m_kAttributes.resize(kMesh.m_stFaces); } FbxVector4* lControlPoints = pMesh->GetControlPoints(); for (int i(0); i < (int)(kMesh.m_stFaces); ++i) { int lPolygonSize = pMesh->GetPolygonSize(i); VE_ASSERT_ALWAYS(lPolygonSize == 3); for (int j(0); j < lPolygonSize; ++j) { uint32_t u32Index = i * 3 + j; kMesh.m_kIndices[u32Index] = u32Index; int lControlPointIndex = pMesh->GetPolygonVertex(i, j); auto& pos = kMesh.m_kPosition[u32Index]; pos.x = (float)lControlPoints[lControlPointIndex][0]; pos.y = (float)lControlPoints[lControlPointIndex][1]; pos.z = (float)lControlPoints[lControlPointIndex][2]; for (int k(0); k < (int)(kMesh.m_kColors.size()); ++k) { FbxColor c; FbxGeometryElementVertexColor* leVtxc = pMesh->GetElementVertexColor(k); switch (leVtxc->GetMappingMode()) { default: break; case FbxGeometryElement::eByControlPoint: switch (leVtxc->GetReferenceMode()) { case FbxGeometryElement::eDirect: c = leVtxc->GetDirectArray().GetAt(lControlPointIndex); break; case FbxGeometryElement::eIndexToDirect: { int id = leVtxc->GetIndexArray().GetAt(lControlPointIndex); c = leVtxc->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } break; case FbxGeometryElement::eByPolygonVertex: { switch (leVtxc->GetReferenceMode()) { case FbxGeometryElement::eDirect: c = leVtxc->GetDirectArray().GetAt(u32Index); break; case FbxGeometryElement::eIndexToDirect: { int id = leVtxc->GetIndexArray().GetAt(u32Index); c = leVtxc->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } } break; case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs case FbxGeometryElement::eAllSame: // doesn't make much sense for UVs case FbxGeometryElement::eNone: // doesn't make much sense for UVs break; } auto& color = kMesh.m_kColors[k][u32Index]; color.x = (float)c[0]; color.y = (float)c[1]; color.z = (float)c[2]; color.w = (float)c[3]; } for (int k(0); k < (int)(kMesh.m_kTexcoords.size()); ++k) { FbxVector2 uv; FbxGeometryElementUV* leUV = pMesh->GetElementUV(k); switch (leUV->GetMappingMode()) { default: break; case FbxGeometryElement::eByControlPoint: switch (leUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: uv = leUV->GetDirectArray().GetAt(lControlPointIndex); break; case FbxGeometryElement::eIndexToDirect: { int id = leUV->GetIndexArray().GetAt(lControlPointIndex); uv = leUV->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } break; case FbxGeometryElement::eByPolygonVertex: { int lTextureUVIndex = pMesh->GetTextureUVIndex(i, j); switch (leUV->GetReferenceMode()) { case FbxGeometryElement::eDirect: case FbxGeometryElement::eIndexToDirect: { uv = leUV->GetDirectArray().GetAt(lTextureUVIndex); } break; default: break; // other reference modes not shown here! } } break; case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs case FbxGeometryElement::eAllSame: // doesn't make much sense for UVs case FbxGeometryElement::eNone: // doesn't make much sense for UVs break; } auto& texcoord = kMesh.m_kTexcoords[k][u32Index]; texcoord.x = (float)uv[0]; texcoord.y = (float)uv[1]; } for (int k(0); k < (int)(kMesh.m_kNormals.size()); ++k) { FbxVector4 n; FbxGeometryElementNormal* leNormal = pMesh->GetElementNormal(k); if (leNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { switch (leNormal->GetReferenceMode()) { case FbxGeometryElement::eDirect: n = leNormal->GetDirectArray().GetAt(u32Index); break; case FbxGeometryElement::eIndexToDirect: { int id = leNormal->GetIndexArray().GetAt(u32Index); n = leNormal->GetDirectArray().GetAt(id); } break; default: break; // other reference modes not shown here! } } auto& normal = kMesh.m_kNormals[k][u32Index]; normal.x = (float)n[0]; normal.y = (float)n[1]; normal.z = (float)n[2]; } if (element_mat >= 0) { FbxGeometryElementMaterial* lMaterialElement = pMesh->GetElementMaterial(element_mat); FbxSurfaceMaterial* lMaterial = NULL; int lMatId = -1; lMaterial = pMesh->GetNode()->GetMaterial(lMaterialElement->GetIndexArray().GetAt(i)); lMatId = lMaterialElement->GetIndexArray().GetAt(i); kMesh.m_kAttributes[i] = lMatId; } } } kMesh.Process(); kMesh.Save(spDest); }