Skip to content

Commit

Permalink
GLTF loader: enabled multiple scenes support (#193, WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed May 18, 2023
1 parent a1593bf commit b182eca
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 66 deletions.
107 changes: 74 additions & 33 deletions AssetLoader/interface/GLTFBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class ModelBuilder
using ConvertedBufferViewMap = std::unordered_map<ConvertedBufferViewKey, ConvertedBufferViewData, ConvertedBufferViewKey::Hasher>;

template <typename GltfModelType>
std::vector<int> LoadScenes(const GltfModelType& GltfModel, int SceneIndex);
void LoadScenes(const GltfModelType& GltfModel, int SceneIndex);

template <typename GltfModelType>
void AllocateNode(const GltfModelType& GltfModel,
Expand All @@ -113,6 +113,7 @@ class ModelBuilder
template <typename GltfModelType>
Node* LoadNode(const GltfModelType& GltfModel,
Node* Parent,
std::vector<Node*>& LinearNodes,
int GltfNodeIndex);

template <typename GltfModelType>
Expand Down Expand Up @@ -170,7 +171,7 @@ class ModelBuilder
{
auto it = m_NodeIndexRemapping.find(GltfIndex);
return it != m_NodeIndexRemapping.end() ?
&m_Model.LinearNodes[it->second] :
&m_Model.Nodes[it->second] :
nullptr;
}

Expand Down Expand Up @@ -199,44 +200,66 @@ class ModelBuilder
};

template <typename GltfModelType>
std::vector<int> ModelBuilder::LoadScenes(const GltfModelType& GltfModel, int SceneIndex)
void ModelBuilder::LoadScenes(const GltfModelType& GltfModel, int SceneIndex)
{
std::vector<int> NodeIds;
auto AddScene = [&](int GltfSceneId) {
const auto& GltfScene = GltfModel.GetScene(GltfSceneId);

m_Model.Scenes.emplace_back();
auto& scene = m_Model.Scenes.back();
scene.Name = GltfScene.GetName();
auto& RootNodes = scene.RootNodes;
RootNodes.resize(GltfScene.GetNodeCount());

// Temporarily store node ids as pointers
for (size_t i = 0; i < RootNodes.size(); ++i)
RootNodes[i] = reinterpret_cast<Node*>(static_cast<size_t>(GltfScene.GetNodeId(i)));
};

const auto SceneCount = GltfModel.GetSceneCount();
if (SceneCount > 0)
if (const auto SceneCount = GltfModel.GetSceneCount())
{
auto SceneId = SceneIndex;
if (SceneId >= static_cast<int>(SceneCount))
{
LOG_ERROR_MESSAGE("Scene id ", SceneIndex, " is invalid: GLTF model only contains ", SceneCount, " scenes. Loading default scene.");
SceneId = -1;
}
if (SceneId < 0)

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

m_Model.DefaultSceneId = GltfModel.GetDefaultSceneId();
if (m_Model.DefaultSceneId < 0)
m_Model.DefaultSceneId = 0;

SceneId = DefaultSceneId >= 0 ? DefaultSceneId : 0;
if (SceneId >= static_cast<int>(SceneCount))
if (m_Model.DefaultSceneId >= static_cast<int>(SceneCount))
{
LOG_ERROR_MESSAGE("Default id ", SceneIndex, " is invalid: GLTF model only contains ", SceneCount, " scenes. Loading scene 0.");
SceneId = 0;
LOG_ERROR_MESSAGE("Default scene id ", m_Model.DefaultSceneId, " is invalid: GLTF model only contains ", SceneCount, " scenes. Using scene 0 as default.");
m_Model.DefaultSceneId = 0;
}
}
const auto& GltfScene = GltfModel.GetScene(SceneId);
NodeIds.resize(GltfScene.GetNodeCount());
for (size_t i = 0; i < NodeIds.size(); ++i)
NodeIds[i] = GltfScene.GetNodeId(i);
}
else
{
NodeIds.resize(GltfModel.GetNodeCount());
m_Model.Scenes.emplace_back();
auto& RootNodes = m_Model.Scenes.back().RootNodes;
RootNodes.resize(GltfModel.GetNodeCount());

// Load all nodes if there is no scene
for (int node_idx = 0; node_idx < static_cast<int>(NodeIds.size()); ++node_idx)
NodeIds[node_idx] = node_idx;
for (size_t node_idx = 0; node_idx < RootNodes.size(); ++node_idx)
RootNodes[node_idx] = reinterpret_cast<Node*>(node_idx);
}

return NodeIds;
m_Model.Scenes.shrink_to_fit();
}


