Skip to content

Commit

Permalink
GLTF loader: separated shader texture attributes from other attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Nov 22, 2023
1 parent e4fcc51 commit 6ce3634
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 49 deletions.
96 changes: 67 additions & 29 deletions AssetLoader/interface/GLTFLoader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,21 @@ static constexpr std::array<TextureAttributeDesc, 7> DefaultTextureAttributes =

struct Material
{
Material() noexcept
Material(Uint32 _NumTextureAttribs) :
TextureIds{
_NumTextureAttribs > 0 ?
std::make_unique<int[]>(_NumTextureAttribs) :
std::unique_ptr<int[]>{},
},
TextureAttribs{
_NumTextureAttribs > 0 ?
std::make_unique<TextureShaderAttribs[]>(_NumTextureAttribs) :
std::unique_ptr<TextureShaderAttribs[]>{},
},
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
{
Expand All @@ -133,47 +142,41 @@ struct Material
ALPHA_MODE_NUM_MODES
};

static constexpr Uint32 NumTextureAttributes = 5;

// Material attributes packed in a shader-friendly format
struct ShaderAttribs
{
float4 BaseColorFactor = float4{1, 1, 1, 1};
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};
};
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.
// _________________ _______________________ __________________
// | | | | | |
Expand All @@ -189,11 +192,45 @@ struct Material
// Defined by
// ModeCI.TextureAttributes
//
std::array<int, NumTextureAttributes> TextureIds = {};
std::unique_ptr<int[]> TextureIds;

std::unique_ptr<TextureShaderAttribs[]> TextureAttribs;

Uint32 NumTextureAttribs = 0;

public:
bool DoubleSided = false;

// Any user-specific data. One way to set this field is from the
// MaterialLoadCallback.
RefCntAutoPtr<IObject> 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];
}
};


Expand Down Expand Up @@ -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
{
Expand Down
40 changes: 20 additions & 20 deletions AssetLoader/src/GLTFLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<int>(TextureIndex))
if (Mat.GetTextureId(i) == static_cast<int>(TextureIndex))
{
Mat.Attribs.UVScaleBias[i] = TexInfo.pAtlasSuballocation->GetUVScaleBias();
(&Mat.Attribs.TextureSlice0)[i] = static_cast<float>(TexInfo.pAtlasSuballocation->GetSlice());
Material::TextureShaderAttribs& TexAttribs{Mat.GetTextureAttrib(i)};
TexAttribs.UVScaleBias = TexInfo.pAtlasSuballocation->GetUVScaleBias();
TexAttribs.TextureSlice = static_cast<float>(TexInfo.pAtlasSuballocation->GetSlice());
}
}
}
Expand Down Expand Up @@ -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<float>(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<float>(tex_it->second.TextureTexCoord());

return true;
};
Expand Down Expand Up @@ -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<int>(Material::NumTextureAttributes));
VERIFY_EXPR(SpecGlossTexAttribIdx < static_cast<int>(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<int>();
(&Mat.Attribs.UVSelector0)[SpecGlossTexAttribIdx] = static_cast<float>(texCoordSet.Get<int>());
Mat.SetTextureId(SpecGlossTexAttribIdx, index.Get<int>());
Mat.GetTextureAttrib(SpecGlossTexAttribIdx).UVSelector = static_cast<float>(texCoordSet.Get<int>());
}
}

Expand All @@ -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<int>(Material::NumTextureAttributes));
VERIFY_EXPR(DiffuseTexAttribIdx < static_cast<int>(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<int>();
(&Mat.Attribs.UVSelector0)[DiffuseTexAttribIdx] = static_cast<float>(texCoordSet.Get<int>());
Mat.SetTextureId(DiffuseTexAttribIdx, index.Get<int>());
Mat.GetTextureAttrib(DiffuseTexAttribIdx).UVSelector = static_cast<float>(texCoordSet.Get<int>());
}
}

Expand Down Expand Up @@ -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});
}
}

Expand Down

0 comments on commit 6ce3634

Please sign in to comment.