Skip to content

Commit

Permalink
GLTF loader: few fixes/improvements to multiple scenes handling (#193)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed May 19, 2023
1 parent 58aa8f5 commit 274b800
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 41 deletions.
37 changes: 24 additions & 13 deletions AssetLoader/interface/GLTFBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct BufferInitData : ObjectBase<IObject>
return RefCntAutoPtr<BufferInitData>{MakeNewRCObj<BufferInitData>()()};
}

IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BufferInitData, ObjectBase);
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BufferInitData, ObjectBase)

std::vector<std::vector<Uint8>> Data;
};
Expand Down Expand Up @@ -103,17 +103,21 @@ class ModelBuilder

using ConvertedBufferViewMap = std::unordered_map<ConvertedBufferViewKey, ConvertedBufferViewData, ConvertedBufferViewKey::Hasher>;

// If SceneIndex >= 0, loads only the specified scene, otherwise loads all scenes.
// Stores the GLTF node indices as the node pointers.
template <typename GltfModelType>
void LoadScenes(const GltfModelType& GltfModel, int SceneIndex);

// Recursively allocates nodes as well as meshes and cameras.
template <typename GltfModelType>
void AllocateNode(const GltfModelType& GltfModel,
int GltfNodeIndex);

// Recursively loads nodes.
template <typename GltfModelType>
Node* LoadNode(const GltfModelType& GltfModel,
Node* Parent,
std::vector<Node*>& LinearNodes,
Scene& scene,
int GltfNodeIndex);

template <typename GltfModelType>
Expand Down Expand Up @@ -167,6 +171,7 @@ class ModelBuilder
template <typename GltfModelType>
auto GetGltfDataInfo(const GltfModelType& GltfModel, int AccessorId);

