diff --git a/src/Fbx2Raw.cpp b/src/Fbx2Raw.cpp index 7a8bdfd..a7d5847 100644 --- a/src/Fbx2Raw.cpp +++ b/src/Fbx2Raw.cpp @@ -691,8 +691,23 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std: meshConverter.Triangulate(pNode->GetNodeAttribute(), true); FbxMesh *pMesh = pNode->GetMesh(); + // Obtains the surface Id + const long surfaceId = pMesh->GetUniqueID(); + + // Associate the node to this surface + int nodeId = raw.GetNodeByName(pNode->GetName()); + if (nodeId >= 0) { + RawNode &node = raw.GetNode(nodeId); + node.surfaceId = surfaceId; + } + + if (raw.GetSurfaceById(surfaceId) >= 0) { + // This surface is already loaded + return; + } + const char *meshName = (pNode->GetName()[0] != '\0') ? pNode->GetName() : pMesh->GetName(); - const int rawSurfaceIndex = raw.AddSurface(meshName, pNode->GetName()); + const int rawSurfaceIndex = raw.AddSurface(meshName, surfaceId); const FbxVector4 *controlPoints = pMesh->GetControlPoints(); const FbxLayerElementAccess normalLayer(pMesh->GetElementNormal(), pMesh->GetElementNormalCount()); @@ -771,9 +786,10 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std: const std::shared_ptr fbxMaterial = materials.GetMaterial(polygonIndex); int textures[RAW_TEXTURE_USAGE_MAX]; - std::fill_n(textures, RAW_TEXTURE_USAGE_MAX, -1); - FbxString materialName; + std::fill_n(textures, (int) RAW_TEXTURE_USAGE_MAX, -1); + std::shared_ptr rawMatProps; + FbxString materialName; if (fbxMaterial == nullptr) { materialName = "DefaultMaterial"; diff --git a/src/Raw2Gltf.cpp b/src/Raw2Gltf.cpp index e0c730f..3860c95 100644 --- a/src/Raw2Gltf.cpp +++ b/src/Raw2Gltf.cpp @@ -244,6 +244,15 @@ T &require(std::map> map, const std::string &key return result; } +template +T &require(std::map> map, long key) +{ + auto iter = map.find(key); + assert(iter != map.end()); + T &result = *iter->second; + return result; +} + static const std::vector getIndexArray(const RawModel &raw) { std::vector result; @@ -297,8 +306,8 @@ ModelData *Raw2Gltf( std::map> nodesByName; std::map> materialsByName; - std::map> meshByNodeName; std::map> textureByIndicesKey; + std::map> meshBySurfaceId; // for now, we only have one buffer; data->binary points to the same vector as that BufferData does. BufferData &buffer = *gltf->buffers.hold( @@ -883,32 +892,20 @@ ModelData *Raw2Gltf( materialsByName[materialHash(material)] = mData; } - // - // surfaces - // - - // in GLTF 2.0, the structural limitation is that a node can - // only belong to a single mesh. A mesh can however contain any - // number of primitives, which are essentially little meshes. - // - // so each RawSurface turns into a primitive, and we sort them - // by root node using this map; one mesh per node. - for (size_t surfaceIndex = 0; surfaceIndex < materialModels.size(); surfaceIndex++) { const RawModel &surfaceModel = materialModels[surfaceIndex]; assert(surfaceModel.GetSurfaceCount() == 1); const RawSurface &rawSurface = surfaceModel.GetSurface(0); + const int surfaceId = rawSurface.id; const RawMaterial &rawMaterial = surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex); const MaterialData &mData = require(materialsByName, materialHash(rawMaterial)); - std::string nodeName = rawSurface.nodeName; - NodeData &meshNode = require(nodesByName, nodeName); - MeshData *mesh = nullptr; - auto meshIter = meshByNodeName.find(nodeName); - if (meshIter != meshByNodeName.end()) { + MeshData *mesh = nullptr; + auto meshIter = meshBySurfaceId.find(surfaceId); + if (meshIter != meshBySurfaceId.end()) { mesh = meshIter->second.get(); } else { @@ -917,36 +914,10 @@ ModelData *Raw2Gltf( defaultDeforms.push_back(channel.defaultDeform); } auto meshPtr = gltf->meshes.hold(new MeshData(rawSurface.name, defaultDeforms)); - meshByNodeName[nodeName] = meshPtr; - meshNode.SetMesh(meshPtr->ix); + meshBySurfaceId[surfaceId] = meshPtr; mesh = meshPtr.get(); } - // - // surface skin - // - if (!rawSurface.jointNames.empty()) { - if (meshNode.skin == -1) { - // glTF uses column-major matrices - std::vector inverseBindMatrices; - for (const auto &inverseBindMatrice : rawSurface.inverseBindMatrices) { - inverseBindMatrices.push_back(inverseBindMatrice.Transpose()); - } - - std::vector jointIndexes; - for (const auto &jointName : rawSurface.jointNames) { - jointIndexes.push_back(require(nodesByName, jointName).ix); - } - - // Write out inverseBindMatrices - auto accIBM = gltf->AddAccessorAndView(buffer, GLT_MAT4F, inverseBindMatrices); - - auto skeletonRoot = require(nodesByName, rawSurface.skeletonRootName); - auto skin = *gltf->skins.hold(new SkinData(jointIndexes, *accIBM, skeletonRoot)); - meshNode.SetSkin(skin.ix); - } - } - std::shared_ptr primitive; if (options.useDraco) { int triangleCount = surfaceModel.GetTriangleCount(); @@ -1087,6 +1058,53 @@ ModelData *Raw2Gltf( mesh->AddPrimitive(primitive); } + // + // Assign meshes to node + // + + for (int i = 0; i < raw.GetNodeCount(); i++) { + + const RawNode &node = raw.GetNode(i); + auto nodeData = gltf->nodes.ptrs[i]; + + // + // Assign mesh to node + // + if (node.surfaceId > 0) + { + int surfaceIndex = raw.GetSurfaceById(node.surfaceId); + const RawSurface &rawSurface = raw.GetSurface(surfaceIndex); + + MeshData &meshData = require(meshBySurfaceId, rawSurface.id); + nodeData->SetMesh(meshData.ix); + + // + // surface skin + // + if (!rawSurface.jointNames.empty()) { + if (nodeData->skin == -1) { + // glTF uses column-major matrices + std::vector inverseBindMatrices; + for (const auto &inverseBindMatrice : rawSurface.inverseBindMatrices) { + inverseBindMatrices.push_back(inverseBindMatrice.Transpose()); + } + + std::vector jointIndexes; + for (const auto &jointName : rawSurface.jointNames) { + jointIndexes.push_back(require(nodesByName, jointName).ix); + } + + // Write out inverseBindMatrices + auto accIBM = gltf->AddAccessorAndView(buffer, GLT_MAT4F, inverseBindMatrices); + + auto skeletonRoot = require(nodesByName, rawSurface.skeletonRootName); + auto skin = *gltf->skins.hold(new SkinData(jointIndexes, *accIBM, skeletonRoot)); + nodeData->SetSkin(skin.ix); + } + } + } + } + // // cameras // diff --git a/src/RawModel.cpp b/src/RawModel.cpp index 840e137..712c799 100644 --- a/src/RawModel.cpp +++ b/src/RawModel.cpp @@ -165,18 +165,18 @@ int RawModel::AddSurface(const RawSurface &surface) return (int) (surfaces.size() - 1); } -int RawModel::AddSurface(const char *name, const char *nodeName) +int RawModel::AddSurface(const char *name, const long surfaceId) { assert(name[0] != '\0'); for (size_t i = 0; i < surfaces.size(); i++) { - if (Gltf::StringUtils::CompareNoCase(surfaces[i].name, name) == 0) { + if (surfaces[i].id == surfaceId) { return (int) i; } } RawSurface surface; + surface.id = surfaceId; surface.name = name; - surface.nodeName = nodeName; surface.bounds.Clear(); surface.discrete = false; @@ -248,6 +248,7 @@ int RawModel::AddNode(const char *name, const char *parentName) joint.isJoint = false; joint.name = name; joint.parentName = parentName; + joint.surfaceId = 0; joint.translation = Vec3f(0, 0, 0); joint.rotation = Quatf(0, 0, 0, 1); joint.scale = Vec3f(1, 1, 1); @@ -266,7 +267,7 @@ void RawModel::Condense() for (auto &triangle : triangles) { const RawSurface &surface = oldSurfaces[triangle.surfaceIndex]; - const int surfaceIndex = AddSurface(surface.name.c_str(), surface.nodeName.c_str()); + const int surfaceIndex = AddSurface(surface.name.c_str(), surface.id); surfaces[surfaceIndex] = surface; triangle.surfaceIndex = surfaceIndex; } @@ -523,3 +524,13 @@ int RawModel::GetNodeByName(const char *name) const } return -1; } + +int RawModel::GetSurfaceById(const long surfaceId) const +{ + for (size_t i = 0; i < surfaces.size(); i++) { + if (surfaces[i].id == surfaceId) { + return (int)i; + } + } + return -1; +} diff --git a/src/RawModel.h b/src/RawModel.h index e402008..f729b6f 100644 --- a/src/RawModel.h +++ b/src/RawModel.h @@ -275,8 +275,8 @@ struct RawBlendChannel struct RawSurface { + long id; std::string name; // The name of this surface - std::string nodeName; // The node that links to this surface. std::string skeletonRootName; // The name of the root of the skeleton. Bounds bounds; std::vector jointNames; @@ -341,6 +341,7 @@ struct RawNode Vec3f translation; Quatf rotation; Vec3f scale; + long surfaceId; }; class RawModel @@ -358,7 +359,7 @@ public: const char *name, const RawMaterialType materialType, const int textures[RAW_TEXTURE_USAGE_MAX], std::shared_ptr materialInfo); int AddSurface(const RawSurface &suface); - int AddSurface(const char *name, const char *nodeName); + int AddSurface(const char *name, long surfaceId); int AddAnimation(const RawAnimation &animation); int AddCameraPerspective( const char *name, const char *nodeName, const float aspectRatio, const float fovDegreesX, const float fovDegreesY, @@ -398,6 +399,7 @@ public: int GetSurfaceCount() const { return (int) surfaces.size(); } const RawSurface &GetSurface(const int index) const { return surfaces[index]; } RawSurface &GetSurface(const int index) { return surfaces[index]; } + int GetSurfaceById(const long id) const; // Iterate over the animations. int GetAnimationCount() const { return (int) animations.size(); }