Fix duplicate name issues (#51)

Fix the naming issues. Now the nodes are identified by pNode->GetUniqueID(), instead of its name. All dictionaries and references to nodes are replaced by its id, instead of its name.
This commit is contained in:
David Ávila 2017-12-06 19:43:18 +01:00 committed by Pär Winzell
parent 13367dfc66
commit a2d5c7d87b
4 changed files with 68 additions and 65 deletions

View File

@ -424,7 +424,7 @@ public:
inverseBindMatrices.emplace_back(globalBindposeInverseMatrix); inverseBindMatrices.emplace_back(globalBindposeInverseMatrix);
jointNodes.push_back(cluster->GetLink()); jointNodes.push_back(cluster->GetLink());
jointNames.push_back(*cluster->GetLink()->GetName() != '\0' ? cluster->GetLink()->GetName() : cluster->GetName()); jointIds.push_back(cluster->GetLink()->GetUniqueID());
const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform(); const FbxAMatrix globalNodeTransform = cluster->GetLink()->EvaluateGlobalTransform();
jointSkinningTransforms.push_back(FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix)); jointSkinningTransforms.push_back(FbxMatrix(globalNodeTransform * globalBindposeInverseMatrix));
@ -486,9 +486,9 @@ public:
return jointNodes[jointIndex]; return jointNodes[jointIndex];
} }
const char *GetJointName(const int jointIndex) const const long GetJointId(const int jointIndex) const
{ {
return jointNames[jointIndex].c_str(); return jointIds[jointIndex];
} }
const FbxMatrix &GetJointSkinningTransform(const int jointIndex) const const FbxMatrix &GetJointSkinningTransform(const int jointIndex) const
@ -501,10 +501,10 @@ public:
return jointInverseGlobalTransforms[jointIndex]; return jointInverseGlobalTransforms[jointIndex];
} }
const char *GetRootNode() const const long GetRootNode() const
{ {
assert(rootIndex != -1); assert(rootIndex != -1);
return jointNames[rootIndex].c_str(); return jointIds[rootIndex];
} }
const FbxAMatrix &GetInverseBindMatrix(const int jointIndex) const const FbxAMatrix &GetInverseBindMatrix(const int jointIndex) const
@ -526,7 +526,7 @@ public:
private: private:
int rootIndex; int rootIndex;
std::vector<std::string> jointNames; std::vector<long> jointIds;
std::vector<FbxNode *> jointNodes; std::vector<FbxNode *> jointNodes;
std::vector<FbxMatrix> jointSkinningTransforms; std::vector<FbxMatrix> jointSkinningTransforms;
std::vector<FbxMatrix> jointInverseGlobalTransforms; std::vector<FbxMatrix> jointInverseGlobalTransforms;
@ -697,7 +697,7 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
const long surfaceId = pMesh->GetUniqueID(); const long surfaceId = pMesh->GetUniqueID();
// Associate the node to this surface // Associate the node to this surface
int nodeId = raw.GetNodeByName(pNode->GetName()); int nodeId = raw.GetNodeById(pNode->GetUniqueID());
if (nodeId >= 0) { if (nodeId >= 0) {
RawNode &node = raw.GetNode(nodeId); RawNode &node = raw.GetNode(nodeId);
node.surfaceId = surfaceId; node.surfaceId = surfaceId;
@ -725,7 +725,7 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
if (verboseOutput) { if (verboseOutput) {
fmt::printf( fmt::printf(
"mesh %d: %s (skinned: %s)\n", rawSurfaceIndex, meshName, "mesh %d: %s (skinned: %s)\n", rawSurfaceIndex, meshName,
skinning.IsSkinned() ? skinning.GetRootNode() : "NO"); skinning.IsSkinned() ? raw.GetNode(raw.GetNodeById(skinning.GetRootNode())).name.c_str() : "NO");
} }
// The FbxNode geometric transformation describes how a FbxNodeAttribute is offset from // The FbxNode geometric transformation describes how a FbxNodeAttribute is offset from
@ -758,12 +758,12 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
RawSurface &rawSurface = raw.GetSurface(rawSurfaceIndex); RawSurface &rawSurface = raw.GetSurface(rawSurfaceIndex);
rawSurface.skeletonRootName = (skinning.IsSkinned()) ? skinning.GetRootNode() : pNode->GetName(); rawSurface.skeletonRootId = (skinning.IsSkinned()) ? skinning.GetRootNode() : pNode->GetUniqueID();
for (int jointIndex = 0; jointIndex < skinning.GetNodeCount(); jointIndex++) { for (int jointIndex = 0; jointIndex < skinning.GetNodeCount(); jointIndex++) {
const char *jointName = skinning.GetJointName(jointIndex); const long jointId = skinning.GetJointId(jointIndex);
raw.GetNode(raw.GetNodeByName(jointName)).isJoint = true; raw.GetNode(raw.GetNodeById(jointId)).isJoint = true;
rawSurface.jointNames.emplace_back(jointName); rawSurface.jointIds.emplace_back(jointId);
rawSurface.inverseBindMatrices.push_back(toMat4f(skinning.GetInverseBindMatrix(jointIndex))); rawSurface.inverseBindMatrices.push_back(toMat4f(skinning.GetInverseBindMatrix(jointIndex)));
rawSurface.jointGeometryMins.emplace_back(FLT_MAX, FLT_MAX, FLT_MAX); rawSurface.jointGeometryMins.emplace_back(FLT_MAX, FLT_MAX, FLT_MAX);
rawSurface.jointGeometryMaxs.emplace_back(-FLT_MAX, -FLT_MAX, -FLT_MAX); rawSurface.jointGeometryMaxs.emplace_back(-FLT_MAX, -FLT_MAX, -FLT_MAX);
@ -988,12 +988,12 @@ static void ReadCamera(RawModel &raw, FbxScene *pScene, FbxNode *pNode)
const FbxCamera *pCamera = pNode->GetCamera(); const FbxCamera *pCamera = pNode->GetCamera();
if (pCamera->ProjectionType.Get() == FbxCamera::EProjectionType::ePerspective) { if (pCamera->ProjectionType.Get() == FbxCamera::EProjectionType::ePerspective) {
raw.AddCameraPerspective( raw.AddCameraPerspective(
"", pNode->GetName(), (float) pCamera->FilmAspectRatio, "", pNode->GetUniqueID(), (float) pCamera->FilmAspectRatio,
(float) pCamera->FieldOfViewX, (float) pCamera->FieldOfViewX, (float) pCamera->FieldOfViewX, (float) pCamera->FieldOfViewX,
(float) pCamera->NearPlane, (float) pCamera->FarPlane); (float) pCamera->NearPlane, (float) pCamera->FarPlane);
} else { } else {
raw.AddCameraOrthographic( raw.AddCameraOrthographic(
"", pNode->GetName(), "", pNode->GetUniqueID(),
(float) pCamera->OrthoZoom, (float) pCamera->OrthoZoom, (float) pCamera->OrthoZoom, (float) pCamera->OrthoZoom,
(float) pCamera->FarPlane, (float) pCamera->NearPlane); (float) pCamera->FarPlane, (float) pCamera->NearPlane);
} }
@ -1069,10 +1069,11 @@ static FbxVector4 computeLocalScale(FbxNode *pNode, FbxTime pTime = FBXSDK_TIME_
static void ReadNodeHierarchy( static void ReadNodeHierarchy(
RawModel &raw, FbxScene *pScene, FbxNode *pNode, RawModel &raw, FbxScene *pScene, FbxNode *pNode,
const std::string &parentName, const std::string &path) const long parentId, const std::string &path)
{ {
const FbxUInt64 nodeId = pNode->GetUniqueID();
const char *nodeName = pNode->GetName(); const char *nodeName = pNode->GetName();
const int nodeIndex = raw.AddNode(nodeName, parentName.c_str()); const int nodeIndex = raw.AddNode(nodeId, nodeName, parentId);
RawNode &node = raw.GetNode(nodeIndex); RawNode &node = raw.GetNode(nodeIndex);
FbxTransform::EInheritType lInheritType; FbxTransform::EInheritType lInheritType;
@ -1085,7 +1086,7 @@ static void ReadNodeHierarchy(
static int warnRrSsCount = 0; static int warnRrSsCount = 0;
static int warnRrsCount = 0; static int warnRrsCount = 0;
if (lInheritType == FbxTransform::eInheritRrSs && !parentName.empty()) { if (lInheritType == FbxTransform::eInheritRrSs && parentId) {
if (++warnRrSsCount == 1) { if (++warnRrSsCount == 1) {
fmt::printf("Warning: node %s uses unsupported transform inheritance type 'eInheritRrSs'.\n", newPath); fmt::printf("Warning: node %s uses unsupported transform inheritance type 'eInheritRrSs'.\n", newPath);
fmt::printf(" (Further warnings of this type squelched.)\n"); fmt::printf(" (Further warnings of this type squelched.)\n");
@ -1112,19 +1113,19 @@ static void ReadNodeHierarchy(
node.rotation = toQuatf(localRotation); node.rotation = toQuatf(localRotation);
node.scale = toVec3f(localScaling); node.scale = toVec3f(localScaling);
if (parentName.size() > 0) { if (parentId) {
RawNode &parentNode = raw.GetNode(raw.GetNodeByName(parentName.c_str())); RawNode &parentNode = raw.GetNode(raw.GetNodeById(parentId));
// Add unique child name to the parent node. // Add unique child name to the parent node.
if (std::find(parentNode.childNames.begin(), parentNode.childNames.end(), nodeName) == parentNode.childNames.end()) { if (std::find(parentNode.childIds.begin(), parentNode.childIds.end(), nodeId) == parentNode.childIds.end()) {
parentNode.childNames.push_back(nodeName); parentNode.childIds.push_back(nodeId);
} }
} else { } else {
// If there is no parent then this is the root node. // If there is no parent then this is the root node.
raw.SetRootNode(nodeName); raw.SetRootNode(nodeId);
} }
for (int child = 0; child < pNode->GetChildCount(); child++) { for (int child = 0; child < pNode->GetChildCount(); child++) {
ReadNodeHierarchy(raw, pScene, pNode->GetChild(child), nodeName, newPath); ReadNodeHierarchy(raw, pScene, pNode->GetChild(child), nodeId, newPath);
} }
} }
@ -1180,7 +1181,7 @@ static void ReadAnimations(RawModel &raw, FbxScene *pScene)
bool hasMorphs = false; bool hasMorphs = false;
RawChannel channel; RawChannel channel;
channel.nodeIndex = raw.GetNodeByName(pNode->GetName()); channel.nodeIndex = raw.GetNodeById(pNode->GetUniqueID());
for (FbxLongLong frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; frameIndex++) { for (FbxLongLong frameIndex = firstFrameIndex; frameIndex <= lastFrameIndex; frameIndex++) {
FbxTime pTime; FbxTime pTime;
@ -1423,7 +1424,7 @@ bool LoadFBXFile(RawModel &raw, const char *fbxFileName, const char *textureExte
FbxSystemUnit::m.ConvertScene(pScene); FbxSystemUnit::m.ConvertScene(pScene);
} }
ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), "", ""); ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), 0, "");
ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations); ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations);
ReadAnimations(raw, pScene); ReadAnimations(raw, pScene);

View File

@ -304,7 +304,7 @@ ModelData *Raw2Gltf(
std::unique_ptr<GLTFData> gltf(new GLTFData(options.outputBinary)); std::unique_ptr<GLTFData> gltf(new GLTFData(options.outputBinary));
std::map<std::string, std::shared_ptr<NodeData>> nodesByName; std::map<long, std::shared_ptr<NodeData>> nodesById;
std::map<std::string, std::shared_ptr<MaterialData>> materialsByName; std::map<std::string, std::shared_ptr<MaterialData>> materialsByName;
std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey; std::map<std::string, std::shared_ptr<TextureData>> textureByIndicesKey;
std::map<long, std::shared_ptr<MeshData>> meshBySurfaceId; std::map<long, std::shared_ptr<MeshData>> meshBySurfaceId;
@ -326,13 +326,13 @@ ModelData *Raw2Gltf(
auto nodeData = gltf->nodes.hold( auto nodeData = gltf->nodes.hold(
new NodeData(node.name, node.translation, node.rotation, node.scale, node.isJoint)); new NodeData(node.name, node.translation, node.rotation, node.scale, node.isJoint));
for (const auto &childName : node.childNames) { for (const auto &childId : node.childIds) {
int childIx = raw.GetNodeByName(childName.c_str()); int childIx = raw.GetNodeById(childId);
assert(childIx >= 0); assert(childIx >= 0);
nodeData->AddChildNode(childIx); nodeData->AddChildNode(childIx);
} }
assert(nodesByName.find(nodeData->name) == nodesByName.end());
nodesByName.insert(std::make_pair(nodeData->name, nodeData)); nodesById.insert(std::make_pair(node.id, nodeData));
} }
// //
@ -367,7 +367,7 @@ ModelData *Raw2Gltf(
channel.scales.size(), channel.weights.size()); channel.scales.size(), channel.weights.size());
} }
NodeData &nDat = require(nodesByName, node.name); NodeData &nDat = require(nodesById, node.id);
if (!channel.translations.empty()) { if (!channel.translations.empty()) {
aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.translations), "translation"); aDat.AddNodeChannel(nDat, *gltf->AddAccessorAndView(buffer, GLT_VEC3F, channel.translations), "translation");
} }
@ -1081,7 +1081,7 @@ ModelData *Raw2Gltf(
// //
// surface skin // surface skin
// //
if (!rawSurface.jointNames.empty()) { if (!rawSurface.jointIds.empty()) {
if (nodeData->skin == -1) { if (nodeData->skin == -1) {
// glTF uses column-major matrices // glTF uses column-major matrices
std::vector<Mat4f> inverseBindMatrices; std::vector<Mat4f> inverseBindMatrices;
@ -1090,14 +1090,14 @@ ModelData *Raw2Gltf(
} }
std::vector<uint32_t> jointIndexes; std::vector<uint32_t> jointIndexes;
for (const auto &jointName : rawSurface.jointNames) { for (const auto &jointId : rawSurface.jointIds) {
jointIndexes.push_back(require(nodesByName, jointName).ix); jointIndexes.push_back(require(nodesById, jointId).ix);
} }
// Write out inverseBindMatrices // Write out inverseBindMatrices
auto accIBM = gltf->AddAccessorAndView(buffer, GLT_MAT4F, inverseBindMatrices); auto accIBM = gltf->AddAccessorAndView(buffer, GLT_MAT4F, inverseBindMatrices);
auto skeletonRoot = require(nodesByName, rawSurface.skeletonRootName); auto skeletonRoot = require(nodesById, rawSurface.skeletonRootId);
auto skin = *gltf->skins.hold(new SkinData(jointIndexes, *accIBM, skeletonRoot)); auto skin = *gltf->skins.hold(new SkinData(jointIndexes, *accIBM, skeletonRoot));
nodeData->SetSkin(skin.ix); nodeData->SetSkin(skin.ix);
} }
@ -1129,16 +1129,16 @@ ModelData *Raw2Gltf(
} }
// Add the camera to the node hierarchy. // Add the camera to the node hierarchy.
auto iter = nodesByName.find(cam.nodeName); auto iter = nodesById.find(cam.nodeId);
if (iter == nodesByName.end()) { if (iter == nodesById.end()) {
fmt::printf("Warning: Camera node name %s does not exist.\n", cam.nodeName); fmt::printf("Warning: Camera node id %s does not exist.\n", cam.nodeId);
continue; continue;
} }
iter->second->SetCamera(camera.ix); iter->second->SetCamera(camera.ix);
} }
} }
NodeData &rootNode = require(nodesByName, "RootNode"); NodeData &rootNode = require(nodesById, raw.GetRootNode());
const SceneData &rootScene = *gltf->scenes.hold(new SceneData(defaultSceneName, rootNode)); const SceneData &rootScene = *gltf->scenes.hold(new SceneData(defaultSceneName, rootNode));
if (options.outputBinary) { if (options.outputBinary) {

View File

@ -193,7 +193,7 @@ int RawModel::AddAnimation(const RawAnimation &animation)
int RawModel::AddNode(const RawNode &node) int RawModel::AddNode(const RawNode &node)
{ {
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
if (Gltf::StringUtils::CompareNoCase(nodes[i].name.c_str(), node.name) == 0) { if (nodes[i].id == node.id) {
return (int)i; return (int)i;
} }
} }
@ -203,12 +203,12 @@ int RawModel::AddNode(const RawNode &node)
} }
int RawModel::AddCameraPerspective( int RawModel::AddCameraPerspective(
const char *name, const char *nodeName, const float aspectRatio, const float fovDegreesX, const float fovDegreesY, const float nearZ, const char *name, const long nodeId, const float aspectRatio, const float fovDegreesX, const float fovDegreesY, const float nearZ,
const float farZ) const float farZ)
{ {
RawCamera camera; RawCamera camera;
camera.name = name; camera.name = name;
camera.nodeName = nodeName; camera.nodeId = nodeId;
camera.mode = RawCamera::CAMERA_MODE_PERSPECTIVE; camera.mode = RawCamera::CAMERA_MODE_PERSPECTIVE;
camera.perspective.aspectRatio = aspectRatio; camera.perspective.aspectRatio = aspectRatio;
camera.perspective.fovDegreesX = fovDegreesX; camera.perspective.fovDegreesX = fovDegreesX;
@ -220,11 +220,11 @@ int RawModel::AddCameraPerspective(
} }
int RawModel::AddCameraOrthographic( int RawModel::AddCameraOrthographic(
const char *name, const char *nodeName, const float magX, const float magY, const float nearZ, const float farZ) const char *name, const long nodeId, const float magX, const float magY, const float nearZ, const float farZ)
{ {
RawCamera camera; RawCamera camera;
camera.name = name; camera.name = name;
camera.nodeName = nodeName; camera.nodeId = nodeId;
camera.mode = RawCamera::CAMERA_MODE_ORTHOGRAPHIC; camera.mode = RawCamera::CAMERA_MODE_ORTHOGRAPHIC;
camera.orthographic.magX = magX; camera.orthographic.magX = magX;
camera.orthographic.magY = magY; camera.orthographic.magY = magY;
@ -234,20 +234,21 @@ int RawModel::AddCameraOrthographic(
return (int) cameras.size() - 1; return (int) cameras.size() - 1;
} }
int RawModel::AddNode(const char *name, const char *parentName) int RawModel::AddNode(const long id, const char *name, const long parentId)
{ {
assert(name[0] != '\0'); assert(name[0] != '\0');
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
if (Gltf::StringUtils::CompareNoCase(nodes[i].name, name) == 0) { if (nodes[i].id == id ) {
return (int) i; return (int) i;
} }
} }
RawNode joint; RawNode joint;
joint.isJoint = false; joint.isJoint = false;
joint.id = id;
joint.name = name; joint.name = name;
joint.parentName = parentName; joint.parentId = parentId;
joint.surfaceId = 0; joint.surfaceId = 0;
joint.translation = Vec3f(0, 0, 0); joint.translation = Vec3f(0, 0, 0);
joint.rotation = Quatf(0, 0, 0, 1); joint.rotation = Quatf(0, 0, 0, 1);
@ -455,9 +456,9 @@ void RawModel::CreateMaterialModels(
RawSurface &rawSurface = model->GetSurface(surfaceIndex); RawSurface &rawSurface = model->GetSurface(surfaceIndex);
if (model->GetSurfaceCount() > prevSurfaceCount) { if (model->GetSurfaceCount() > prevSurfaceCount) {
const std::vector<std::string> &jointNames = surfaces[sortedTriangles[i].surfaceIndex].jointNames; const std::vector<long> &jointIds = surfaces[sortedTriangles[i].surfaceIndex].jointIds;
for (const auto &jointName : jointNames) { for (const auto &jointId : jointIds) {
const int nodeIndex = GetNodeByName(jointName.c_str()); const int nodeIndex = GetNodeById(jointId);
assert(nodeIndex != -1); assert(nodeIndex != -1);
model->AddNode(GetNode(nodeIndex)); model->AddNode(GetNode(nodeIndex));
} }
@ -515,10 +516,10 @@ void RawModel::CreateMaterialModels(
} }
} }
int RawModel::GetNodeByName(const char *name) const int RawModel::GetNodeById(const long nodeId) const
{ {
for (size_t i = 0; i < nodes.size(); i++) { for (size_t i = 0; i < nodes.size(); i++) {
if (nodes[i].name == name) { if (nodes[i].id == nodeId) {
return (int) i; return (int) i;
} }
} }

View File

@ -277,9 +277,9 @@ struct RawSurface
{ {
long id; long id;
std::string name; // The name of this surface std::string name; // The name of this surface
std::string skeletonRootName; // The name of the root of the skeleton. long skeletonRootId; // The id of the root node of the skeleton.
Bounds<float, 3> bounds; Bounds<float, 3> bounds;
std::vector<std::string> jointNames; std::vector<long> jointIds;
std::vector<Vec3f> jointGeometryMins; std::vector<Vec3f> jointGeometryMins;
std::vector<Vec3f> jointGeometryMaxs; std::vector<Vec3f> jointGeometryMaxs;
std::vector<Mat4f> inverseBindMatrices; std::vector<Mat4f> inverseBindMatrices;
@ -306,7 +306,7 @@ struct RawAnimation
struct RawCamera struct RawCamera
{ {
std::string name; std::string name;
std::string nodeName; long nodeId;
enum enum
{ {
@ -335,9 +335,10 @@ struct RawCamera
struct RawNode struct RawNode
{ {
bool isJoint; bool isJoint;
long id;
std::string name; std::string name;
std::string parentName; long parentId;
std::vector<std::string> childNames; std::vector<long> childIds;
Vec3f translation; Vec3f translation;
Quatf rotation; Quatf rotation;
Vec3f scale; Vec3f scale;
@ -362,14 +363,14 @@ public:
int AddSurface(const char *name, long surfaceId); int AddSurface(const char *name, long surfaceId);
int AddAnimation(const RawAnimation &animation); int AddAnimation(const RawAnimation &animation);
int AddCameraPerspective( int AddCameraPerspective(
const char *name, const char *nodeName, const float aspectRatio, const float fovDegreesX, const float fovDegreesY, const char *name, const long nodeId, const float aspectRatio, const float fovDegreesX, const float fovDegreesY,
const float nearZ, const float farZ); const float nearZ, const float farZ);
int int
AddCameraOrthographic(const char *name, const char *nodeName, const float magX, const float magY, const float nearZ, const float farZ); AddCameraOrthographic(const char *name, const long nodeId, const float magX, const float magY, const float nearZ, const float farZ);
int AddNode(const RawNode &node); int AddNode(const RawNode &node);
int AddNode(const char *name, const char *parentName); int AddNode(const long id, const char *name, const long parentId);
void SetRootNode(const char *name) { rootNodeName = name; } void SetRootNode(const long nodeId) { rootNodeId = nodeId; }
const char *GetRootNode() const { return rootNodeName.c_str(); } const long GetRootNode() const { return rootNodeId; }
// Remove unused vertices, textures or materials after removing vertex attributes, textures, materials or surfaces. // Remove unused vertices, textures or materials after removing vertex attributes, textures, materials or surfaces.
void Condense(); void Condense();
@ -413,7 +414,7 @@ public:
int GetNodeCount() const { return (int) nodes.size(); } int GetNodeCount() const { return (int) nodes.size(); }
const RawNode &GetNode(const int index) const { return nodes[index]; } const RawNode &GetNode(const int index) const { return nodes[index]; }
RawNode &GetNode(const int index) { return nodes[index]; } RawNode &GetNode(const int index) { return nodes[index]; }
int GetNodeByName(const char *name) const; int GetNodeById(const long nodeId) const;
// Create individual attribute arrays. // Create individual attribute arrays.
// Returns true if the vertices store the particular attribute. // Returns true if the vertices store the particular attribute.
@ -427,7 +428,7 @@ public:
std::vector<RawModel> &materialModels, const int maxModelVertices, const int keepAttribs, const bool forceDiscrete) const; std::vector<RawModel> &materialModels, const int maxModelVertices, const int keepAttribs, const bool forceDiscrete) const;
private: private:
std::string rootNodeName; long rootNodeId;
int vertexAttributes; int vertexAttributes;
std::unordered_map<RawVertex, int, VertexHasher> vertexHash; std::unordered_map<RawVertex, int, VertexHasher> vertexHash;
std::vector<RawVertex> vertices; std::vector<RawVertex> vertices;