summaryrefslogtreecommitdiffstats
path: root/AssetLoader/include
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2021-03-27 09:12:40 +0000
committers-ol <s+removethis@s-ol.nu>2021-03-30 14:37:36 +0000
commit1b66dcfa8bd1f2deddb3e406653a3553c5549bf5 (patch)
treef29514aa4b05bad3a6ab1949549b2831102d28fd /AssetLoader/include
parentGLTF Loader: fixed default alpha channel value of 3-component textures (diff)
downloadDiligentTools-1b66dcfa8bd1f2deddb3e406653a3553c5549bf5.tar.gz
DiligentTools-1b66dcfa8bd1f2deddb3e406653a3553c5549bf5.zip
C API for GLTFLoader
Diffstat (limited to 'AssetLoader/include')
-rw-r--r--AssetLoader/include/GLTFLoader.hpp442
-rw-r--r--AssetLoader/include/GLTFResourceManager.hpp161
2 files changed, 603 insertions, 0 deletions
diff --git a/AssetLoader/include/GLTFLoader.hpp b/AssetLoader/include/GLTFLoader.hpp
new file mode 100644
index 0000000..83b9a4d
--- /dev/null
+++ b/AssetLoader/include/GLTFLoader.hpp
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+#include <vector>
+#include <array>
+#include <memory>
+#include <cfloat>
+#include <unordered_map>
+#include <mutex>
+#include <atomic>
+
+#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h"
+#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h"
+#include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp"
+#include "../../../DiligentCore/Common/interface/AdvancedMath.hpp"
+#include "GLTFLoader.h"
+#include "GLTFResourceManager.hpp"
+
+namespace tinygltf
+{
+
+class Node;
+class Model;
+
+} // namespace tinygltf
+
+namespace Diligent
+{
+
+namespace GLTF
+{
+
+struct Material
+{
+ Material() noexcept
+ {
+ TextureIds.fill(-1);
+ }
+
+ enum PBR_WORKFLOW
+ {
+ PBR_WORKFLOW_METALL_ROUGH = 0,
+ PBR_WORKFLOW_SPEC_GLOSS
+ };
+
+ // Material attributes packed in a shader-friendly format
+ struct ShaderAttribs
+ {
+ float4 BaseColorFactor = float4{1, 1, 1, 1};
+ float4 EmissiveFactor = float4{1, 1, 1, 1};
+ float4 SpecularFactor = float4{1, 1, 1, 1};
+
+ int Workflow = PBR_WORKFLOW_METALL_ROUGH;
+ float BaseColorUVSelector = -1;
+ float PhysicalDescriptorUVSelector = -1;
+ float NormalUVSelector = -1;
+
+ float OcclusionUVSelector = -1;
+ float EmissiveUVSelector = -1;
+ float BaseColorSlice = 0;
+ float PhysicalDescriptorSlice = 0;
+
+ float NormalSlice = 0;
+ float OcclusionSlice = 0;
+ float EmissiveSlice = 0;
+ float MetallicFactor = 1;
+
+ float RoughnessFactor = 1;
+ int AlphaMode = GLTF_MAT_ALPHA_MODE_OPAQUE;
+ float AlphaCutoff = 0.5f;
+ float Dummy0;
+
+ // When texture atlas is used, UV scale and bias applied to
+ // each texture coordinate set
+ float4 BaseColorUVScaleBias = float4{1, 1, 0, 0};
+ float4 PhysicalDescriptorUVScaleBias = float4{1, 1, 0, 0};
+ float4 NormalUVScaleBias = float4{1, 1, 0, 0};
+ float4 OcclusionUVScaleBias = float4{1, 1, 0, 0};
+ float4 EmissiveUVScaleBias = float4{1, 1, 0, 0};
+ };
+ static_assert(sizeof(ShaderAttribs) % 16 == 0, "ShaderAttribs struct must be 16-byte aligned");
+ ShaderAttribs Attribs;
+
+ bool DoubleSided = false;
+
+ enum TEXTURE_ID
+ {
+ // Base color for metallic-roughness workflow or
+ // diffuse color for specular-glossinees workflow
+ TEXTURE_ID_BASE_COLOR = 0,
+
+ // Metallic-roughness or specular-glossinees map
+ TEXTURE_ID_PHYSICAL_DESC,
+
+ TEXTURE_ID_NORMAL_MAP,
+ TEXTURE_ID_OCCLUSION,
+ TEXTURE_ID_EMISSIVE,
+ TEXTURE_ID_NUM_TEXTURES
+ };
+ // Texture indices in Model.Textures array
+ std::array<int, TEXTURE_ID_NUM_TEXTURES> TextureIds = {};
+};
+
+
+struct Primitive
+{
+ const Uint32 FirstIndex;
+ const Uint32 IndexCount;
+ const Uint32 VertexCount;
+ const Uint32 MaterialId;
+
+ const BoundBox BB;
+
+ Primitive(Uint32 _FirstIndex,
+ Uint32 _IndexCount,
+ Uint32 _VertexCount,
+ Uint32 _MaterialId,
+ const float3& BBMin,
+ const float3& BBMax) :
+ FirstIndex{_FirstIndex},
+ IndexCount{_IndexCount},
+ VertexCount{_VertexCount},
+ MaterialId{_MaterialId},
+ BB{BBMin, BBMax}
+ {
+ }
+
+ Primitive(Primitive&&) = default;
+
+ bool HasIndices() const
+ {
+ return IndexCount > 0;
+ }
+};
+
+
+
+struct Mesh
+{
+ std::vector<Primitive> Primitives;
+
+ BoundBox BB;
+
+ // There may be no primitives in the mesh, in which
+ // case the bounding box will be invalid.
+ bool IsValidBB() const
+ {
+ return !Primitives.empty();
+ }
+
+ struct TransformData
+ {
+ float4x4 matrix;
+ std::vector<float4x4> jointMatrices;
+ };
+
+ TransformData Transforms;
+
+ Mesh(const float4x4& matrix);
+};
+
+
+struct Node;
+struct Skin
+{
+ std::string Name;
+ Node* pSkeletonRoot = nullptr;
+ std::vector<float4x4> InverseBindMatrices;
+ std::vector<Node*> Joints;
+};
+
+struct Camera
+{
+ enum class Projection
+ {
+ Unknown,
+ Perspective,
+ Orthographic
+ } Type = Projection::Unknown;
+
+ std::string Name;
+
+ struct PerspectiveAttribs
+ {
+ float AspectRatio;
+ float YFov;
+ float ZNear;
+ float ZFar;
+ };
+ struct OrthographicAttribs
+ {
+ float XMag;
+ float YMag;
+ float ZNear;
+ float ZFar;
+ };
+ union
+ {
+ PerspectiveAttribs Perspective = {};
+ OrthographicAttribs Orthographic;
+ };
+
+ float4x4 matrix;
+};
+
+struct Node
+{
+ std::string Name;
+ Node* Parent = nullptr;
+ Uint32 Index;
+
+ std::vector<std::unique_ptr<Node>> Children;
+
+ float4x4 Matrix;
+ std::unique_ptr<Mesh> pMesh;
+ std::unique_ptr<Camera> pCamera;
+ Skin* pSkin = nullptr;
+ Int32 SkinIndex = -1;
+ float3 Translation;
+ float3 Scale = float3{1, 1, 1};
+ Quaternion Rotation;
+ BoundBox BVH;
+ BoundBox AABB;
+
+ bool IsValidBVH = false;
+
+ float4x4 LocalMatrix() const;
+ float4x4 GetMatrix() const;
+ void UpdateTransforms();
+};
+
+
+struct AnimationChannel
+{
+ enum PATH_TYPE
+ {
+ TRANSLATION,
+ ROTATION,
+ SCALE
+ };
+ PATH_TYPE PathType;
+ Node* pNode = nullptr;
+ Uint32 SamplerIndex = static_cast<Uint32>(-1);
+};
+
+
+struct AnimationSampler
+{
+ enum INTERPOLATION_TYPE
+ {
+ LINEAR,
+ STEP,
+ CUBICSPLINE
+ };
+ INTERPOLATION_TYPE Interpolation;
+ std::vector<float> Inputs;
+ std::vector<float4> OutputsVec4;
+};
+
+struct Animation
+{
+ std::string Name;
+ std::vector<AnimationSampler> Samplers;
+ std::vector<AnimationChannel> Channels;
+
+ float Start = std::numeric_limits<float>::max();
+ float End = std::numeric_limits<float>::min();
+};
+
+struct GLTF_TextureCacheType
+{
+ std::mutex TexturesMtx;
+
+ std::unordered_map<std::string, RefCntWeakPtr<ITexture>> Textures;
+};
+
+class Model : public IGLTFModel
+{
+public:
+ struct VertexBasicAttribs
+ {
+ float3 pos;
+ float3 normal;
+ float2 uv0;
+ float2 uv1;
+ };
+
+ struct VertexSkinAttribs
+ {
+ float4 joint0;
+ float4 weight0;
+ };
+
+ Uint32 IndexCount = 0;
+
+ /// Transformation matrix that transforms unit cube [0,1]x[0,1]x[0,1] into
+ /// axis-aligned bounding box in model space.
+ float4x4 AABBTransform;
+
+ std::vector<std::unique_ptr<Node>> Nodes;
+ std::vector<Node*> LinearNodes;
+
+ std::vector<std::unique_ptr<Skin>> Skins;
+
+ std::vector<RefCntAutoPtr<ISampler>> TextureSamplers;
+ std::vector<Material> Materials;
+ std::vector<Animation> Animations;
+ std::vector<std::string> Extensions;
+
+ struct Dimensions
+ {
+ float3 min = float3{+FLT_MAX, +FLT_MAX, +FLT_MAX};
+ float3 max = float3{-FLT_MAX, -FLT_MAX, -FLT_MAX};
+ } dimensions;
+
+ Model(IRenderDevice* pDevice,
+ IDeviceContext* pContext,
+ const IGLTFModelCreateInfo& CI);
+
+ ~Model();
+
+ virtual void UpdateAnimation(Uint32 index, float time) override final;
+
+ virtual void PrepareGPUResources(IRenderDevice* pDevice, IDeviceContext* pCtx) override final;
+
+ virtual bool IsGPUDataInitialized() const override final
+ {
+ return GPUDataInitialized.load();
+ }
+
+ virtual void Transform(const float* Matrix) override final;
+
+ virtual IBuffer* GetBuffer(GLTF_BUFFER_ID BuffId) override final
+ {
+ return Buffers[BuffId].pBuffer;
+ }
+
+ virtual ITexture* GetTexture(Uint32 Index) override final
+ {
+ return Textures[Index].pTexture;
+ }
+
+ virtual Uint32 GetFirstIndexLocation() const override final
+ {
+ auto& IndBuff = Buffers[GLTF_BUFFER_ID_INDEX];
+ VERIFY(!IndBuff.pSuballocation || IndBuff.pSuballocation->GetOffset() % sizeof(Uint32) == 0,
+ "Allocation offset is not multiple of sizeof(Uint32)");
+ return IndBuff.pSuballocation ?
+ static_cast<Uint32>(IndBuff.pSuballocation->GetOffset() / sizeof(Uint32)) :
+ 0;
+ }
+
+ virtual Uint32 GetBaseVertex() const override final
+ {
+ auto& VertBuff = Buffers[GLTF_BUFFER_ID_VERTEX_BASIC_ATTRIBS];
+ VERIFY(!VertBuff.pSuballocation || VertBuff.pSuballocation->GetOffset() % sizeof(VertexBasicAttribs) == 0,
+ "Allocation offset is not multiple of sizeof(VertexAttribs0)");
+ return VertBuff.pSuballocation ?
+ static_cast<Uint32>(VertBuff.pSuballocation->GetOffset() / sizeof(VertexBasicAttribs)) :
+ 0;
+ }
+
+private:
+ void LoadFromFile(IRenderDevice* pDevice,
+ IDeviceContext* pContext,
+ const IGLTFModelCreateInfo& CI);
+
+ void LoadNode(Node* parent,
+ const tinygltf::Node& gltf_node,
+ uint32_t nodeIndex,
+ const tinygltf::Model& gltf_model,
+ std::vector<Uint32>& IndexData,
+ std::vector<VertexBasicAttribs>& VertexBasicData,
+ std::vector<VertexSkinAttribs>* pVertexSkinData);
+
+ void LoadSkins(const tinygltf::Model& gltf_model);
+
+ void LoadTextures(IRenderDevice* pDevice,
+ const tinygltf::Model& gltf_model,
+ const std::string& BaseDir,
+ GLTF_TextureCacheType* pTextureCache,
+ ResourceManager* pResourceMgr);
+
+ void LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model);
+ void LoadMaterials(const tinygltf::Model& gltf_model);
+ void LoadAnimations(const tinygltf::Model& gltf_model);
+ void CalculateBoundingBox(Node* node, const Node* parent);
+ void CalculateSceneDimensions();
+ Node* FindNode(Node* parent, Uint32 index);
+ Node* NodeFromIndex(uint32_t index);
+
+ std::atomic_bool GPUDataInitialized{false};
+
+ struct BufferInfo
+ {
+ RefCntAutoPtr<IBuffer> pBuffer;
+ RefCntAutoPtr<IBufferSuballocation> pSuballocation;
+ };
+ std::array<BufferInfo, GLTF_BUFFER_ID_NUM_BUFFERS> Buffers;
+
+ struct TextureInfo
+ {
+ RefCntAutoPtr<ITexture> pTexture;
+ RefCntAutoPtr<ITextureAtlasSuballocation> pAtlasSuballocation;
+
+ bool IsValid() const
+ {
+ return pTexture || pAtlasSuballocation;
+ }
+ };
+ std::vector<TextureInfo> Textures;
+};
+
+} // namespace GLTF
+
+} // namespace Diligent
diff --git a/AssetLoader/include/GLTFResourceManager.hpp b/AssetLoader/include/GLTFResourceManager.hpp
new file mode 100644
index 0000000..a65f9e1
--- /dev/null
+++ b/AssetLoader/include/GLTFResourceManager.hpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2019-2021 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <vector>
+#include <unordered_map>
+#include <atomic>
+
+#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h"
+#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h"
+#include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp"
+#include "../../../DiligentCore/Common/interface/ObjectBase.hpp"
+#include "../../../DiligentCore/Graphics/GraphicsTools/interface/BufferSuballocator.h"
+#include "../../../DiligentCore/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h"
+
+
+namespace Diligent
+{
+
+namespace GLTF
+{
+
+/// GLTF resource manager
+class ResourceManager final : public ObjectBase<IObject>
+{
+public:
+ using TBase = ObjectBase<IObject>;
+
+ struct CreateInfo
+ {
+ const BufferSuballocatorCreateInfo* BuffSuballocators = nullptr; // [NumBuffSuballocators]
+ const DynamicTextureAtlasCreateInfo* TexAtlases = nullptr; // [NumTexAtlases]
+
+ Uint32 NumBuffSuballocators = 0;
+ Uint32 NumTexAtlases = 0;
+
+ DynamicTextureAtlasCreateInfo DefaultAtlasDesc;
+ };
+
+ static RefCntAutoPtr<ResourceManager> Create(IRenderDevice* pDevice,
+ const CreateInfo& CI);
+
+ RefCntAutoPtr<IBufferSuballocation> AllocateBufferSpace(Uint32 BufferIndex,
+ Uint32 Size,
+ Uint32 Alignment)
+ {
+ RefCntAutoPtr<IBufferSuballocation> pSuballoc;
+ m_BufferSuballocators[BufferIndex]->Allocate(Size, Alignment, &pSuballoc);
+ return pSuballoc;
+ }
+
+ RefCntAutoPtr<ITextureAtlasSuballocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt,
+ Uint32 Width,
+ Uint32 Height,
+ const char* CacheId = nullptr,
+ IObject* pUserData = nullptr);
+
+ RefCntAutoPtr<ITextureAtlasSuballocation> FindAllocation(const char* CacheId);
+
+ Uint32 GetTextureVersion()
+ {
+ Uint32 Version = 0;
+
+ std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
+ for (auto atlas_it : m_Atlases)
+ Version += atlas_it.second->GetVersion();
+
+ return Version;
+ }
+
+ Uint32 GetBufferVersion(Uint32 Index) const
+ {
+ return m_BufferSuballocators[Index]->GetVersion();
+ }
+
+ IBuffer* GetBuffer(Uint32 Index, IRenderDevice* pDevice, IDeviceContext* pContext)
+ {
+ return m_BufferSuballocators[Index]->GetBuffer(pDevice, pContext);
+ }
+
+ ITexture* GetTexture(TEXTURE_FORMAT Fmt, IRenderDevice* pDevice, IDeviceContext* pContext)
+ {
+ decltype(m_Atlases)::iterator cache_it; // NB: can't initialize it without locking the mutex
+ {
+ std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
+ cache_it = m_Atlases.find(Fmt);
+ if (cache_it == m_Atlases.end())
+ return nullptr;
+ }
+
+ return cache_it->second->GetTexture(pDevice, pContext);
+ }
+
+ // NB: can't return reference here!
+ TextureDesc GetAtlasDesc(TEXTURE_FORMAT Fmt)
+ {
+ {
+ std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
+
+ auto cache_it = m_Atlases.find(Fmt);
+ if (cache_it != m_Atlases.end())
+ return cache_it->second->GetAtlasDesc();
+ }
+
+ // Atlas is not present in the map - use default description
+ TextureDesc Desc = m_DefaultAtlasDesc.Desc;
+ Desc.Format = Fmt;
+ return Desc;
+ }
+
+private:
+ template <typename AllocatorType, typename ObjectType>
+ friend class Diligent::MakeNewRCObj;
+
+ ResourceManager(IReferenceCounters* pRefCounters,
+ IRenderDevice* pDevice,
+ const CreateInfo& CI);
+
+ std::vector<RefCntAutoPtr<IBufferSuballocator>> m_BufferSuballocators;
+
+ DynamicTextureAtlasCreateInfo m_DefaultAtlasDesc;
+ const std::string m_DefaultAtlasName;
+
+ using AtlasesHashMapType = std::unordered_map<TEXTURE_FORMAT, RefCntAutoPtr<IDynamicTextureAtlas>, std::hash<Uint32>>;
+ std::mutex m_AtlasesMtx;
+ AtlasesHashMapType m_Atlases;
+
+ using TexAllocationsHashMapType = std::unordered_map<std::string, RefCntWeakPtr<ITextureAtlasSuballocation>>;
+ std::mutex m_TexAllocationsMtx;
+ TexAllocationsHashMapType m_TexAllocations;
+};
+
+} // namespace GLTF
+
+} // namespace Diligent