Modify FBX2glTF to allow that several nodes share the same mesh. (#46)
This commit is contained in:
parent
f61814f7c9
commit
fada9e45ee
|
@ -607,8 +607,25 @@ 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<FbxVector4> normalLayer(pMesh->GetElementNormal(), pMesh->GetElementNormalCount());
|
||||
|
@ -688,7 +705,7 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
|
|||
const std::shared_ptr<FbxMaterialAccess> fbxMaterial = materials.GetMaterial(polygonIndex);
|
||||
|
||||
int textures[RAW_TEXTURE_USAGE_MAX];
|
||||
std::fill_n(textures, RAW_TEXTURE_USAGE_MAX, -1);
|
||||
std::fill_n(textures, (int)RAW_TEXTURE_USAGE_MAX, -1);
|
||||
|
||||
FbxString shadingModel, materialName;
|
||||
FbxVector4 ambient, specular, diffuse, emissive;
|
||||
|
|
111
src/Raw2Gltf.cpp
111
src/Raw2Gltf.cpp
|
@ -231,6 +231,15 @@ T &require(std::map<std::string, std::shared_ptr<T>> map, std::string key)
|
|||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T &require(std::map<long, std::shared_ptr<T>> map, long key)
|
||||
{
|
||||
auto iter = map.find(key);
|
||||
assert(iter != map.end());
|
||||
T &result = *iter->second;
|
||||
return result;
|
||||
}
|
||||
|
||||
static const std::vector<TriangleIndex> getIndexArray(const RawModel &raw)
|
||||
{
|
||||
std::vector<TriangleIndex> result;
|
||||
|
@ -284,7 +293,7 @@ ModelData *Raw2Gltf(
|
|||
|
||||
std::map<std::string, std::shared_ptr<NodeData>> nodesByName;
|
||||
std::map<std::string, std::shared_ptr<MaterialData>> materialsByName;
|
||||
std::map<std::string, std::shared_ptr<MeshData>> meshByNodeName;
|
||||
std::map<long, std::shared_ptr<MeshData>> meshBySurfaceId;
|
||||
|
||||
// for now, we only have one buffer; data->binary points to the same vector as that BufferData does.
|
||||
BufferData &buffer = *gltf->buffers.hold(
|
||||
|
@ -461,17 +470,6 @@ 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];
|
||||
|
||||
|
@ -481,50 +479,25 @@ ModelData *Raw2Gltf(
|
|||
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);
|
||||
int surfaceId = rawSurface.id;
|
||||
//NodeData &meshNode = require(nodesByName, nodeName);
|
||||
|
||||
MeshData *mesh = nullptr;
|
||||
auto meshIter = meshByNodeName.find(nodeName);
|
||||
if (meshIter != meshByNodeName.end()) {
|
||||
auto meshIter = meshBySurfaceId.find(surfaceId);
|
||||
if (meshIter != meshBySurfaceId.end()) {
|
||||
mesh = meshIter->second.get();
|
||||
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
std::vector<float> defaultDeforms;
|
||||
for (const auto &channel : rawSurface.blendChannels) {
|
||||
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<Mat4f> inverseBindMatrices;
|
||||
for (const auto &inverseBindMatrice : rawSurface.inverseBindMatrices) {
|
||||
inverseBindMatrices.push_back(inverseBindMatrice.Transpose());
|
||||
}
|
||||
|
||||
std::vector<uint32_t> 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<PrimitiveData> primitive;
|
||||
if (options.useDraco) {
|
||||
int triangleCount = surfaceModel.GetTriangleCount();
|
||||
|
@ -544,7 +517,8 @@ ModelData *Raw2Gltf(
|
|||
AccessorData &indexes = *gltf->accessors.hold(new AccessorData(GLT_USHORT));
|
||||
indexes.count = 3 * triangleCount;
|
||||
primitive.reset(new PrimitiveData(indexes, mData, dracoMesh));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
const AccessorData &indexes = *gltf->AddAccessorWithView(
|
||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ELEMENT_ARRAY_BUFFER),
|
||||
GLT_USHORT, getIndexArray(surfaceModel));
|
||||
|
@ -665,6 +639,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<Mat4f> inverseBindMatrices;
|
||||
for (const auto &inverseBindMatrice : rawSurface.inverseBindMatrices) {
|
||||
inverseBindMatrices.push_back(inverseBindMatrice.Transpose());
|
||||
}
|
||||
|
||||
std::vector<uint32_t> 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
|
||||
//
|
||||
|
|
|
@ -180,18 +180,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;
|
||||
|
||||
|
@ -263,6 +263,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);
|
||||
|
@ -281,7 +282,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;
|
||||
}
|
||||
|
@ -538,3 +539,14 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -182,8 +182,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<float, 3> bounds;
|
||||
std::vector<std::string> jointNames;
|
||||
|
@ -248,6 +248,7 @@ struct RawNode
|
|||
Vec3f translation;
|
||||
Quatf rotation;
|
||||
Vec3f scale;
|
||||
long surfaceId;
|
||||
};
|
||||
|
||||
class RawModel
|
||||
|
@ -267,7 +268,7 @@ public:
|
|||
Vec4f diffuseFactor, Vec3f specularFactor,
|
||||
Vec3f emissiveFactor, float shinineness);
|
||||
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,
|
||||
|
@ -307,6 +308,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(); }
|
||||
|
|
Loading…
Reference in New Issue