diff --git a/AssetLoader/interface/GLTFLoader.hpp b/AssetLoader/interface/GLTFLoader.hpp index 8167e81b..d1fe5965 100644 --- a/AssetLoader/interface/GLTFLoader.hpp +++ b/AssetLoader/interface/GLTFLoader.hpp @@ -112,12 +112,21 @@ static constexpr std::array DefaultTextureAttributes = struct Material { - Material() noexcept + Material(Uint32 _NumTextureAttribs) : + TextureIds{ + _NumTextureAttribs > 0 ? + std::make_unique(_NumTextureAttribs) : + std::unique_ptr{}, + }, + TextureAttribs{ + _NumTextureAttribs > 0 ? + std::make_unique(_NumTextureAttribs) : + std::unique_ptr{}, + }, + NumTextureAttribs{_NumTextureAttribs} { - TextureIds.fill(-1); - for (size_t i = 0; i < _countof(Attribs.UVScaleBias); ++i) - Attribs.UVScaleBias[i] = float4{1, 1, 0, 0}; } + Material(Material&&) = default; enum PBR_WORKFLOW { @@ -133,8 +142,6 @@ struct Material ALPHA_MODE_NUM_MODES }; - static constexpr Uint32 NumTextureAttributes = 5; - // Material attributes packed in a shader-friendly format struct ShaderAttribs { @@ -142,29 +149,15 @@ struct Material float4 EmissiveFactor = float4{0, 0, 0, 0}; float4 SpecularFactor = float4{1, 1, 1, 1}; - int Workflow = PBR_WORKFLOW_METALL_ROUGH; - float UVSelector0 = -1; - float UVSelector1 = -1; - float UVSelector2 = -1; - - float UVSelector3 = -1; - float UVSelector4 = -1; - float TextureSlice0 = 0; - float TextureSlice1 = 0; - - float TextureSlice2 = 0; - float TextureSlice3 = 0; - float TextureSlice4 = 0; + int Workflow = PBR_WORKFLOW_METALL_ROUGH; + int AlphaMode = ALPHA_MODE_OPAQUE; + float AlphaCutoff = 0.5f; float MetallicFactor = 1; float RoughnessFactor = 1; - int AlphaMode = ALPHA_MODE_OPAQUE; - float AlphaCutoff = 0.5f; float OcclusionFactor = 1; - - // When texture atlas is used, UV scale and bias is applied to - // each texture coordinate set. - float4 UVScaleBias[NumTextureAttributes]; + float Padding0 = 0; + float Padding1 = 0; // Any user-specific data float4 CustomData = float4{0, 0, 0, 0}; @@ -172,8 +165,18 @@ struct Material static_assert(sizeof(ShaderAttribs) % 16 == 0, "ShaderAttribs struct must be 16-byte aligned"); ShaderAttribs Attribs; - bool DoubleSided = false; + struct TextureShaderAttribs + { + float UVSelector = -1; + float TextureSlice = 0; + float Padding0 = 0; + float Padding1 = 0; + + float4 UVScaleBias = float4{1, 1, 0, 0}; + }; + static_assert(sizeof(TextureShaderAttribs) % 16 == 0, "TextureShaderAttribs struct must be 16-byte aligned"); +private: // Texture indices in Model.Textures array, for each attribute. // _________________ _______________________ __________________ // | | | | | | @@ -189,11 +192,45 @@ struct Material // Defined by // ModeCI.TextureAttributes // - std::array TextureIds = {}; + std::unique_ptr TextureIds; + + std::unique_ptr TextureAttribs; + + Uint32 NumTextureAttribs = 0; + +public: + bool DoubleSided = false; // Any user-specific data. One way to set this field is from the // MaterialLoadCallback. RefCntAutoPtr pUserData; + + Uint32 GetNumTextureAttribs() const + { + return NumTextureAttribs; + } + + int GetTextureId(Uint32 Idx) const + { + VERIFY_EXPR(Idx < NumTextureAttribs); + return TextureIds[Idx]; + } + void SetTextureId(Uint32 Idx, int TextureId) + { + VERIFY_EXPR(Idx < NumTextureAttribs); + TextureIds[Idx] = TextureId; + } + + TextureShaderAttribs& GetTextureAttrib(Uint32 Idx) + { + VERIFY_EXPR(Idx < NumTextureAttribs); + return TextureAttribs[Idx]; + } + const TextureShaderAttribs& GetTextureAttrib(Uint32 Idx) const + { + VERIFY_EXPR(Idx < NumTextureAttribs); + return TextureAttribs[Idx]; + } }; @@ -872,8 +909,9 @@ struct Model const VertexAttributeDesc* VertexAttributes = nullptr; const TextureAttributeDesc* TextureAttributes = nullptr; - Uint32 NumVertexAttributes = 0; - Uint32 NumTextureAttributes = 0; + Uint32 NumVertexAttributes = 0; + Uint32 NumTextureAttributes = 0; + Uint32 MaxTextureAttributeIndex = 0; struct VertexDataInfo { diff --git a/AssetLoader/src/GLTFLoader.cpp b/AssetLoader/src/GLTFLoader.cpp index 095b1e91..e1170057 100644 --- a/AssetLoader/src/GLTFLoader.cpp +++ b/AssetLoader/src/GLTFLoader.cpp @@ -583,10 +583,9 @@ Model::Model(const ModelCreateInfo& CI) const auto& Attrib = pSrcTexAttribs[i]; DEV_CHECK_ERR(Attrib.Name != nullptr, "Texture attribute name must not be null"); - DEV_CHECK_ERR(Attrib.Index < Uint32{Material::NumTextureAttributes}, "Texture attribute index (", Attrib.Index, - ") exceeds the number of attributes (", Uint32{Material::NumTextureAttributes}, ")."); - Allocator.AddSpaceForString(Attrib.Name); + + MaxTextureAttributeIndex = std::max(MaxTextureAttributeIndex, Attrib.Index); } Allocator.Reserve(); @@ -660,7 +659,7 @@ float Model::GetTextureAlphaCutoffValue(int TextureIndex) const float AlphaCutoff = -1.f; for (const auto& Mat : Materials) { - if (Mat.TextureIds[BaseTexAttribIdx] != TextureIndex) + if (Mat.GetTextureId(BaseTexAttribIdx) != TextureIndex) { // The material does not use this texture as base color. continue; @@ -906,12 +905,13 @@ void Model::InitMaterialTextureAddressingAttribs(Material& Mat, Uint32 TextureIn if (TexInfo.pAtlasSuballocation) { - for (Uint32 i = 0; i < Material::NumTextureAttributes; ++i) + for (Uint32 i = 0; i < Mat.GetNumTextureAttribs(); ++i) { - if (Mat.TextureIds[i] == static_cast(TextureIndex)) + if (Mat.GetTextureId(i) == static_cast(TextureIndex)) { - Mat.Attribs.UVScaleBias[i] = TexInfo.pAtlasSuballocation->GetUVScaleBias(); - (&Mat.Attribs.TextureSlice0)[i] = static_cast(TexInfo.pAtlasSuballocation->GetSlice()); + Material::TextureShaderAttribs& TexAttribs{Mat.GetTextureAttrib(i)}; + TexAttribs.UVScaleBias = TexInfo.pAtlasSuballocation->GetUVScaleBias(); + TexAttribs.TextureSlice = static_cast(TexInfo.pAtlasSuballocation->GetSlice()); } } } @@ -1175,16 +1175,16 @@ void Model::LoadMaterials(const tinygltf::Model& gltf_model, const ModelCreateIn Materials.reserve(gltf_model.materials.size()); for (const tinygltf::Material& gltf_mat : gltf_model.materials) { - Material Mat; + Material Mat{MaxTextureAttributeIndex + 1}; auto FindTexture = [&Mat](const TextureAttributeDesc& Attrib, const auto& Mapping) { auto tex_it = Mapping.find(Attrib.Name); if (tex_it == Mapping.end()) return false; - VERIFY_EXPR(Attrib.Index < Material::NumTextureAttributes); - Mat.TextureIds[Attrib.Index] = tex_it->second.TextureIndex(); - (&Mat.Attribs.UVSelector0)[Attrib.Index] = static_cast(tex_it->second.TextureTexCoord()); + VERIFY_EXPR(Attrib.Index < Mat.GetNumTextureAttribs()); + Mat.SetTextureId(Attrib.Index, tex_it->second.TextureIndex()); + Mat.GetTextureAttrib(Attrib.Index).UVSelector = static_cast(tex_it->second.TextureTexCoord()); return true; }; @@ -1265,12 +1265,12 @@ void Model::LoadMaterials(const tinygltf::Model& gltf_model, const ModelCreateIn const auto SpecGlossTexAttribIdx = GetTextureAttributeIndex(SpecularGlossinessTextureName); if (SpecGlossTexAttribIdx >= 0) { - VERIFY_EXPR(SpecGlossTexAttribIdx < static_cast(Material::NumTextureAttributes)); + VERIFY_EXPR(SpecGlossTexAttribIdx < static_cast(Mat.GetNumTextureAttribs())); auto index = ext_it->second.Get(SpecularGlossinessTextureName).Get("index"); auto texCoordSet = ext_it->second.Get(SpecularGlossinessTextureName).Get("texCoord"); - Mat.TextureIds[SpecGlossTexAttribIdx] = index.Get(); - (&Mat.Attribs.UVSelector0)[SpecGlossTexAttribIdx] = static_cast(texCoordSet.Get()); + Mat.SetTextureId(SpecGlossTexAttribIdx, index.Get()); + Mat.GetTextureAttrib(SpecGlossTexAttribIdx).UVSelector = static_cast(texCoordSet.Get()); } } @@ -1279,12 +1279,12 @@ void Model::LoadMaterials(const tinygltf::Model& gltf_model, const ModelCreateIn const auto DiffuseTexAttribIdx = GetTextureAttributeIndex(DiffuseTextureName); if (DiffuseTexAttribIdx >= 0) { - VERIFY_EXPR(DiffuseTexAttribIdx < static_cast(Material::NumTextureAttributes)); + VERIFY_EXPR(DiffuseTexAttribIdx < static_cast(Mat.GetNumTextureAttribs())); auto index = ext_it->second.Get(DiffuseTextureName).Get("index"); auto texCoordSet = ext_it->second.Get(DiffuseTextureName).Get("texCoord"); - Mat.TextureIds[DiffuseTexAttribIdx] = index.Get(); - (&Mat.Attribs.UVSelector0)[DiffuseTexAttribIdx] = static_cast(texCoordSet.Get()); + Mat.SetTextureId(DiffuseTexAttribIdx, index.Get()); + Mat.GetTextureAttrib(DiffuseTexAttribIdx).UVSelector = static_cast(texCoordSet.Get()); } } @@ -1315,13 +1315,13 @@ void Model::LoadMaterials(const tinygltf::Model& gltf_model, const ModelCreateIn if (MaterialLoadCallback != nullptr) MaterialLoadCallback(&gltf_mat, Mat); - Materials.push_back(Mat); + Materials.push_back(std::move(Mat)); } if (Materials.empty()) { // Push a default material for meshes with no material assigned - Materials.push_back(Material{}); + Materials.push_back(Material{MaxTextureAttributeIndex + 1}); } }