Expand All @@ -245,7 +268,7 @@ void ModelBuilder::AllocateNode(const GltfModelType& GltfModel,
int GltfNodeIndex)
{
{
const auto NodeId = static_cast<int>(m_Model.LinearNodes.size());
const auto NodeId = static_cast<int>(m_Model.Nodes.size());
if (!m_NodeIndexRemapping.emplace(GltfNodeIndex, NodeId).second)
{
// The node has already been allocated.
Expand All @@ -256,7 +279,7 @@ void ModelBuilder::AllocateNode(const GltfModelType& GltfModel,
return;
}

m_Model.LinearNodes.emplace_back(NodeId);
m_Model.Nodes.emplace_back(NodeId);
}

const auto& GltfNode = GltfModel.GetNode(GltfNodeIndex);
Expand Down Expand Up @@ -454,14 +477,16 @@ Camera* ModelBuilder::LoadCamera(const GltfModelType& GltfModel,
template <typename GltfModelType>
Node* ModelBuilder::LoadNode(const GltfModelType& GltfModel,
Node* Parent,
std::vector<Node*>& LinearNodes,
int GltfNodeIndex)
{
auto node_it = m_NodeIndexRemapping.find(GltfNodeIndex);
VERIFY(node_it != m_NodeIndexRemapping.end(), "Node with GLTF index ", GltfNodeIndex, " is not present in the map. This appears to be a bug.");
const auto LoadedNodeId = node_it->second;

auto& NewNode = m_Model.LinearNodes[LoadedNodeId];
auto& NewNode = m_Model.Nodes[LoadedNodeId];
VERIFY_EXPR(NewNode.Index == LoadedNodeId);
LinearNodes.emplace_back(&NewNode);

if (m_LoadedNodes.find(LoadedNodeId) != m_LoadedNodes.end())
return &NewNode;
Expand Down Expand Up @@ -501,7 +526,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, ChildNodeIdx));
NewNode.Children.push_back(LoadNode(GltfModel, &NewNode, LinearNodes, ChildNodeIdx));
}

// Node contains mesh data
Expand Down Expand Up @@ -817,15 +842,15 @@ bool ModelBuilder::LoadAnimationAndSkin(const GltfModelType& GltfModel)
LoadSkins(GltfModel);

// Assign skins
for (int i = 0; i < static_cast<int>(m_Model.LinearNodes.size()); ++i)
for (int i = 0; i < static_cast<int>(m_Model.Nodes.size()); ++i)
{
auto skin_it = m_NodeIdToSkinId.find(i);
if (skin_it != m_NodeIdToSkinId.end())
{
const auto SkinIndex = skin_it->second;
if (SkinIndex >= 0)
{
auto& N = m_Model.LinearNodes[i];
auto& N = m_Model.Nodes[i];
N.pSkin = &m_Model.Skins[SkinIndex];
N.SkinTransformsIndex = m_Model.SkinTransformsCount++;
}
Expand All @@ -845,17 +870,33 @@ void ModelBuilder::Execute(const GltfModelType& GltfModel,
IRenderDevice* pDevice,
IDeviceContext* pContext)
{
const auto NodeIds = LoadScenes(GltfModel, SceneIndex);
for (auto GltfNodeId : NodeIds)
AllocateNode(GltfModel, GltfNodeId);
LoadScenes(GltfModel, SceneIndex);

for (const auto& scene : m_Model.Scenes)
{
for (auto* pNode : scene.RootNodes)
{
// We temporarily store GLTF node index in the pointer
const auto GltfNodeId = static_cast<int>(reinterpret_cast<size_t>(pNode));
AllocateNode(GltfModel, GltfNodeId);
}
}

m_Model.LinearNodes.shrink_to_fit();
m_Model.Nodes.shrink_to_fit();
m_Model.Meshes.shrink_to_fit();
m_Model.Cameras.shrink_to_fit();

m_Model.RootNodes.reserve(NodeIds.size());
for (auto GltfNodeId : NodeIds)
m_Model.RootNodes.push_back(LoadNode(GltfModel, nullptr, GltfNodeId));
//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);
}
scene.LinearNodes.shrink_to_fit();
}

LoadAnimationAndSkin(GltfModel);

Expand Down
23 changes: 15 additions & 8 deletions AssetLoader/interface/GLTFLoader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,13 @@ struct Node
{}
};

struct Scene
{
std::string Name;
std::vector<Node*> RootNodes;
// Linear list of all nodes in the scene.
std::vector<Node*> LinearNodes;
};

struct AnimationChannel
{
Expand Down Expand Up @@ -560,10 +567,8 @@ struct Model
VERTEX_BUFFER_ID_SKIN_ATTRIBS,
};

/// Node hierarchy.
std::vector<Node*> RootNodes;

std::vector<Node> LinearNodes;
std::vector<Scene> Scenes;
std::vector<Node> Nodes;
std::vector<Mesh> Meshes;
std::vector<Camera> Cameras;
std::vector<Skin> Skins;
Expand All @@ -575,6 +580,7 @@ struct Model

// The number of nodes that have skin.
int SkinTransformsCount = 0;
int DefaultSceneId = 0;

Model(const ModelCreateInfo& CI);

Expand Down Expand Up @@ -693,14 +699,15 @@ struct Model
/// use Material.TextureIds[TextureAttributeIndex].
int GetTextureAttibuteIndex(const char* Name) const;

bool CompatibleWithTransforms(const ModelTransforms& Transforms) const;
bool CompatibleWithTransforms(Uint32 SceneIndex, const ModelTransforms& Transforms) const;

void ComputeTransforms(ModelTransforms& Transforms,
void ComputeTransforms(Uint32 SceneIndex,
ModelTransforms& Transforms,
const float4x4& RootTransform = float4x4::Identity(),
Int32 AnimationIndex = -1,
float Time = 0) const;

BoundBox ComputeBoundingBox(const ModelTransforms& Transforms) const;
BoundBox ComputeBoundingBox(Uint32 SceneIndex, const ModelTransforms& Transforms) const;

size_t GetTextureCount() const
{
Expand Down Expand Up @@ -729,7 +736,7 @@ struct Model

void LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model);
void LoadMaterials(const tinygltf::Model& gltf_model, const ModelCreateInfo::MaterialLoadCallbackType& MaterialLoadCallback);
void UpdateAnimation(Uint32 index, float time, ModelTransforms& Transforms) const;
void UpdateAnimation(Uint32 SceneIndex, Uint32 AnimationIndex, float time, ModelTransforms& Transforms) const;

// Returns the alpha cutoff value for the given texture.
// TextureIdx is the texture index in the GLTF file and also the Textures array.
Expand Down
Loading

0 comments on commit b182eca

Please sign in to comment.