// Returns the node pointer from the node index in the source GLTF model.
Node* NodeFromGltfIndex(int GltfIndex) const
{
auto it = m_NodeIndexRemapping.find(GltfIndex);
Expand Down Expand Up @@ -221,19 +226,21 @@ void ModelBuilder::LoadScenes(const GltfModelType& GltfModel, int SceneIndex)
auto SceneId = SceneIndex;
if (SceneId >= SceneCount)
{
LOG_ERROR_MESSAGE("Scene id ", SceneIndex, " is invalid: GLTF model only contains ", SceneCount, " scenes. Loading default scene.");
DEV_ERROR("Scene id ", SceneIndex, " is invalid: GLTF model only contains ", SceneCount, " scenes.");
SceneId = -1;
}

if (SceneId >= 0)
{
// Load only the selected scene
m_Model.Scenes.reserve(1);
AddScene(SceneId);
m_Model.DefaultSceneId = 0;
}
else
{
// Load all scenes
m_Model.Scenes.reserve(SceneCount);
for (int i = 0; i < SceneCount; ++i)
AddScene(i);

Expand All @@ -250,11 +257,11 @@ void ModelBuilder::LoadScenes(const GltfModelType& GltfModel, int SceneIndex)
}
else
{
m_Model.Scenes.emplace_back();
auto& RootNodes = m_Model.Scenes.back().RootNodes;
m_Model.Scenes.resize(1);
auto& RootNodes = m_Model.Scenes[0].RootNodes;
RootNodes.resize(GltfModel.GetNodeCount());

// Load all nodes if there is no scene
// Load all nodes if there are no scenes
for (size_t node_idx = 0; node_idx < RootNodes.size(); ++node_idx)
RootNodes[node_idx] = reinterpret_cast<Node*>(node_idx);
}
Expand All @@ -274,7 +281,7 @@ void ModelBuilder::AllocateNode(const GltfModelType& GltfModel,
// The node has already been allocated.
// Note: we iterate through the list of nodes and recursively allocate
// all child nodes. As a result, we may encounter a node that
// has already been allocated as child of another.
// has already been allocated as a child of another.
// Besides, same node may be present in multiple scenes.
return;
}
Expand Down Expand Up @@ -477,7 +484,7 @@ Camera* ModelBuilder::LoadCamera(const GltfModelType& GltfModel,
template <typename GltfModelType>
Node* ModelBuilder::LoadNode(const GltfModelType& GltfModel,
Node* Parent,
std::vector<Node*>& LinearNodes,
Scene& scene,
int GltfNodeIndex)
{
auto node_it = m_NodeIndexRemapping.find(GltfNodeIndex);
Expand All @@ -486,7 +493,8 @@ Node* ModelBuilder::LoadNode(const GltfModelType& GltfModel,

auto& NewNode = m_Model.Nodes[LoadedNodeId];
VERIFY_EXPR(NewNode.Index == LoadedNodeId);
LinearNodes.emplace_back(&NewNode);
// Add the node to the scene's linear nodes array
scene.LinearNodes.emplace_back(&NewNode);

if (m_LoadedNodes.find(LoadedNodeId) != m_LoadedNodes.end())
return &NewNode;
Expand Down Expand Up @@ -526,7 +534,7 @@ Node* ModelBuilder::LoadNode(const GltfModelType& GltfModel,
NewNode.Children.reserve(GltfNode.GetChildrenIds().size());
for (const auto ChildNodeIdx : GltfNode.GetChildrenIds())
{
NewNode.Children.push_back(LoadNode(GltfModel, &NewNode, LinearNodes, ChildNodeIdx));
NewNode.Children.push_back(LoadNode(GltfModel, &NewNode, scene, ChildNodeIdx));
}

// Node contains mesh data
Expand Down Expand Up @@ -844,6 +852,7 @@ bool ModelBuilder::LoadAnimationAndSkin(const GltfModelType& GltfModel)
// Assign skins
for (int i = 0; i < static_cast<int>(m_Model.Nodes.size()); ++i)
{
VERIFY_EXPR(m_Model.Nodes[i].Index == i);
auto skin_it = m_NodeIdToSkinId.find(i);
if (skin_it != m_NodeIdToSkinId.end())
{
Expand Down Expand Up @@ -874,7 +883,7 @@ void ModelBuilder::Execute(const GltfModelType& GltfModel,

for (const auto& scene : m_Model.Scenes)
{
for (auto* pNode : scene.RootNodes)
for (const auto* pNode : scene.RootNodes)
{
// We temporarily store GLTF node index in the pointer
const auto GltfNodeId = static_cast<int>(reinterpret_cast<size_t>(pNode));
Expand All @@ -886,17 +895,19 @@ void ModelBuilder::Execute(const GltfModelType& GltfModel,
m_Model.Meshes.shrink_to_fit();
m_Model.Cameras.shrink_to_fit();

//m_Model.RootNodes.reserve(NodeIds.size());
for (auto& scene : m_Model.Scenes)
{
for (size_t i = 0; i < scene.RootNodes.size(); ++i)
{
auto& pNode = scene.RootNodes[i];
const auto GltfNodeId = static_cast<int>(reinterpret_cast<size_t>(pNode));
pNode = LoadNode(GltfModel, nullptr, scene.LinearNodes, GltfNodeId);
pNode = LoadNode(GltfModel, nullptr, scene, GltfNodeId);
}
scene.LinearNodes.shrink_to_fit();
}
VERIFY_EXPR(m_LoadedNodes.size() == m_Model.Nodes.size());
VERIFY_EXPR(m_LoadedMeshes.size() == m_Model.Meshes.size());
VERIFY_EXPR(m_LoadedCameras.size() == m_Model.Cameras.size());

LoadAnimationAndSkin(GltfModel);

Expand Down
2 changes: 1 addition & 1 deletion AssetLoader/interface/GLTFLoader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ struct ModelTransforms
};
std::vector<SkinTransforms> Skins;

// Node animation transforms.
// Animation transforms for each node in the model.
// This is an intermediate data to compute transform matrices.
struct AnimationTransforms
{
Expand Down
56 changes: 29 additions & 27 deletions AssetLoader/src/GLTFLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1703,13 +1703,13 @@ BoundBox Model::ComputeBoundingBox(Uint32 SceneIndex, const ModelTransforms& Tra
ModelAABB.Min = float3{+FLT_MAX, +FLT_MAX, +FLT_MAX};
ModelAABB.Max = float3{-FLT_MAX, -FLT_MAX, -FLT_MAX};

for (size_t i = 0; i < scene.LinearNodes.size(); ++i)
for (const auto* pN : scene.LinearNodes)
{
const auto& N = *scene.LinearNodes[i];
if (N.pMesh != nullptr && N.pMesh->IsValidBB())
VERIFY_EXPR(pN != nullptr);
if (pN->pMesh != nullptr && pN->pMesh->IsValidBB())
{
const auto& GlobalMatrix = Transforms.NodeGlobalMatrices[N.Index];
const auto NodeAABB = N.pMesh->BB.Transform(GlobalMatrix);
const auto& GlobalMatrix = Transforms.NodeGlobalMatrices[pN->Index];
const auto NodeAABB = pN->pMesh->BB.Transform(GlobalMatrix);

ModelAABB.Min = std::min(ModelAABB.Min, NodeAABB.Min);
ModelAABB.Max = std::max(ModelAABB.Max, NodeAABB.Max);
Expand Down Expand Up @@ -1774,8 +1774,10 @@ void Model::ComputeTransforms(Uint32 SceneIndex,
DEV_ERROR("Invalid scene index ", SceneIndex);
return;
}

const auto& scene = Scenes[SceneIndex];

// Note that the matrices are indexed by the global node index,
// not the linear node index in the scene.
Transforms.NodeGlobalMatrices.resize(Nodes.size());
Transforms.NodeLocalMatrices.resize(Nodes.size());

Expand All @@ -1788,10 +1790,10 @@ void Model::ComputeTransforms(Uint32 SceneIndex,
else
{
Transforms.Skins.clear();
for (size_t i = 0; i < scene.LinearNodes.size(); ++i)
for (auto* pNode : scene.LinearNodes)
{
auto& N = *scene.LinearNodes[i];
Transforms.NodeLocalMatrices[N.Index] = ComputeNodeLocalMatrix(N);
VERIFY_EXPR(pNode != nullptr);
Transforms.NodeLocalMatrices[pNode->Index] = ComputeNodeLocalMatrix(*pNode);
}
}

Expand All @@ -1802,19 +1804,19 @@ void Model::ComputeTransforms(Uint32 SceneIndex,
// Update join matrices
if (!Transforms.Skins.empty())
{
for (auto& pNode : scene.LinearNodes)
for (const auto* pNode : scene.LinearNodes)
{
auto& node = *pNode;
auto* pMesh = node.pMesh;
auto* pSkin = node.pSkin;
VERIFY_EXPR(pNode != nullptr);
auto* pMesh = pNode->pMesh;
auto* pSkin = pNode->pSkin;
if (pMesh == nullptr || pSkin == nullptr)
continue;

const auto& NodeGlobalMat = Transforms.NodeGlobalMatrices[node.Index];
VERIFY(node.SkinTransformsIndex < static_cast<int>(SkinTransformsCount),
"Skin transform index (", node.SkinTransformsIndex, ") exceeds the skin transform count in this mesh (", SkinTransformsCount,
const auto& NodeGlobalMat = Transforms.NodeGlobalMatrices[pNode->Index];
VERIFY(pNode->SkinTransformsIndex < static_cast<int>(SkinTransformsCount),
"Skin transform index (", pNode->SkinTransformsIndex, ") exceeds the skin transform count in this mesh (", SkinTransformsCount,
"). This appears to be a bug.");
auto& JointMatrices = Transforms.Skins[node.SkinTransformsIndex].JointMatrices;
auto& JointMatrices = Transforms.Skins[pNode->SkinTransformsIndex].JointMatrices;
if (JointMatrices.size() != pSkin->Joints.size())
JointMatrices.resize(pSkin->Joints.size());

Expand Down Expand Up @@ -1854,15 +1856,15 @@ void Model::UpdateAnimation(Uint32 SceneIndex, Uint32 AnimationIndex, float time
Transforms.NodeAnimations.resize(scene.LinearNodes.size());
VERIFY_EXPR(Transforms.NodeAnimations.size() == Transforms.NodeLocalMatrices.size());

for (size_t i = 0; i < scene.LinearNodes.size(); ++i)
for (const auto* pN : scene.LinearNodes)
{
const auto& N = *scene.LinearNodes[i];
auto& A = Transforms.NodeAnimations[i];
VERIFY_EXPR(pN != nullptr);
auto& A = Transforms.NodeAnimations[pN->Index];

// NB: not each component has to be animated (e.g. 'Fox' test model)
A.Translation = N.Translation;
A.Rotation = N.Rotation;
A.Scale = N.Scale;
A.Translation = pN->Translation;
A.Rotation = pN->Rotation;
A.Scale = pN->Scale;
}

for (auto& channel : animation.Channels)
Expand Down Expand Up @@ -1944,12 +1946,12 @@ void Model::UpdateAnimation(Uint32 SceneIndex, Uint32 AnimationIndex, float time
}
}

for (size_t i = 0; i < scene.LinearNodes.size(); ++i)
for (const auto* pN : scene.LinearNodes)
{
const auto& N = *scene.LinearNodes[i];
const auto& A = Transforms.NodeAnimations[i];
VERIFY_EXPR(pN != nullptr);
const auto& A = Transforms.NodeAnimations[pN->Index];

Transforms.NodeLocalMatrices[N.Index] = ComputeNodeLocalMatrix(A.Scale, A.Rotation, A.Translation, N.Matrix);
Transforms.NodeLocalMatrices[pN->Index] = ComputeNodeLocalMatrix(A.Scale, A.Rotation, A.Translation, pN->Matrix);
}
}

Expand Down

0 comments on commit 274b800

Please sign in to comment.