Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify FBX2glTF to allow that several nodes share the same mesh. #46

Merged
merged 1 commit into from
Nov 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/Fbx2Raw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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;
Expand Down
113 changes: 67 additions & 46 deletions src/Raw2Gltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should make this available in a common header file...

static const std::vector<TriangleIndex> getIndexArray(const RawModel &raw)
{
std::vector<TriangleIndex> result;
Expand Down Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you fix up the indentation here (and anywhere else)?


// for now, we only have one buffer; data->binary points to the same vector as that BufferData does.
BufferData &buffer = *gltf->buffers.hold(
Expand Down Expand Up @@ -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];

Expand All @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not leave commented-out code -- just nuke the line.


MeshData *mesh = nullptr;
auto meshIter = meshByNodeName.find(nodeName);
if (meshIter != meshByNodeName.end()) {
MeshData *mesh = nullptr;
auto meshIter = meshBySurfaceId.find(surfaceId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

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();
Expand All @@ -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));
Expand Down Expand Up @@ -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
//
Expand Down
20 changes: 16 additions & 4 deletions src/RawModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

6 changes: 4 additions & 2 deletions src/RawModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -248,6 +248,7 @@ struct RawNode
Vec3f translation;
Quatf rotation;
Vec3f scale;
long surfaceId;
};

class RawModel
Expand All @@ -267,7 +268,7 @@ class RawModel
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,
Expand Down Expand Up @@ -307,6 +308,7 @@ class RawModel
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(); }
Expand Down