summaryrefslogtreecommitdiffstats
path: root/AssetLoader/src/GLTFLoader.cpp
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2019-04-23 16:15:54 +0000
committerEgor Yusov <egor.yusov@gmail.com>2019-04-23 16:15:54 +0000
commited52abbec59881abc349ecc2fcd427f363f6a71a (patch)
treeabdf5dcec3639138d19302cb9020f2f1803ccfef /AssetLoader/src/GLTFLoader.cpp
parentAdded AssetLoader project with first implementation of GLTFLoader (diff)
downloadDiligentTools-ed52abbec59881abc349ecc2fcd427f363f6a71a.tar.gz
DiligentTools-ed52abbec59881abc349ecc2fcd427f363f6a71a.zip
Moved GLTFLoader structures to the header
Diffstat (limited to 'AssetLoader/src/GLTFLoader.cpp')
-rw-r--r--AssetLoader/src/GLTFLoader.cpp1994
1 files changed, 900 insertions, 1094 deletions
diff --git a/AssetLoader/src/GLTFLoader.cpp b/AssetLoader/src/GLTFLoader.cpp
index fb3d0d0..2b94c4b 100644
--- a/AssetLoader/src/GLTFLoader.cpp
+++ b/AssetLoader/src/GLTFLoader.cpp
@@ -26,7 +26,6 @@
#include <cmath>
#include "GLTFLoader.h"
-#include "AdvancedMath.h"
#include "MapHelper.h"
#include "CommonlyUsedStates.h"
@@ -38,1334 +37,1141 @@
#include "../../External/tinygltf/tiny_gltf.h"
-
-// Changing this value here also requires changing it in the vertex shader
-#define MAX_NUM_JOINTS 128u
-
namespace Diligent
{
namespace GLTF
{
- RefCntAutoPtr<ITexture> TextureFromGLTFImage(IRenderDevice* pDevice,
- IDeviceContext* pCtx,
- const tinygltf::Image& gltfimage,
- ISampler* pSampler)
+
+RefCntAutoPtr<ITexture> TextureFromGLTFImage(IRenderDevice* pDevice,
+ IDeviceContext* pCtx,
+ const tinygltf::Image& gltfimage,
+ ISampler* pSampler)
+{
+ std::vector<Uint8> RGBA;
+ const Uint8* pTextureData = nullptr;
+ if (gltfimage.component == 3)
{
- std::vector<Uint8> RGBA;
- const Uint8* pTextureData = nullptr;
- if (gltfimage.component == 3)
+ RGBA.resize(gltfimage.width * gltfimage.height * 4);
+ auto rgb = gltfimage.image.begin();
+ auto rgba = RGBA.begin();
+ for (int i = 0; i < gltfimage.width * gltfimage.height; ++i)
{
- RGBA.resize(gltfimage.width * gltfimage.height * 4);
- auto rgb = gltfimage.image.begin();
- auto rgba = RGBA.begin();
- for (int i = 0; i < gltfimage.width * gltfimage.height; ++i)
+ for (int j = 0; j < 3; ++j)
{
- for (int j = 0; j < 3; ++j)
- {
- rgba[j] = rgb[j];
- }
- rgba += 4;
- rgb += 3;
+ rgba[j] = rgb[j];
}
- pTextureData = RGBA.data();
- }
- else if (gltfimage.component == 4)
- {
- pTextureData = gltfimage.image.data();
- }
- else
- {
- UNEXPECTED("Unexpected number of color components in gltf image: ", gltfimage.component);
+ rgba += 4;
+ rgb += 3;
}
+ pTextureData = RGBA.data();
+ }
+ else if (gltfimage.component == 4)
+ {
+ pTextureData = gltfimage.image.data();
+ }
+ else
+ {
+ UNEXPECTED("Unexpected number of color components in gltf image: ", gltfimage.component);
+ }
- TextureDesc TexDesc;
- TexDesc.Name = "GLTF Texture";
- TexDesc.Type = RESOURCE_DIM_TEX_2D;
- TexDesc.Usage = USAGE_DEFAULT;
- TexDesc.BindFlags = BIND_SHADER_RESOURCE;
- TexDesc.Width = gltfimage.width;
- TexDesc.Height = gltfimage.height;
- TexDesc.Format = TEX_FORMAT_RGBA8_UNORM;
- TexDesc.MipLevels = 0;
- TexDesc.MiscFlags = MISC_TEXTURE_FLAG_GENERATE_MIPS;
- RefCntAutoPtr<ITexture> pTexture;
+ TextureDesc TexDesc;
+ TexDesc.Name = "GLTF Texture";
+ TexDesc.Type = RESOURCE_DIM_TEX_2D;
+ TexDesc.Usage = USAGE_DEFAULT;
+ TexDesc.BindFlags = BIND_SHADER_RESOURCE;
+ TexDesc.Width = gltfimage.width;
+ TexDesc.Height = gltfimage.height;
+ TexDesc.Format = TEX_FORMAT_RGBA8_UNORM;
+ TexDesc.MipLevels = 0;
+ TexDesc.MiscFlags = MISC_TEXTURE_FLAG_GENERATE_MIPS;
+ RefCntAutoPtr<ITexture> pTexture;
- pDevice->CreateTexture(TexDesc, nullptr, &pTexture);
- Box UpdateBox;
- UpdateBox.MaxX = TexDesc.Width;
- UpdateBox.MaxY = TexDesc.Height;
- TextureSubResData Level0Data(pTextureData, gltfimage.width*4);
- pCtx->UpdateTexture(pTexture, 0, 0, UpdateBox, Level0Data, RESOURCE_STATE_TRANSITION_MODE_NONE, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
- pCtx->GenerateMips(pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE));
- pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)->SetSampler(pSampler);
-
- return pTexture;
- }
+ pDevice->CreateTexture(TexDesc, nullptr, &pTexture);
+ Box UpdateBox;
+ UpdateBox.MaxX = TexDesc.Width;
+ UpdateBox.MaxY = TexDesc.Height;
+ TextureSubResData Level0Data(pTextureData, gltfimage.width*4);
+ pCtx->UpdateTexture(pTexture, 0, 0, UpdateBox, Level0Data, RESOURCE_STATE_TRANSITION_MODE_NONE, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
+ pCtx->GenerateMips(pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE));
+ pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)->SetSampler(pSampler);
+
+ return pTexture;
+}
+
+
+
+Mesh::Mesh(IRenderDevice* pDevice, const float4x4& matrix)
+{
+ uniformBlock.matrix = matrix;
+
+ BufferDesc BuffDesc;
+ BuffDesc.Name = "GLTF mesh Uniform buffer";
+ BuffDesc.uiSizeInBytes = sizeof(UniformBlock);
+ BuffDesc.BindFlags = BIND_UNIFORM_BUFFER;
+ BuffDesc.Usage = USAGE_DYNAMIC;
+ BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
+
+ BufferData BuffData(&uniformBlock, sizeof(uniformBlock));
+ pDevice->CreateBuffer(BuffDesc, &BuffData, &pUniformBuffer);
+};
+
+void Mesh::SetBoundingBox(const float3& min, const float3& max)
+{
+ BB.Min = min;
+ BB.Max = max;
+ IsValidBB = true;
+}
- struct Material
- {
- enum ALPHA_MODE
- {
- ALPHAMODE_OPAQUE,
- ALPHAMODE_MASK,
- ALPHAMODE_BLEND
- };
- ALPHA_MODE AlphaMode = ALPHAMODE_OPAQUE;
-
- float AlphaCutoff = 1.0f;
- float MetallicFactor = 1.0f;
- float RoughnessFactor = 1.0f;
- float4 BaseColorFactor = float4(1.0f, 1.0f, 1.0f, 1.0f);
- float4 EmissiveFactor = float4(1.0f, 1.0f, 1.0f, 1.0f);
-
- RefCntAutoPtr<ITexture> pBaseColorTexture;
- RefCntAutoPtr<ITexture> pMetallicRoughnessTexture;
- RefCntAutoPtr<ITexture> pNormalTexture;
- RefCntAutoPtr<ITexture> pOcclusionTexture;
- RefCntAutoPtr<ITexture> pEmissiveTexture;
-
- struct TextureCoordinateSets
- {
- Uint8 BaseColor = 0;
- Uint8 MetallicRoughness = 0;
- Uint8 SpecularGlossiness = 0;
- Uint8 Normal = 0;
- Uint8 Occlusion = 0;
- Uint8 Emissive = 0;
- };
- TextureCoordinateSets TexCoordSets;
-
- struct Extension
- {
- RefCntAutoPtr<ITexture> pSpecularGlossinessTexture;
- RefCntAutoPtr<ITexture> pDiffuseTexture;
- float4 DiffuseFactor = float4(1.0f, 1.0f, 1.0f, 1.0f);
- float3 SpecularFactor = float3(0.0f, 0.0f, 0.0f);
- };
- Extension extension;
-
- struct PbrWorkflows
- {
- bool MetallicRoughness = true;
- bool SpecularGlossiness = false;
- };
- PbrWorkflows pbrWorkflows;
- };
-
- struct Primitive
+
+
+float4x4 Node::LocalMatrix()const
+{
+ return float4x4::TranslationGL(Translation) * QuaternionToMatrix(Rotation) * float4x4::Scale(Scale) * Matrix;
+}
+
+float4x4 Node::GetMatrix()const
+{
+ auto mat = LocalMatrix();
+ auto* p = Parent;
+ while (p != nullptr)
+ {
+ mat = mat * p->LocalMatrix();
+ p = p->Parent;
+ }
+ return mat;
+}
+
+void Node::Update(IDeviceContext* pCtx)
+{
+ if (Mesh)
{
- Uint32 FirstIndex = 0;
- Uint32 IndexCount = 0;
- Uint32 VertexCount = 0;
- Material& material;
- bool hasIndices;
-
- BoundBox BB;
- bool IsValidBB = false;
-
- Primitive(Uint32 _FirstIndex,
- Uint32 _IndexCount,
- Uint32 _VertexCount,
- Material& _material) :
- FirstIndex (_FirstIndex),
- IndexCount (_IndexCount),
- VertexCount (_VertexCount),
- material (_material),
- hasIndices (_IndexCount > 0)
+ auto mat = GetMatrix();
+ if (Skin != nullptr)
{
+ Mesh->uniformBlock.matrix = mat;
+ // Update join matrices
+ auto InverseTransform = mat.Inverse();
+ size_t numJoints = std::min((uint32_t)Skin->Joints.size(), Mesh::UniformBlock::MaxNumJoints);
+ for (size_t i = 0; i < numJoints; i++)
+ {
+ auto* JointNode = Skin->Joints[i];
+ auto JointMat = JointNode->GetMatrix() * Skin->InverseBindMatrices[i];
+ JointMat = InverseTransform * JointMat;
+ Mesh->uniformBlock.jointMatrix[i] = JointMat;
+ }
+ Mesh->uniformBlock.jointcount = (float)numJoints;
+ MapHelper<Mesh::UniformBlock> UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD);
+ *UniformData = Mesh->uniformBlock;
}
-
- void SetBoundingBox(const float3& min, const float3& max)
+ else
{
- BB.Min = min;
- BB.Max = max;
- IsValidBB = true;
+ MapHelper<Mesh::UniformBlock> UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD);
+ UniformData->matrix = mat;
}
- };
+ }
+ for (auto& child : Children) {
+ child->Update(pCtx);
+ }
+}
- struct Mesh
- {
- std::vector<std::unique_ptr<Primitive>> Primitives;
- BoundBox BB;
- BoundBox AABB;
- bool IsValidBB = false;
- RefCntAutoPtr<IBuffer> pUniformBuffer;
- struct UniformBlock
- {
- float4x4 matrix;
- float4x4 jointMatrix[MAX_NUM_JOINTS] = {};
- float jointcount = 0;
- } uniformBlock;
- Mesh(IRenderDevice* pDevice, const float4x4& matrix)
- {
- uniformBlock.matrix = matrix;
-
- BufferDesc BuffDesc;
- BuffDesc.Name = "GLTF mesh Uniform buffer";
- BuffDesc.uiSizeInBytes = sizeof(UniformBlock);
- BuffDesc.BindFlags = BIND_UNIFORM_BUFFER;
- BuffDesc.Usage = USAGE_DYNAMIC;
- BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE;
-
- BufferData BuffData(&uniformBlock, sizeof(uniformBlock));
- pDevice->CreateBuffer(BuffDesc, &BuffData, &pUniformBuffer);
- };
+void Model::Destroy()
+{
+ pVertexBuffer.Release();
+ pIndexBuffer.Release();
+ Nodes.clear();
+ LinearNodes.clear();
+ Skins.clear();
+ Textures.clear();
+ TextureSamplers.clear();
+ Materials.clear();
+ Animations.clear();
+ Extensions.clear();
+};
+
+void Model::LoadNode(IRenderDevice* pDevice,
+ Node* parent,
+ const tinygltf::Node& gltf_node,
+ uint32_t nodeIndex,
+ const tinygltf::Model& gltf_model,
+ std::vector<uint32_t>& indexBuffer,
+ std::vector<Vertex>& vertexBuffer,
+ float globalscale)
+{
+ std::unique_ptr<Node> NewNode(new Node{});
+ NewNode->Index = nodeIndex;
+ NewNode->Parent = parent;
+ NewNode->Name = gltf_node.name;
+ NewNode->SkinIndex = gltf_node.skin;
+ NewNode->Matrix = float4x4::Identity();
+
+ // Generate local node matrix
+ //float3 Translation;
+ if (gltf_node.translation.size() == 3)
+ {
+ NewNode->Translation = float3::MakeVector(gltf_node.translation.data());
+ }
- void SetBoundingBox(const float3& min, const float3& max)
- {
- BB.Min = min;
- BB.Max = max;
- IsValidBB = true;
- }
- };
+ if (gltf_node.rotation.size() == 4)
+ {
+ NewNode->Rotation.q = float4::MakeVector(gltf_node.rotation.data());
+ //NewNode->rotation = glm::mat4(q);
+ }
+ if (gltf_node.scale.size() == 3)
+ {
+ NewNode->Scale = float3::MakeVector(gltf_node.scale.data());
+ }
- struct Node;
- struct Skin
+ if (gltf_node.matrix.size() == 16)
{
- std::string Name;
- Node* pSkeletonRoot = nullptr;
- std::vector<float4x4> InverseBindMatrices;
- std::vector<Node*> Joints;
+ NewNode->Matrix = float4x4::MakeMatrix(gltf_node.matrix.data());
};
- /*
- glTF node
- */
- struct Node
+ // Node with children
+ if (gltf_node.children.size() > 0)
{
- std::string Name;
- Node* Parent = nullptr;
- Uint32 Index;
- std::vector<std::unique_ptr<Node>> Children;
- float4x4 Matrix;
- std::unique_ptr<Mesh> Mesh;
- Skin* Skin = nullptr;
- Uint32 SkinIndex = static_cast<Uint32>(-1);
- float3 Translation;
- float3 Scale = float3(1.0f, 1.0f, 1.0f);
- Quaternion Rotation;
- BoundBox BVH;
- BoundBox AABB;
- bool IsValidBVH = false;
-
- float4x4 LocalMatrix()
+ for (size_t i = 0; i < gltf_node.children.size(); i++)
{
- float4x4::TranslationGL(Translation) * QuaternionToMatrix(Rotation) * float4x4::Scale(Scale) * Matrix;
+ LoadNode(pDevice, NewNode.get(), gltf_model.nodes[gltf_node.children[i]], gltf_node.children[i], gltf_model, indexBuffer, vertexBuffer, globalscale);
}
+ }
- float4x4 GetMatrix()
+ // Node contains mesh data
+ if (gltf_node.mesh > -1)
+ {
+ const tinygltf::Mesh& gltf_mesh = gltf_model.meshes[gltf_node.mesh];
+ std::unique_ptr<Mesh> NewMesh(new Mesh(pDevice, NewNode->Matrix));
+ for (size_t j = 0; j < gltf_mesh.primitives.size(); j++)
{
- auto mat = LocalMatrix();
- auto* p = Parent;
- while (p != nullptr)
+ const tinygltf::Primitive& primitive = gltf_mesh.primitives[j];
+ uint32_t indexStart = static_cast<uint32_t>(indexBuffer.size());
+ uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size());
+ uint32_t indexCount = 0;
+ uint32_t vertexCount = 0;
+ float3 PosMin;
+ float3 PosMax;
+ bool hasSkin = false;
+ bool hasIndices = primitive.indices > -1;
+
+ // Vertices
{
- mat = mat * p->LocalMatrix();
- p = p->Parent;
+ const float* bufferPos = nullptr;
+ const float* bufferNormals = nullptr;
+ const float* bufferTexCoordSet0 = nullptr;
+ const float* bufferTexCoordSet1 = nullptr;
+ const uint16_t* bufferJoints = nullptr;
+ const float* bufferWeights = nullptr;
+
+ auto position_it = primitive.attributes.find("POSITION");
+ VERIFY(position_it != primitive.attributes.end(), "Position attribute is required");
+
+ const tinygltf::Accessor& posAccessor = gltf_model.accessors[position_it->second];
+ const tinygltf::BufferView& posView = gltf_model.bufferViews[posAccessor.bufferView];
+ bufferPos = reinterpret_cast<const float*>(&(gltf_model.buffers[posView.buffer].data[posAccessor.byteOffset + posView.byteOffset]));
+ PosMin =
+ float3
+ {
+ static_cast<float>(posAccessor.minValues[0]),
+ static_cast<float>(posAccessor.minValues[1]),
+ static_cast<float>(posAccessor.minValues[2])
+ };
+ PosMax =
+ float3
+ {
+ static_cast<float>(posAccessor.maxValues[0]),
+ static_cast<float>(posAccessor.maxValues[1]),
+ static_cast<float>(posAccessor.maxValues[2])
+ };
+
+ vertexCount = static_cast<uint32_t>(posAccessor.count);
+
+ if (primitive.attributes.find("NORMAL") != primitive.attributes.end())
+ {
+ const tinygltf::Accessor& normAccessor = gltf_model.accessors[primitive.attributes.find("NORMAL")->second];
+ const tinygltf::BufferView& normView = gltf_model.bufferViews[normAccessor.bufferView];
+ bufferNormals = reinterpret_cast<const float*>(&(gltf_model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset]));
+ }
+
+ if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end())
+ {
+ const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_0")->second];
+ const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView];
+ bufferTexCoordSet0 = reinterpret_cast<const float*>(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
+ }
+ if (primitive.attributes.find("TEXCOORD_1") != primitive.attributes.end())
+ {
+ const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_1")->second];
+ const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView];
+ bufferTexCoordSet1 = reinterpret_cast<const float*>(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
+ }
+
+ // Skinning
+ // Joints
+ if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end())
+ {
+ const tinygltf::Accessor& jointAccessor = gltf_model.accessors[primitive.attributes.find("JOINTS_0")->second];
+ const tinygltf::BufferView& jointView = gltf_model.bufferViews[jointAccessor.bufferView];
+ bufferJoints = reinterpret_cast<const uint16_t*>(&(gltf_model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset]));
+ }
+
+ if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end())
+ {
+ const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("WEIGHTS_0")->second];
+ const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView];
+ bufferWeights = reinterpret_cast<const float*>(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
+ }
+
+ hasSkin = (bufferJoints != nullptr && bufferWeights != nullptr);
+
+ for (size_t v = 0; v < posAccessor.count; v++)
+ {
+ Vertex vert{};
+ vert.pos = float4(float3::MakeVector(&bufferPos[v * 3]), 1.0f);
+ vert.normal = bufferNormals != nullptr ? normalize(float3::MakeVector(&bufferNormals[v * 3])) : float3{0,1,0};
+ vert.uv0 = bufferTexCoordSet0 != nullptr ? float2::MakeVector(&bufferTexCoordSet0[v * 2]) : float2{};
+ vert.uv1 = bufferTexCoordSet1 != nullptr ? float2::MakeVector(&bufferTexCoordSet1[v * 2]) : float2{};
+
+ if (hasSkin)
+ {
+ vert.joint0 = float4::MakeVector(&bufferJoints [v * 4]);
+ vert.weight0 = float4::MakeVector(&bufferWeights[v * 4]);
+ }
+ vertexBuffer.push_back(vert);
+ }
}
- return mat;
- }
- void Update(IDeviceContext* pCtx)
- {
- if (Mesh)
+ // Indices
+ if (hasIndices)
{
- auto mat = GetMatrix();
- if (Skin != nullptr)
+ const tinygltf::Accessor& accessor = gltf_model.accessors[primitive.indices > -1 ? primitive.indices : 0];
+ const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
+ const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
+
+ indexCount = static_cast<uint32_t>(accessor.count);
+ const void *dataPtr = &(buffer.data[accessor.byteOffset + bufferView.byteOffset]);
+
+ switch (accessor.componentType)
{
- Mesh->uniformBlock.matrix = mat;
- // Update join matrices
- auto InverseTransform = mat.Inverse();
- size_t numJoints = std::min((uint32_t)Skin->Joints.size(), MAX_NUM_JOINTS);
- for (size_t i = 0; i < numJoints; i++)
+ case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT:
+ {
+ const uint32_t *buf = static_cast<const uint32_t*>(dataPtr);
+ for (size_t index = 0; index < accessor.count; index++)
+ {
+ indexBuffer.push_back(buf[index] + vertexStart);
+ }
+ break;
+ }
+ case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT:
+ {
+ const uint16_t *buf = static_cast<const uint16_t*>(dataPtr);
+ for (size_t index = 0; index < accessor.count; index++)
+ {
+ indexBuffer.push_back(buf[index] + vertexStart);
+ }
+ break;
+ }
+ case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE:
{
- auto* JointNode = Skin->Joints[i];
- auto JointMat = JointNode->GetMatrix() * Skin->InverseBindMatrices[i];
- JointMat = InverseTransform * JointMat;
- Mesh->uniformBlock.jointMatrix[i] = JointMat;
+ const uint8_t *buf = static_cast<const uint8_t*>(dataPtr);
+ for (size_t index = 0; index < accessor.count; index++)
+ {
+ indexBuffer.push_back(buf[index] + vertexStart);
+ }
+ break;
}
- Mesh->uniformBlock.jointcount = (float)numJoints;
- MapHelper<Mesh::UniformBlock> UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD);
- *UniformData = Mesh->uniformBlock;
+ default:
+ std::cerr << "Index component type " << accessor.componentType << " not supported!" << std::endl;
+ return;
}
- else
+ }
+ std::unique_ptr<Primitive> newPrimitive(
+ new Primitive
{
- MapHelper<Mesh::UniformBlock> UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD);
- UniformData->matrix = mat;
+ indexStart,
+ indexCount,
+ vertexCount,
+ primitive.material > -1 ? Materials[primitive.material] : Materials.back()
}
- }
+ );
- for (auto& child : Children) {
- child->Update(pCtx);
- }
+ newPrimitive->SetBoundingBox(PosMin, PosMax);
+ NewMesh->Primitives.push_back(std::move(newPrimitive));
}
- };
+ // Mesh BB from BBs of primitives
+ for (const auto& prim : NewMesh->Primitives)
+ {
+ if (prim->IsValidBB && !NewMesh->IsValidBB)
+ {
+ NewMesh->BB = prim->BB;
+ NewMesh->IsValidBB = true;
+ }
+ float3 bb_min = std::min(NewMesh->BB.Min, prim->BB.Min);
+ float3 bb_max = std::max(NewMesh->BB.Max, prim->BB.Max);
+ NewMesh->SetBoundingBox(bb_min, bb_max);
+ }
+ NewNode->Mesh = std::move(NewMesh);
+ }
- struct AnimationChannel
+ LinearNodes.push_back(NewNode.get());
+ if (parent)
{
- enum PATH_TYPE
- {
- TRANSLATION,
- ROTATION,
- SCALE
- };
- PATH_TYPE PathType;
- Node* node = nullptr;
- Uint32 SamplerIndex = static_cast<Uint32>(-1);
- };
+ parent->Children.push_back(std::move(NewNode));
+ }
+ else
+ {
+ Nodes.push_back(std::move(NewNode));
+ }
+}
- struct AnimationSampler
+void Model::LoadSkins(const tinygltf::Model& gltf_model)
+{
+ for (const auto& source : gltf_model.skins)
{
- enum INTERPOLATION_TYPE
+ std::unique_ptr<Skin> NewSkin( new Skin{} );
+ NewSkin->Name = source.name;
+
+ // Find skeleton root node
+ if (source.skeleton > -1)
{
- LINEAR,
- STEP,
- CUBICSPLINE
- };
- INTERPOLATION_TYPE Interpolation;
- std::vector<float> Inputs;
- std::vector<float4> OutputsVec4;
- };
+ NewSkin->pSkeletonRoot = NodeFromIndex(source.skeleton);
+ }
+ // Find joint nodes
+ for (int jointIndex : source.joints)
+ {
+ Node* node = NodeFromIndex(jointIndex);
+ if (node)
+ {
+ NewSkin->Joints.push_back(NodeFromIndex(jointIndex));
+ }
+ }
- struct Animation
- {
- std::string Name;
- std::vector<AnimationSampler> Samplers;
- std::vector<AnimationChannel> Channels;
+ // Get inverse bind matrices from buffer
+ if (source.inverseBindMatrices > -1)
+ {
+ const tinygltf::Accessor& accessor = gltf_model.accessors[source.inverseBindMatrices];
+ const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
+ const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
+ NewSkin->InverseBindMatrices.resize(accessor.count);
+ memcpy(NewSkin->InverseBindMatrices.data(), &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(float4x4));
+ }
- float Start = std::numeric_limits<float>::max();
- float End = std::numeric_limits<float>::min();
- };
+ Skins.push_back(std::move(NewSkin));
+ }
+}
- struct Model
+void Model::LoadTextures(IRenderDevice* pDevice,
+ IDeviceContext* pCtx,
+ const tinygltf::Model& gltf_model)
+{
+ for (const tinygltf::Texture& gltf_tex : gltf_model.textures)
{
- struct Vertex
+ const tinygltf::Image& gltf_image = gltf_model.images[gltf_tex.source];
+ RefCntAutoPtr<ISampler> pSampler;
+ if (gltf_tex.sampler == -1)
+ {
+ // No sampler specified, use a default one
+ pDevice->CreateSampler(Sam_LinearWrap, &pSampler);
+ }
+ else
{
- float3 pos;
- float3 normal;
- float2 uv0;
- float2 uv1;
- float4 joint0;
- float4 weight0;
- };
+ pSampler = TextureSamplers[gltf_tex.sampler];
+ }
+ auto pTexture = TextureFromGLTFImage(pDevice, pCtx, gltf_image, pSampler);
+ Textures.push_back(std::move(pTexture));
+ }
+}
- RefCntAutoPtr<IBuffer> pVertexBuffer;
- RefCntAutoPtr<IBuffer> pIndexBuffer;
- Uint32 IndexCount = 0;
+namespace
+{
- float4x4 aabb;
+TEXTURE_ADDRESS_MODE GetWrapMode(int32_t wrapMode)
+{
+ switch (wrapMode)
+ {
+ case 10497:
+ return TEXTURE_ADDRESS_WRAP;
+ case 33071:
+ return TEXTURE_ADDRESS_CLAMP;
+ case 33648:
+ return TEXTURE_ADDRESS_MIRROR;
+ default:
+ return TEXTURE_ADDRESS_WRAP;
+ }
+}
- std::vector<std::unique_ptr<Node>> Nodes;
- std::vector<Node*> LinearNodes;
+FILTER_TYPE GetFilterMode(int32_t filterMode)
+{
+ switch (filterMode)
+ {
+ case 9728:
+ return FILTER_TYPE_POINT;
+ case 9729:
+ return FILTER_TYPE_LINEAR;
+ case 9984:
+ return FILTER_TYPE_POINT;
+ case 9985:
+ return FILTER_TYPE_POINT;
+ case 9986:
+ return FILTER_TYPE_LINEAR;
+ case 9987:
+ return FILTER_TYPE_LINEAR;
+ default:
+ return FILTER_TYPE_LINEAR;
+ }
+}
- std::vector<std::unique_ptr<Skin>> Skins;
+} // namespace
- std::vector<RefCntAutoPtr<ITexture>> Textures;
- std::vector<RefCntAutoPtr<ISampler>> TextureSamplers;
- std::vector<Material> Materials;
- std::vector<Animation> Animations;
- std::vector<std::string> Extensions;
+void Model::LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model)
+{
+ for (const tinygltf::Sampler& smpl : gltf_model.samplers)
+ {
+ SamplerDesc SamDesc;
+ SamDesc.MinFilter = GetFilterMode(smpl.minFilter);
+ SamDesc.MagFilter = GetFilterMode(smpl.magFilter);
+ SamDesc.MipFilter = SamDesc.MagFilter;
+ SamDesc.AddressU = GetWrapMode(smpl.wrapS);
+ SamDesc.AddressV = GetWrapMode(smpl.wrapT);
+ SamDesc.AddressW = SamDesc.AddressV;
+ RefCntAutoPtr<ISampler> pSampler;
+ pDevice->CreateSampler(SamDesc, &pSampler);
+ TextureSamplers.push_back(std::move(pSampler));
+ }
+}
- struct Dimensions
- {
- float3 min = float3(+FLT_MAX, +FLT_MAX, +FLT_MAX);
- float3 max = float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
- } dimensions;
+void Model::LoadMaterials(const tinygltf::Model& gltf_model)
+{
+ for (const tinygltf::Material& gltf_mat : gltf_model.materials)
+ {
+ Material Mat;
- void Destroy()
{
- pVertexBuffer.Release();
- pIndexBuffer.Release();
- Nodes.clear();
- LinearNodes.clear();
- Skins.clear();
- Textures.clear();
- TextureSamplers.clear();
- Materials.clear();
- Animations.clear();
- Extensions.clear();
- };
-
- void LoadNode(IRenderDevice* pDevice,
- Node* parent,
- const tinygltf::Node& gltf_node,
- uint32_t nodeIndex,
- const tinygltf::Model& gltf_model,
- std::vector<uint32_t>& indexBuffer,
- std::vector<Vertex>& vertexBuffer,
- float globalscale)
- {
- std::unique_ptr<Node> NewNode(new Node{});
- NewNode->Index = nodeIndex;
- NewNode->Parent = parent;
- NewNode->Name = gltf_node.name;
- NewNode->SkinIndex = gltf_node.skin;
- NewNode->Matrix = float4x4::Identity();
-
- // Generate local node matrix
- //float3 Translation;
- if (gltf_node.translation.size() == 3)
+ auto base_color_tex_it = gltf_mat.values.find("baseColorTexture");
+ if (base_color_tex_it != gltf_mat.values.end())
{
- NewNode->Translation = float3::MakeVector(gltf_node.translation.data());
+ Mat.pBaseColorTexture = Textures[base_color_tex_it->second.TextureIndex()];
+ Mat.TexCoordSets.BaseColor = static_cast<Uint8>(base_color_tex_it->second.TextureTexCoord());
}
+ }
- if (gltf_node.rotation.size() == 4)
+ {
+ auto metal_rough_tex_it = gltf_mat.values.find("metallicRoughnessTexture");
+ if (metal_rough_tex_it != gltf_mat.values.end())
{
- NewNode->Rotation.q = float4::MakeVector(gltf_node.rotation.data());
- //NewNode->rotation = glm::mat4(q);
+ Mat.pMetallicRoughnessTexture = Textures[metal_rough_tex_it->second.TextureIndex()];
+ Mat.TexCoordSets.MetallicRoughness = static_cast<Uint8>(metal_rough_tex_it->second.TextureTexCoord());
}
+ }
- if (gltf_node.scale.size() == 3)
+ {
+ auto rough_factor_it = gltf_mat.values.find("roughnessFactor");
+ if (rough_factor_it != gltf_mat.values.end())
{
- NewNode->Scale = float3::MakeVector(gltf_node.scale.data());
+ Mat.RoughnessFactor = static_cast<float>(rough_factor_it->second.Factor());
}
+ }
- if (gltf_node.matrix.size() == 16)
- {
- NewNode->Matrix = float4x4::MakeMatrix(gltf_node.matrix.data());
- };
-
- // Node with children
- if (gltf_node.children.size() > 0)
+ {
+ auto metal_factor_it = gltf_mat.values.find("metallicFactor");
+ if (metal_factor_it != gltf_mat.values.end())
{
- for (size_t i = 0; i < gltf_node.children.size(); i++)
- {
- LoadNode(pDevice, NewNode.get(), gltf_model.nodes[gltf_node.children[i]], gltf_node.children[i], gltf_model, indexBuffer, vertexBuffer, globalscale);
- }
+ Mat.MetallicFactor = static_cast<float>(metal_factor_it->second.Factor());
}
+ }
- // Node contains mesh data
- if (gltf_node.mesh > -1)
+ {
+ auto base_col_factor_it = gltf_mat.values.find("baseColorFactor");
+ if (base_col_factor_it != gltf_mat.values.end())
{
- const tinygltf::Mesh& gltf_mesh = gltf_model.meshes[gltf_node.mesh];
- std::unique_ptr<Mesh> NewMesh(new Mesh(pDevice, NewNode->Matrix));
- for (size_t j = 0; j < gltf_mesh.primitives.size(); j++)
- {
- const tinygltf::Primitive& primitive = gltf_mesh.primitives[j];
- uint32_t indexStart = static_cast<uint32_t>(indexBuffer.size());
- uint32_t vertexStart = static_cast<uint32_t>(vertexBuffer.size());
- uint32_t indexCount = 0;
- uint32_t vertexCount = 0;
- float3 PosMin;
- float3 PosMax;
- bool hasSkin = false;
- bool hasIndices = primitive.indices > -1;
-
- // Vertices
- {
- const float* bufferPos = nullptr;
- const float* bufferNormals = nullptr;
- const float* bufferTexCoordSet0 = nullptr;
- const float* bufferTexCoordSet1 = nullptr;
- const uint16_t* bufferJoints = nullptr;
- const float* bufferWeights = nullptr;
-
- auto position_it = primitive.attributes.find("POSITION");
- VERIFY(position_it != primitive.attributes.end(), "Position attribute is required");
-
- const tinygltf::Accessor& posAccessor = gltf_model.accessors[position_it->second];
- const tinygltf::BufferView& posView = gltf_model.bufferViews[posAccessor.bufferView];
- bufferPos = reinterpret_cast<const float*>(&(gltf_model.buffers[posView.buffer].data[posAccessor.byteOffset + posView.byteOffset]));
- PosMin =
- float3
- {
- static_cast<float>(posAccessor.minValues[0]),
- static_cast<float>(posAccessor.minValues[1]),
- static_cast<float>(posAccessor.minValues[2])
- };
- PosMax =
- float3
- {
- static_cast<float>(posAccessor.maxValues[0]),
- static_cast<float>(posAccessor.maxValues[1]),
- static_cast<float>(posAccessor.maxValues[2])
- };
-
- vertexCount = static_cast<uint32_t>(posAccessor.count);
-
- if (primitive.attributes.find("NORMAL") != primitive.attributes.end())
- {
- const tinygltf::Accessor& normAccessor = gltf_model.accessors[primitive.attributes.find("NORMAL")->second];
- const tinygltf::BufferView& normView = gltf_model.bufferViews[normAccessor.bufferView];
- bufferNormals = reinterpret_cast<const float*>(&(gltf_model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset]));
- }
-
- if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end())
- {
- const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_0")->second];
- const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView];
- bufferTexCoordSet0 = reinterpret_cast<const float*>(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
- }
- if (primitive.attributes.find("TEXCOORD_1") != primitive.attributes.end())
- {
- const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_1")->second];
- const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView];
- bufferTexCoordSet1 = reinterpret_cast<const float*>(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
- }
-
- // Skinning
- // Joints
- if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end())
- {
- const tinygltf::Accessor& jointAccessor = gltf_model.accessors[primitive.attributes.find("JOINTS_0")->second];
- const tinygltf::BufferView& jointView = gltf_model.bufferViews[jointAccessor.bufferView];
- bufferJoints = reinterpret_cast<const uint16_t*>(&(gltf_model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset]));
- }
-
- if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end())
- {
- const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("WEIGHTS_0")->second];
- const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView];
- bufferWeights = reinterpret_cast<const float*>(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset]));
- }
-
- hasSkin = (bufferJoints != nullptr && bufferWeights != nullptr);
-
- for (size_t v = 0; v < posAccessor.count; v++)
- {
- Vertex vert{};
- vert.pos = float4(float3::MakeVector(&bufferPos[v * 3]), 1.0f);
- vert.normal = bufferNormals != nullptr ? normalize(float3::MakeVector(&bufferNormals[v * 3])) : float3{0,1,0};
- vert.uv0 = bufferTexCoordSet0 != nullptr ? float2::MakeVector(&bufferTexCoordSet0[v * 2]) : float2{};
- vert.uv1 = bufferTexCoordSet1 != nullptr ? float2::MakeVector(&bufferTexCoordSet1[v * 2]) : float2{};
-
- if (hasSkin)
- {
- vert.joint0 = float4::MakeVector(&bufferJoints [v * 4]);
- vert.weight0 = float4::MakeVector(&bufferWeights[v * 4]);
- }
- vertexBuffer.push_back(vert);
- }
- }
-
- // Indices
- if (hasIndices)
- {
- const tinygltf::Accessor& accessor = gltf_model.accessors[primitive.indices > -1 ? primitive.indices : 0];
- const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
- const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
-
- indexCount = static_cast<uint32_t>(accessor.count);
- const void *dataPtr = &(buffer.data[accessor.byteOffset + bufferView.byteOffset]);
-
- switch (accessor.componentType)
- {
- case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT:
- {
- const uint32_t *buf = static_cast<const uint32_t*>(dataPtr);
- for (size_t index = 0; index < accessor.count; index++)
- {
- indexBuffer.push_back(buf[index] + vertexStart);
- }
- break;
- }
- case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT:
- {
- const uint16_t *buf = static_cast<const uint16_t*>(dataPtr);
- for (size_t index = 0; index < accessor.count; index++)
- {
- indexBuffer.push_back(buf[index] + vertexStart);
- }
- break;
- }
- case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE:
- {
- const uint8_t *buf = static_cast<const uint8_t*>(dataPtr);
- for (size_t index = 0; index < accessor.count; index++)
- {
- indexBuffer.push_back(buf[index] + vertexStart);
- }
- break;
- }
- default:
- std::cerr << "Index component type " << accessor.componentType << " not supported!" << std::endl;
- return;
- }
- }
- std::unique_ptr<Primitive> newPrimitive(
- new Primitive
- {
- indexStart,
- indexCount,
- vertexCount,
- primitive.material > -1 ? Materials[primitive.material] : Materials.back()
- }
- );
-
- newPrimitive->SetBoundingBox(PosMin, PosMax);
- NewMesh->Primitives.push_back(std::move(newPrimitive));
- }
-
- // Mesh BB from BBs of primitives
- for (const auto& prim : NewMesh->Primitives)
- {
- if (prim->IsValidBB && !NewMesh->IsValidBB)
- {
- NewMesh->BB = prim->BB;
- NewMesh->IsValidBB = true;
- }
- float3 bb_min = std::min(NewMesh->BB.Min, prim->BB.Min);
- float3 bb_max = std::max(NewMesh->BB.Max, prim->BB.Max);
- NewMesh->SetBoundingBox(bb_min, bb_max);
- }
- NewNode->Mesh = std::move(NewMesh);
+ Mat.BaseColorFactor = float4::MakeVector(base_col_factor_it->second.ColorFactor().data());
}
+ }
- LinearNodes.push_back(NewNode.get());
- if (parent)
+ {
+ auto normal_tex_it = gltf_mat.additionalValues.find("normalTexture");
+ if (normal_tex_it != gltf_mat.additionalValues.end())
{
- parent->Children.push_back(std::move(NewNode));
+ Mat.pNormalTexture = Textures[normal_tex_it->second.TextureIndex()];
+ Mat.TexCoordSets.Normal = static_cast<Uint8>(normal_tex_it->second.TextureTexCoord());
}
- else
+ }
+
+ {
+ auto emssive_tex_it = gltf_mat.additionalValues.find("emissiveTexture");
+ if (emssive_tex_it != gltf_mat.additionalValues.end())
{
- Nodes.push_back(std::move(NewNode));
+ Mat.pEmissiveTexture = Textures[emssive_tex_it->second.TextureIndex()];
+ Mat.TexCoordSets.Emissive = static_cast<Uint8>(emssive_tex_it->second.TextureTexCoord());
}
}
-
- void LoadSkins(const tinygltf::Model& gltf_model)
{
- for (const auto& source : gltf_model.skins)
+ auto occlusion_tex_it = gltf_mat.additionalValues.find("occlusionTexture");
+ if (occlusion_tex_it != gltf_mat.additionalValues.end())
{
- std::unique_ptr<Skin> NewSkin( new Skin{} );
- NewSkin->Name = source.name;
-
- // Find skeleton root node
- if (source.skeleton > -1)
- {
- NewSkin->pSkeletonRoot = NodeFromIndex(source.skeleton);
- }
-
- // Find joint nodes
- for (int jointIndex : source.joints)
- {
- Node* node = NodeFromIndex(jointIndex);
- if (node)
- {
- NewSkin->Joints.push_back(NodeFromIndex(jointIndex));
- }
- }
-
- // Get inverse bind matrices from buffer
- if (source.inverseBindMatrices > -1)
- {
- const tinygltf::Accessor& accessor = gltf_model.accessors[source.inverseBindMatrices];
- const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
- const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
- NewSkin->InverseBindMatrices.resize(accessor.count);
- memcpy(NewSkin->InverseBindMatrices.data(), &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(float4x4));
- }
-
- Skins.push_back(std::move(NewSkin));
+ Mat.pOcclusionTexture = Textures[occlusion_tex_it->second.TextureIndex()];
+ Mat.TexCoordSets.Occlusion = static_cast<Uint8>(occlusion_tex_it->second.TextureTexCoord());
}
}
-
- void LoadTextures(IRenderDevice* pDevice,
- IDeviceContext* pCtx,
- const tinygltf::Model& gltf_model)
{
- for (const tinygltf::Texture& gltf_tex : gltf_model.textures)
+ auto alpha_mode_it = gltf_mat.additionalValues.find("alphaMode");
+ if (alpha_mode_it != gltf_mat.additionalValues.end())
{
- const tinygltf::Image& gltf_image = gltf_model.images[gltf_tex.source];
- RefCntAutoPtr<ISampler> pSampler;
- if (gltf_tex.sampler == -1)
+ const tinygltf::Parameter& param = alpha_mode_it->second;
+ if (param.string_value == "BLEND")
{
- // No sampler specified, use a default one
- pDevice->CreateSampler(Sam_LinearWrap, &pSampler);
+ Mat.AlphaMode = Material::ALPHAMODE_BLEND;
}
- else
+ if (param.string_value == "MASK")
{
- pSampler = TextureSamplers[gltf_tex.sampler];
+ Mat.AlphaCutoff = 0.5f;
+ Mat.AlphaMode = Material::ALPHAMODE_MASK;
}
- auto pTexture = TextureFromGLTFImage(pDevice, pCtx, gltf_image, pSampler);
- Textures.push_back(std::move(pTexture));
}
}
- TEXTURE_ADDRESS_MODE GetWrapMode(int32_t wrapMode)
{
- switch (wrapMode)
+ auto alpha_cutoff_it = gltf_mat.additionalValues.find("alphaCutoff");
+ if (alpha_cutoff_it != gltf_mat.additionalValues.end())
{
- case 10497:
- return TEXTURE_ADDRESS_WRAP;
- case 33071:
- return TEXTURE_ADDRESS_CLAMP;
- case 33648:
- return TEXTURE_ADDRESS_MIRROR;
- default:
- return TEXTURE_ADDRESS_WRAP;
+ Mat.AlphaCutoff = static_cast<float>(alpha_cutoff_it->second.Factor());
}
}
-
- FILTER_TYPE GetFilterMode(int32_t filterMode)
+
{
- switch (filterMode)
+ auto emissive_fctr_it = gltf_mat.additionalValues.find("emissiveFactor");
+ if (emissive_fctr_it != gltf_mat.additionalValues.end())
{
- case 9728:
- return FILTER_TYPE_POINT;
- case 9729:
- return FILTER_TYPE_LINEAR;
- case 9984:
- return FILTER_TYPE_POINT;
- case 9985:
- return FILTER_TYPE_POINT;
- case 9986:
- return FILTER_TYPE_LINEAR;
- case 9987:
- return FILTER_TYPE_LINEAR;
- default:
- return FILTER_TYPE_LINEAR;
+ Mat.EmissiveFactor = float4(float3::MakeVector(emissive_fctr_it->second.ColorFactor().data()), 1.0);
+ //Mat.EmissiveFactor = float4(0.0f);
}
}
- void LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model)
+ // Extensions
+ // @TODO: Find out if there is a nicer way of reading these properties with recent tinygltf headers
{
- for (const tinygltf::Sampler& smpl : gltf_model.samplers)
+ auto ext_it = gltf_mat.extensions.find("KHR_materials_pbrSpecularGlossiness");
+ if (ext_it != gltf_mat.extensions.end())
{
- SamplerDesc SamDesc;
- SamDesc.MinFilter = GetFilterMode(smpl.minFilter);
- SamDesc.MagFilter = GetFilterMode(smpl.magFilter);
- SamDesc.MipFilter = SamDesc.MagFilter;
- SamDesc.AddressU = GetWrapMode(smpl.wrapS);
- SamDesc.AddressV = GetWrapMode(smpl.wrapT);
- SamDesc.AddressW = SamDesc.AddressV;
- RefCntAutoPtr<ISampler> pSampler;
- pDevice->CreateSampler(SamDesc, &pSampler);
- TextureSamplers.push_back(std::move(pSampler));
- }
- }
-
-
- void LoadMaterials(const tinygltf::Model& gltf_model)
- {
- for (const tinygltf::Material& gltf_mat : gltf_model.materials)
- {
- Material Mat;
-
- {
- auto base_color_tex_it = gltf_mat.values.find("baseColorTexture");
- if (base_color_tex_it != gltf_mat.values.end())
- {
- Mat.pBaseColorTexture = Textures[base_color_tex_it->second.TextureIndex()];
- Mat.TexCoordSets.BaseColor = static_cast<Uint8>(base_color_tex_it->second.TextureTexCoord());
- }
- }
-
- {
- auto metal_rough_tex_it = gltf_mat.values.find("metallicRoughnessTexture");
- if (metal_rough_tex_it != gltf_mat.values.end())
- {
- Mat.pMetallicRoughnessTexture = Textures[metal_rough_tex_it->second.TextureIndex()];
- Mat.TexCoordSets.MetallicRoughness = static_cast<Uint8>(metal_rough_tex_it->second.TextureTexCoord());
- }
- }
-
- {
- auto rough_factor_it = gltf_mat.values.find("roughnessFactor");
- if (rough_factor_it != gltf_mat.values.end())
- {
- Mat.RoughnessFactor = static_cast<float>(rough_factor_it->second.Factor());
- }
- }
-
- {
- auto metal_factor_it = gltf_mat.values.find("metallicFactor");
- if (metal_factor_it != gltf_mat.values.end())
- {
- Mat.MetallicFactor = static_cast<float>(metal_factor_it->second.Factor());
- }
- }
-
+ if (ext_it->second.Has("specularGlossinessTexture"))
{
- auto base_col_factor_it = gltf_mat.values.find("baseColorFactor");
- if (base_col_factor_it != gltf_mat.values.end())
- {
- Mat.BaseColorFactor = float4::MakeVector(base_col_factor_it->second.ColorFactor().data());
- }
+ auto index = ext_it->second.Get("specularGlossinessTexture").Get("index");
+ Mat.extension.pSpecularGlossinessTexture = Textures[index.Get<int>()];
+ auto texCoordSet = ext_it->second.Get("specularGlossinessTexture").Get("texCoord");
+ Mat.TexCoordSets.SpecularGlossiness = static_cast<Uint8>(texCoordSet.Get<int>());
+ Mat.pbrWorkflows.SpecularGlossiness = true;
}
+ if (ext_it->second.Has("diffuseTexture"))
{
- auto normal_tex_it = gltf_mat.additionalValues.find("normalTexture");
- if (normal_tex_it != gltf_mat.additionalValues.end())
- {
- Mat.pNormalTexture = Textures[normal_tex_it->second.TextureIndex()];
- Mat.TexCoordSets.Normal = static_cast<Uint8>(normal_tex_it->second.TextureTexCoord());
- }
+ auto index = ext_it->second.Get("diffuseTexture").Get("index");
+ Mat.extension.pDiffuseTexture = Textures[index.Get<int>()];
}
+ if (ext_it->second.Has("diffuseFactor"))
{
- auto emssive_tex_it = gltf_mat.additionalValues.find("emissiveTexture");
- if (emssive_tex_it != gltf_mat.additionalValues.end())
+ auto factor = ext_it->second.Get("diffuseFactor");
+ for (uint32_t i = 0; i < factor.ArrayLen(); i++)
{
- Mat.pEmissiveTexture = Textures[emssive_tex_it->second.TextureIndex()];
- Mat.TexCoordSets.Emissive = static_cast<Uint8>(emssive_tex_it->second.TextureTexCoord());
+ auto val = factor.Get(i);
+ Mat.extension.DiffuseFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
}
}
+ if (ext_it->second.Has("specularFactor"))
{
- auto occlusion_tex_it = gltf_mat.additionalValues.find("occlusionTexture");
- if (occlusion_tex_it != gltf_mat.additionalValues.end())
+ auto factor = ext_it->second.Get("specularFactor");
+ for (uint32_t i = 0; i < factor.ArrayLen(); i++)
{
- Mat.pOcclusionTexture = Textures[occlusion_tex_it->second.TextureIndex()];
- Mat.TexCoordSets.Occlusion = static_cast<Uint8>(occlusion_tex_it->second.TextureTexCoord());
- }
- }
-
- {
- auto alpha_mode_it = gltf_mat.additionalValues.find("alphaMode");
- if (alpha_mode_it != gltf_mat.additionalValues.end())
- {
- const tinygltf::Parameter& param = alpha_mode_it->second;
- if (param.string_value == "BLEND")
- {
- Mat.AlphaMode = Material::ALPHAMODE_BLEND;
- }
- if (param.string_value == "MASK")
- {
- Mat.AlphaCutoff = 0.5f;
- Mat.AlphaMode = Material::ALPHAMODE_MASK;
- }
+ auto val = factor.Get(i);
+ Mat.extension.SpecularFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
}
}
+ }
+ }
- {
- auto alpha_cutoff_it = gltf_mat.additionalValues.find("alphaCutoff");
- if (alpha_cutoff_it != gltf_mat.additionalValues.end())
- {
- Mat.AlphaCutoff = static_cast<float>(alpha_cutoff_it->second.Factor());
- }
- }
-
- {
- auto emissive_fctr_it = gltf_mat.additionalValues.find("emissiveFactor");
- if (emissive_fctr_it != gltf_mat.additionalValues.end())
- {
- Mat.EmissiveFactor = float4(float3::MakeVector(emissive_fctr_it->second.ColorFactor().data()), 1.0);
- //Mat.EmissiveFactor = float4(0.0f);
- }
- }
+ Materials.push_back(Mat);
+ }
- // Extensions
- // @TODO: Find out if there is a nicer way of reading these properties with recent tinygltf headers
- {
- auto ext_it = gltf_mat.extensions.find("KHR_materials_pbrSpecularGlossiness");
- if (ext_it != gltf_mat.extensions.end())
- {
- if (ext_it->second.Has("specularGlossinessTexture"))
- {
- auto index = ext_it->second.Get("specularGlossinessTexture").Get("index");
- Mat.extension.pSpecularGlossinessTexture = Textures[index.Get<int>()];
- auto texCoordSet = ext_it->second.Get("specularGlossinessTexture").Get("texCoord");
- Mat.TexCoordSets.SpecularGlossiness = static_cast<Uint8>(texCoordSet.Get<int>());
- Mat.pbrWorkflows.SpecularGlossiness = true;
- }
+ // Push a default material at the end of the list for meshes with no material assigned
+ Materials.push_back(Material{});
+}
- if (ext_it->second.Has("diffuseTexture"))
- {
- auto index = ext_it->second.Get("diffuseTexture").Get("index");
- Mat.extension.pDiffuseTexture = Textures[index.Get<int>()];
- }
- if (ext_it->second.Has("diffuseFactor"))
- {
- auto factor = ext_it->second.Get("diffuseFactor");
- for (uint32_t i = 0; i < factor.ArrayLen(); i++)
- {
- auto val = factor.Get(i);
- Mat.extension.DiffuseFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
- }
- }
+void Model::loadAnimations(const tinygltf::Model& gltf_model)
+{
+ for (const tinygltf::Animation& gltf_anim : gltf_model.animations)
+ {
+ Animation animation{};
+ animation.Name = gltf_anim.name;
+ if (gltf_anim.name.empty())
+ {
+ animation.Name = std::to_string(Animations.size());
+ }
- if (ext_it->second.Has("specularFactor"))
- {
- auto factor = ext_it->second.Get("specularFactor");
- for (uint32_t i = 0; i < factor.ArrayLen(); i++)
- {
- auto val = factor.Get(i);
- Mat.extension.SpecularFactor[i] = val.IsNumber() ? (float)val.Get<double>() : (float)val.Get<int>();
- }
- }
- }
- }
+ // Samplers
+ for (auto &samp : gltf_anim.samplers)
+ {
+ AnimationSampler AnimSampler{};
- Materials.push_back(Mat);
+ if (samp.interpolation == "LINEAR")
+ {
+ AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::LINEAR;
+ }
+ else if (samp.interpolation == "STEP")
+ {
+ AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::STEP;
+ }
+ else if (samp.interpolation == "CUBICSPLINE")
+ {
+ AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::CUBICSPLINE;
}
- // Push a default material at the end of the list for meshes with no material assigned
- Materials.push_back(Material{});
- }
+ // Read sampler input time values
+ {
+ const tinygltf::Accessor& accessor = gltf_model.accessors[samp.input];
+ const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
+ const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
+ VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
- void loadAnimations(const tinygltf::Model& gltf_model)
- {
- for (const tinygltf::Animation& gltf_anim : gltf_model.animations)
- {
- Animation animation{};
- animation.Name = gltf_anim.name;
- if (gltf_anim.name.empty())
+ const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
+ const float *buf = static_cast<const float*>(dataPtr);
+ for (size_t index = 0; index < accessor.count; index++)
{
- animation.Name = std::to_string(Animations.size());
+ AnimSampler.Inputs.push_back(buf[index]);
}
- // Samplers
- for (auto &samp : gltf_anim.samplers)
+ for (auto input : AnimSampler.Inputs)
{
- AnimationSampler AnimSampler{};
-
- if (samp.interpolation == "LINEAR")
- {
- AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::LINEAR;
- }
- else if (samp.interpolation == "STEP")
+ if (input < animation.Start)
{
- AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::STEP;
+ animation.Start = input;
}
- else if (samp.interpolation == "CUBICSPLINE")
+ if (input > animation.End)
{
- AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::CUBICSPLINE;
+ animation.End = input;
}
+ }
+ }
- // Read sampler input time values
- {
- const tinygltf::Accessor& accessor = gltf_model.accessors[samp.input];
- const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
- const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
+ // Read sampler output T/R/S values
+ {
+ const tinygltf::Accessor& accessor = gltf_model.accessors[samp.output];
+ const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
+ const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
- VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
+ VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
- const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
- const float *buf = static_cast<const float*>(dataPtr);
- for (size_t index = 0; index < accessor.count; index++)
- {
- AnimSampler.Inputs.push_back(buf[index]);
- }
+ const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
- for (auto input : AnimSampler.Inputs)
+ switch (accessor.type)
+ {
+ case TINYGLTF_TYPE_VEC3:
+ {
+ const float3* buf = static_cast<const float3*>(dataPtr);
+ for (size_t index = 0; index < accessor.count; index++)
{
- if (input < animation.Start)
- {
- animation.Start = input;
- }
- if (input > animation.End)
- {
- animation.End = input;
- }
+ AnimSampler.OutputsVec4.push_back(float4(buf[index], 0.0f));
}
+ break;
}
- // Read sampler output T/R/S values
+ case TINYGLTF_TYPE_VEC4:
{
- const tinygltf::Accessor& accessor = gltf_model.accessors[samp.output];
- const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView];
- const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer];
-
- VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
-
- const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
-
- switch (accessor.type)
+ const float4* buf = static_cast<const float4*>(dataPtr);
+ for (size_t index = 0; index < accessor.count; index++)
{
- case TINYGLTF_TYPE_VEC3:
- {
- const float3* buf = static_cast<const float3*>(dataPtr);
- for (size_t index = 0; index < accessor.count; index++)
- {
- AnimSampler.OutputsVec4.push_back(float4(buf[index], 0.0f));
- }
- break;
- }
-
- case TINYGLTF_TYPE_VEC4:
- {
- const float4* buf = static_cast<const float4*>(dataPtr);
- for (size_t index = 0; index < accessor.count; index++)
- {
- AnimSampler.OutputsVec4.push_back(buf[index]);
- }
- break;
- }
-
- default:
- {
- LOG_WARNING_MESSAGE("Unknown type", accessor.type);
- break;
- }
+ AnimSampler.OutputsVec4.push_back(buf[index]);
}
+ break;
}
- animation.Samplers.push_back(AnimSampler);
- }
-
-
- for (auto& source : gltf_anim.channels)
- {
- AnimationChannel channel{};
-
- if (source.target_path == "rotation")
- {
- channel.PathType = AnimationChannel::PATH_TYPE::ROTATION;
- }
- else if (source.target_path == "translation")
- {
- channel.PathType = AnimationChannel::PATH_TYPE::TRANSLATION;
- }
- else if (source.target_path == "scale")
+ default:
{
- channel.PathType = AnimationChannel::PATH_TYPE::SCALE;
+ LOG_WARNING_MESSAGE("Unknown type", accessor.type);
+ break;
}
- else if (source.target_path == "weights")
- {
- LOG_WARNING_MESSAGE("Weights not yet supported, skipping channel");
- continue;
- }
-
- channel.SamplerIndex = source.sampler;
- channel.node = NodeFromIndex(source.target_node);
- if (!channel.node)
- {
- continue;
- }
-
- animation.Channels.push_back(channel);
}
-
- Animations.push_back(animation);
}
+
+ animation.Samplers.push_back(AnimSampler);
}
- void loadFromFile(IRenderDevice* pDevice, IDeviceContext* pContext, std::string filename, float scale = 1.0f)
+ for (auto& source : gltf_anim.channels)
{
- tinygltf::Model gltf_model;
- tinygltf::TinyGLTF gltf_context;
- std::string error;
- std::string warning;
-
- bool binary = false;
- size_t extpos = filename.rfind('.', filename.length());
- if (extpos != std::string::npos)
+ AnimationChannel channel{};
+
+ if (source.target_path == "rotation")
{
- binary = (filename.substr(extpos + 1, filename.length() - extpos) == "glb");
- }
-
- bool fileLoaded;
- if (binary)
- fileLoaded = gltf_context.LoadBinaryFromFile(&gltf_model, &error, &warning, filename.c_str());
- else
- fileLoaded = gltf_context.LoadASCIIFromFile(&gltf_model, &error, &warning, filename.c_str());
- if (!fileLoaded)
+ channel.PathType = AnimationChannel::PATH_TYPE::ROTATION;
+ }
+ else if (source.target_path == "translation")
{
- LOG_ERROR_AND_THROW("Failed to load gltf file");
+ channel.PathType = AnimationChannel::PATH_TYPE::TRANSLATION;
}
-
- std::vector<Uint32> IndexBuffer;
- std::vector<Vertex> VertexBuffer;
-
- LoadTextureSamplers(pDevice, gltf_model);
- LoadTextures(pDevice, pContext, gltf_model);
- LoadMaterials(gltf_model);
-
- // TODO: scene handling with no default scene
- const tinygltf::Scene& scene = gltf_model.scenes[gltf_model.defaultScene > -1 ? gltf_model.defaultScene : 0];
- for (size_t i = 0; i < scene.nodes.size(); i++)
+ else if (source.target_path == "scale")
{
- const tinygltf::Node node = gltf_model.nodes[scene.nodes[i]];
- LoadNode(pDevice, nullptr, node, scene.nodes[i], gltf_model, IndexBuffer, VertexBuffer, scale);
+ channel.PathType = AnimationChannel::PATH_TYPE::SCALE;
}
-
- if (gltf_model.animations.size() > 0)
+ else if (source.target_path == "weights")
{
- loadAnimations(gltf_model);
+ LOG_WARNING_MESSAGE("Weights not yet supported, skipping channel");
+ continue;
}
- LoadSkins(gltf_model);
- for (auto* node : LinearNodes)
+ channel.SamplerIndex = source.sampler;
+ channel.node = NodeFromIndex(source.target_node);
+ if (!channel.node)
{
- // Assign skins
- if (node->SkinIndex > -1)
- {
- node->Skin = Skins[node->SkinIndex].get();
- }
-
- // Initial pose
- if (node->Mesh)
- {
- node->Update(pContext);
- }
+ continue;
}
+ animation.Channels.push_back(channel);
+ }
- Extensions = gltf_model.extensionsUsed;
+ Animations.push_back(animation);
+ }
+}
- size_t vertexBufferSize = VertexBuffer.size() * sizeof(Vertex);
- size_t indexBufferSize = IndexBuffer.size() * sizeof(Uint32);
- IndexCount = static_cast<Uint32>(IndexBuffer.size());
- VERIFY_EXPR(vertexBufferSize > 0);
+void Model::loadFromFile(IRenderDevice* pDevice, IDeviceContext* pContext, std::string filename, float scale)
+{
+ tinygltf::Model gltf_model;
+ tinygltf::TinyGLTF gltf_context;
+ std::string error;
+ std::string warning;
+
+ bool binary = false;
+ size_t extpos = filename.rfind('.', filename.length());
+ if (extpos != std::string::npos)
+ {
+ binary = (filename.substr(extpos + 1, filename.length() - extpos) == "glb");
+ }
+
+ bool fileLoaded;
+ if (binary)
+ fileLoaded = gltf_context.LoadBinaryFromFile(&gltf_model, &error, &warning, filename.c_str());
+ else
+ fileLoaded = gltf_context.LoadASCIIFromFile(&gltf_model, &error, &warning, filename.c_str());
+ if (!fileLoaded)
+ {
+ LOG_ERROR_AND_THROW("Failed to load gltf file");
+ }
- {
- BufferDesc VBDesc;
- VBDesc.Name = "GLTF vertex buffer";
- VBDesc.uiSizeInBytes = static_cast<Uint32>(vertexBufferSize);
- VBDesc.BindFlags = BIND_UNIFORM_BUFFER;
- VBDesc.Usage = USAGE_STATIC;
-
- BufferData BuffData(VertexBuffer.data(), static_cast<Uint32>(vertexBufferSize));
- pDevice->CreateBuffer(VBDesc, &BuffData, &pVertexBuffer);
- }
+ std::vector<Uint32> IndexBuffer;
+ std::vector<Vertex> VertexBuffer;
- if (indexBufferSize > 0)
- {
- BufferDesc IBDesc;
- IBDesc.Name = "GLTF inde buffer";
- IBDesc.uiSizeInBytes = static_cast<Uint32>(vertexBufferSize);
- IBDesc.BindFlags = BIND_UNIFORM_BUFFER;
- IBDesc.Usage = USAGE_STATIC;
-
- BufferData BuffData(IndexBuffer.data(), static_cast<Uint32>(indexBufferSize));
- pDevice->CreateBuffer(IBDesc, &BuffData, &pIndexBuffer);
- }
+ LoadTextureSamplers(pDevice, gltf_model);
+ LoadTextures(pDevice, pContext, gltf_model);
+ LoadMaterials(gltf_model);
- GetSceneDimensions();
- }
+ // TODO: scene handling with no default scene
+ const tinygltf::Scene& scene = gltf_model.scenes[gltf_model.defaultScene > -1 ? gltf_model.defaultScene : 0];
+ for (size_t i = 0; i < scene.nodes.size(); i++)
+ {
+ const tinygltf::Node node = gltf_model.nodes[scene.nodes[i]];
+ LoadNode(pDevice, nullptr, node, scene.nodes[i], gltf_model, IndexBuffer, VertexBuffer, scale);
+ }
+ if (gltf_model.animations.size() > 0)
+ {
+ loadAnimations(gltf_model);
+ }
+ LoadSkins(gltf_model);
- void DrawNode(IDeviceContext* pCtx, const Node* node)
+ for (auto* node : LinearNodes)
+ {
+ // Assign skins
+ if (node->SkinIndex > -1)
{
- if (node->Mesh)
- {
- for (const auto& primitive : node->Mesh->Primitives)
- {
- DrawAttribs Attribs(primitive->IndexCount, VT_UINT32, DRAW_FLAG_VERIFY_ALL);
- Attribs.FirstIndexLocation = primitive->FirstIndex;
- pCtx->Draw(Attribs);
- }
- }
-
- for (const auto& child : node->Children)
- {
- DrawNode(pCtx, child.get());
- }
+ node->Skin = Skins[node->SkinIndex].get();
}
-
- void Draw(IDeviceContext* pCtx)
+ // Initial pose
+ if (node->Mesh)
{
- IBuffer* pVertBuffers[] = {pVertexBuffer};
- Uint32 Offsets [] = {0};
- pCtx->SetVertexBuffers(0, 1, pVertBuffers, Offsets, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET);
- pCtx->SetIndexBuffer(pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
- for (const auto& node : Nodes)
- {
- DrawNode(pCtx, node.get());
- }
+ node->Update(pContext);
}
+ }
+ Extensions = gltf_model.extensionsUsed;
- BoundBox GetAABB(const BoundBox& bb, const float4x4& m)
- {
- float3 min = float3::MakeVector(m[3]);
- float3 max = min;
- float3 v0, v1;
+ size_t vertexBufferSize = VertexBuffer.size() * sizeof(Vertex);
+ size_t indexBufferSize = IndexBuffer.size() * sizeof(Uint32);
+ IndexCount = static_cast<Uint32>(IndexBuffer.size());
+
+ VERIFY_EXPR(vertexBufferSize > 0);
+
+ {
+ BufferDesc VBDesc;
+ VBDesc.Name = "GLTF vertex buffer";
+ VBDesc.uiSizeInBytes = static_cast<Uint32>(vertexBufferSize);
+ VBDesc.BindFlags = BIND_UNIFORM_BUFFER;
+ VBDesc.Usage = USAGE_STATIC;
- float3 right = float3::MakeVector(m[0]);
- v0 = right * bb.Min.x;
- v1 = right * bb.Max.x;
- min += std::min(v0, v1);
- max += std::max(v0, v1);
-
- float3 up = float3::MakeVector(m[1]);
- v0 = up * bb.Min.y;
- v1 = up * bb.Max.y;
- min += std::min(v0, v1);
- max += std::max(v0, v1);
-
- float3 back = float3::MakeVector(m[2]);
- v0 = back * bb.Min.z;
- v1 = back * bb.Max.z;
- min += std::min(v0, v1);
- max += std::max(v0, v1);
-
- return BoundBox{min, max};
- }
+ BufferData BuffData(VertexBuffer.data(), static_cast<Uint32>(vertexBufferSize));
+ pDevice->CreateBuffer(VBDesc, &BuffData, &pVertexBuffer);
+ }
- void CalculateBoundingBox(Node* node, const Node* parent)
- {
- BoundBox parentBvh = parent ? parent->BVH : BoundBox{dimensions.min, dimensions.max};
+ if (indexBufferSize > 0)
+ {
+ BufferDesc IBDesc;
+ IBDesc.Name = "GLTF inde buffer";
+ IBDesc.uiSizeInBytes = static_cast<Uint32>(vertexBufferSize);
+ IBDesc.BindFlags = BIND_UNIFORM_BUFFER;
+ IBDesc.Usage = USAGE_STATIC;
+
+ BufferData BuffData(IndexBuffer.data(), static_cast<Uint32>(indexBufferSize));
+ pDevice->CreateBuffer(IBDesc, &BuffData, &pIndexBuffer);
+ }
- if (node->Mesh)
- {
- if (node->Mesh->IsValidBB)
- {
- node->AABB = GetAABB(node->Mesh->BB, node->GetMatrix());
- if (node->Children.empty())
- {
- node->BVH.Min = node->AABB.Min;
- node->BVH.Max = node->AABB.Max;
- node->IsValidBVH = true;
- }
- }
- }
+ GetSceneDimensions();
+}
- parentBvh.Min = std::min(parentBvh.Min, node->BVH.Min);
- parentBvh.Max = std::min(parentBvh.Max, node->BVH.Max);
- for (auto& child : node->Children)
- {
- CalculateBoundingBox(child.get(), node);
- }
+void Model::DrawNode(IDeviceContext* pCtx, const Node* node)
+{
+ if (node->Mesh)
+ {
+ for (const auto& primitive : node->Mesh->Primitives)
+ {
+ DrawAttribs Attribs(primitive->IndexCount, VT_UINT32, DRAW_FLAG_VERIFY_ALL);
+ Attribs.FirstIndexLocation = primitive->FirstIndex;
+ pCtx->Draw(Attribs);
}
+ }
+
+ for (const auto& child : node->Children)
+ {
+ DrawNode(pCtx, child.get());
+ }
+}
+
+
+void Model::Draw(IDeviceContext* pCtx)
+{
+ IBuffer* pVertBuffers[] = {pVertexBuffer};
+ Uint32 Offsets [] = {0};
+ pCtx->SetVertexBuffers(0, 1, pVertBuffers, Offsets, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET);
+ pCtx->SetIndexBuffer(pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
+ for (const auto& node : Nodes)
+ {
+ DrawNode(pCtx, node.get());
+ }
+}
- void GetSceneDimensions()
+
+namespace
+{
+
+BoundBox GetAABB(const BoundBox& bb, const float4x4& m)
+{
+ float3 min = float3::MakeVector(m[3]);
+ float3 max = min;
+ float3 v0, v1;
+
+ float3 right = float3::MakeVector(m[0]);
+ v0 = right * bb.Min.x;
+ v1 = right * bb.Max.x;
+ min += std::min(v0, v1);
+ max += std::max(v0, v1);
+
+ float3 up = float3::MakeVector(m[1]);
+ v0 = up * bb.Min.y;
+ v1 = up * bb.Max.y;
+ min += std::min(v0, v1);
+ max += std::max(v0, v1);
+
+ float3 back = float3::MakeVector(m[2]);
+ v0 = back * bb.Min.z;
+ v1 = back * bb.Max.z;
+ min += std::min(v0, v1);
+ max += std::max(v0, v1);
+
+ return BoundBox{min, max};
+}
+
+}
+
+void Model::CalculateBoundingBox(Node* node, const Node* parent)
+{
+ BoundBox parentBvh = parent ? parent->BVH : BoundBox{dimensions.min, dimensions.max};
+
+ if (node->Mesh)
+ {
+ if (node->Mesh->IsValidBB)
{
- // Calculate binary volume hierarchy for all nodes in the scene
- for (auto* node : LinearNodes)
+ node->AABB = GetAABB(node->Mesh->BB, node->GetMatrix());
+ if (node->Children.empty())
{
- CalculateBoundingBox(node, nullptr);
+ node->BVH.Min = node->AABB.Min;
+ node->BVH.Max = node->AABB.Max;
+ node->IsValidBVH = true;
}
+ }
+ }
- dimensions.min = float3(+FLT_MAX, +FLT_MAX, +FLT_MAX);
- dimensions.max = float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+ parentBvh.Min = std::min(parentBvh.Min, node->BVH.Min);
+ parentBvh.Max = std::min(parentBvh.Max, node->BVH.Max);
- for (const auto* node : LinearNodes)
- {
- if (node->IsValidBVH)
- {
- dimensions.min = std::min(dimensions.min, node->BVH.Min);
- dimensions.max = std::max(dimensions.max, node->BVH.Max);
- }
- }
+ for (auto& child : node->Children)
+ {
+ CalculateBoundingBox(child.get(), node);
+ }
+}
+
+void Model::GetSceneDimensions()
+{
+ // Calculate binary volume hierarchy for all nodes in the scene
+ for (auto* node : LinearNodes)
+ {
+ CalculateBoundingBox(node, nullptr);
+ }
- // Calculate scene aabb
- aabb = float4x4::Scale(dimensions.max[0] - dimensions.min[0], dimensions.max[1] - dimensions.min[1], dimensions.max[2] - dimensions.min[2]);
- aabb[3][0] = dimensions.min[0];
- aabb[3][1] = dimensions.min[1];
- aabb[3][2] = dimensions.min[2];
+ dimensions.min = float3(+FLT_MAX, +FLT_MAX, +FLT_MAX);
+ dimensions.max = float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+
+ for (const auto* node : LinearNodes)
+ {
+ if (node->IsValidBVH)
+ {
+ dimensions.min = std::min(dimensions.min, node->BVH.Min);
+ dimensions.max = std::max(dimensions.max, node->BVH.Max);
}
+ }
+
+ // Calculate scene aabb
+ aabb = float4x4::Scale(dimensions.max[0] - dimensions.min[0], dimensions.max[1] - dimensions.min[1], dimensions.max[2] - dimensions.min[2]);
+ aabb[3][0] = dimensions.min[0];
+ aabb[3][1] = dimensions.min[1];
+ aabb[3][2] = dimensions.min[2];
+}
+
+void Model::UpdateAnimation(IDeviceContext* pContext, Uint32 index, float time)
+{
+ if (index > static_cast<Uint32>(Animations.size()) - 1)
+ {
+ LOG_WARNING_MESSAGE("No animation with index ", index);
+ return;
+ }
+ Animation& animation = Animations[index];
- void UpdateAnimation(IDeviceContext* pContext, Uint32 index, float time)
+ bool updated = false;
+ for (auto& channel : animation.Channels)
+ {
+ AnimationSampler& sampler = animation.Samplers[channel.SamplerIndex];
+ if (sampler.Inputs.size() > sampler.OutputsVec4.size())
{
- if (index > static_cast<Uint32>(Animations.size()) - 1)
- {
- LOG_WARNING_MESSAGE("No animation with index ", index);
- return;
- }
- Animation& animation = Animations[index];
+ continue;
+ }
- bool updated = false;
- for (auto& channel : animation.Channels)
+ for (size_t i = 0; i < sampler.Inputs.size() - 1; i++)
+ {
+ if ((time >= sampler.Inputs[i]) && (time <= sampler.Inputs[i + 1]))
{
- AnimationSampler& sampler = animation.Samplers[channel.SamplerIndex];
- if (sampler.Inputs.size() > sampler.OutputsVec4.size())
- {
- continue;
- }
-
- for (size_t i = 0; i < sampler.Inputs.size() - 1; i++)
+ float u = std::max(0.0f, time - sampler.Inputs[i]) / (sampler.Inputs[i + 1] - sampler.Inputs[i]);
+ if (u <= 1.0f)
{
- if ((time >= sampler.Inputs[i]) && (time <= sampler.Inputs[i + 1]))
+ switch (channel.PathType)
{
- float u = std::max(0.0f, time - sampler.Inputs[i]) / (sampler.Inputs[i + 1] - sampler.Inputs[i]);
- if (u <= 1.0f)
+ case AnimationChannel::PATH_TYPE::TRANSLATION:
{
- switch (channel.PathType)
- {
- case AnimationChannel::PATH_TYPE::TRANSLATION:
- {
- float4 trans = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u);
- channel.node->Translation = float3(trans);
- break;
- }
-
- case AnimationChannel::PATH_TYPE::SCALE:
- {
- float4 scale = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u);
- channel.node->Scale = float3(scale);
- break;
- }
-
- case AnimationChannel::PATH_TYPE::ROTATION:
- {
- Quaternion q1;
- q1.q.x = sampler.OutputsVec4[i].x;
- q1.q.y = sampler.OutputsVec4[i].y;
- q1.q.z = sampler.OutputsVec4[i].z;
- q1.q.w = sampler.OutputsVec4[i].w;
-
- Quaternion q2;
- q2.q.x = sampler.OutputsVec4[i + 1].x;
- q2.q.y = sampler.OutputsVec4[i + 1].y;
- q2.q.z = sampler.OutputsVec4[i + 1].z;
- q2.q.w = sampler.OutputsVec4[i + 1].w;
- channel.node->Rotation = normalize(slerp(q1, q2, u));
- break;
- }
- }
- updated = true;
+ float4 trans = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u);
+ channel.node->Translation = float3(trans);
+ break;
+ }
+
+ case AnimationChannel::PATH_TYPE::SCALE:
+ {
+ float4 scale = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u);
+ channel.node->Scale = float3(scale);
+ break;
+ }
+
+ case AnimationChannel::PATH_TYPE::ROTATION:
+ {
+ Quaternion q1;
+ q1.q.x = sampler.OutputsVec4[i].x;
+ q1.q.y = sampler.OutputsVec4[i].y;
+ q1.q.z = sampler.OutputsVec4[i].z;
+ q1.q.w = sampler.OutputsVec4[i].w;
+
+ Quaternion q2;
+ q2.q.x = sampler.OutputsVec4[i + 1].x;
+ q2.q.y = sampler.OutputsVec4[i + 1].y;
+ q2.q.z = sampler.OutputsVec4[i + 1].z;
+ q2.q.w = sampler.OutputsVec4[i + 1].w;
+ channel.node->Rotation = normalize(slerp(q1, q2, u));
+ break;
}
}
+ updated = true;
}
}
+ }
+ }
- if (updated)
- {
- for (auto& node : Nodes)
- {
- node->Update(pContext);
- }
- }
+ if (updated)
+ {
+ for (auto& node : Nodes)
+ {
+ node->Update(pContext);
}
+ }
+}
- Node* FindNode(Node* parent, Uint32 index)
+Node* Model::FindNode(Node* parent, Uint32 index)
+{
+ Node* nodeFound = nullptr;
+ if (parent->Index == index)
+ {
+ return parent;
+ }
+ for (auto& child : parent->Children)
+ {
+ nodeFound = FindNode(child.get(), index);
+ if (nodeFound)
{
- Node* nodeFound = nullptr;
- if (parent->Index == index)
- {
- return parent;
- }
- for (auto& child : parent->Children)
- {
- nodeFound = FindNode(child.get(), index);
- if (nodeFound)
- {
- break;
- }
- }
- return nodeFound;
+ break;
}
+ }
+ return nodeFound;
+}
- Node* NodeFromIndex(uint32_t index)
+Node* Model::NodeFromIndex(uint32_t index)
+{
+ Node* nodeFound = nullptr;
+ for (auto &node : Nodes)
+ {
+ nodeFound = FindNode(node.get(), index);
+ if (nodeFound)
{
- Node* nodeFound = nullptr;
- for (auto &node : Nodes)
- {
- nodeFound = FindNode(node.get(), index);
- if (nodeFound)
- {
- break;
- }
- }
- return nodeFound;
+ break;
}
- };
+ }
+ return nodeFound;
+}
+
}