Skip to content

Commit

Permalink
Implement KHR_materials_unlit extension
Browse files Browse the repository at this point in the history
  • Loading branch information
pablode committed Mar 8, 2024
1 parent 77d7dc1 commit 03c5f80
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/libguc/src/cgltf_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace detail
strcmp(name, "KHR_materials_sheen") == 0 ||
strcmp(name, "KHR_materials_specular") == 0 ||
strcmp(name, "KHR_materials_transmission") == 0 ||
strcmp(name, "KHR_materials_unlit") == 0 ||
strcmp(name, "KHR_materials_variants") == 0 ||
strcmp(name, "KHR_materials_volume") == 0 ||
strcmp(name, "KHR_texture_transform") == 0;
Expand Down
35 changes: 34 additions & 1 deletion src/libguc/src/materialx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,14 +428,47 @@ namespace guc

try
{
createGltfPbrNodes(material, materialName);
if (material->unlit)
{
createUnlitSurfaceNodes(material, materialName);
}
else
{
createGltfPbrNodes(material, materialName);
}
}
catch (const mx::Exception& ex)
{
TF_RUNTIME_ERROR("Failed to create glTF PBR nodes for material '%s': %s", materialName.c_str(), ex.what());
}
}

void MaterialXMaterialConverter::createUnlitSurfaceNodes(const cgltf_material* material, const std::string& materialName)
{
createMaterialNodes(material, materialName, "unlit_surface", [this](const cgltf_material* material,
mx::NodeGraphPtr nodeGraph,
mx::NodePtr shaderNode) {
mx::InputPtr emissionInput = shaderNode->addInput("emission", MTLX_TYPE_COLOR3);

if (material->has_pbr_metallic_roughness)
{
const cgltf_pbr_metallic_roughness* pbrMetallicRoughness = &material->pbr_metallic_roughness;

if (material->alpha_mode != cgltf_alpha_mode_opaque)
{
mx::InputPtr opacityInput = shaderNode->addInput("opacity", MTLX_TYPE_FLOAT);
setAlphaTextureInput(nodeGraph, opacityInput, &pbrMetallicRoughness->base_color_texture, pbrMetallicRoughness->base_color_factor[3]);
}

setDiffuseTextureInput(nodeGraph, emissionInput, &pbrMetallicRoughness->base_color_texture, detail::makeMxColor3(pbrMetallicRoughness->base_color_factor));
}
else
{
emissionInput->setValue(mx::Color3(1.0f));
}
});
}

void MaterialXMaterialConverter::createGltfPbrNodes(const cgltf_material* material, const std::string& materialName)
{
createMaterialNodes(material, materialName, "gltf_pbr", [this](const cgltf_material* material,
Expand Down
3 changes: 3 additions & 0 deletions src/libguc/src/materialx.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ namespace guc
bool m_hdstormCompat;

private:
void createUnlitSurfaceNodes(const cgltf_material* material,
const std::string& materialName);

void createGltfPbrNodes(const cgltf_material* material,
const std::string& materialName);

Expand Down
55 changes: 41 additions & 14 deletions src/libguc/src/usdpreviewsurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,47 @@ namespace guc
auto shaderOutput = shader.CreateOutput(UsdShadeTokens->surface, SdfValueTypeNames->Token);
surfaceOutput.ConnectToSource(shaderOutput);

auto setAlphaTextureInput = [&](const cgltf_pbr_metallic_roughness* pbrMetallicRoughness)
{
if (material->alpha_mode != cgltf_alpha_mode_opaque)
{
// Do nothing.
return;
}

GfVec4f opacityFallback(1.0f); // image fallback value is 0.0, but opacity default should be 1.0

auto opacityInput = shader.CreateInput(_tokens->opacity, SdfValueTypeNames->Float);
setFloatTextureInput(path, opacityInput, pbrMetallicRoughness->base_color_texture, _tokens->a, GfVec4f(pbrMetallicRoughness->base_color_factor[3]), &opacityFallback);

if (material->alpha_mode == cgltf_alpha_mode_mask)
{
auto opacityThresholdInput = shader.CreateInput(_tokens->opacityThreshold, SdfValueTypeNames->Float);
opacityThresholdInput.Set(material->alpha_cutoff);
}
};

auto emissiveColorInput = shader.CreateInput(_tokens->emissiveColor, SdfValueTypeNames->Float3);
auto emissiveFactor = GfVec4f(material->emissive_factor);

if (material->unlit) // Not really 'unlit', but there's no better way
{
if (material->has_pbr_metallic_roughness)
{
const cgltf_pbr_metallic_roughness* pbrMetallicRoughness = &material->pbr_metallic_roughness;

GfVec4f unlitColorFallback(1.0f); // not specified

setSrgbTextureInput(path, emissiveColorInput, pbrMetallicRoughness->base_color_texture, GfVec4f(pbrMetallicRoughness->base_color_factor), &unlitColorFallback);
setAlphaTextureInput(pbrMetallicRoughness);
}
else
{
emissiveColorInput.Set(GfVec3f(1.0f));
}
return;
}

if (material->has_emissive_strength)
{
const cgltf_emissive_strength* emissiveStrength = &material->emissive_strength;
Expand All @@ -169,7 +208,6 @@ namespace guc
// We need to set these values regardless of whether pbrMetallicRoughness is present or not, because UsdPreviewSurface's
// default values differ (and we want to come as close as possible to the MaterialX look, although the shading model differs).
auto diffuseColorInput = shader.CreateInput(_tokens->diffuseColor, SdfValueTypeNames->Float3);
auto opacityInput = shader.CreateInput(_tokens->opacity, SdfValueTypeNames->Float);
auto metallicInput = shader.CreateInput(_tokens->metallic, SdfValueTypeNames->Float);
auto roughnessInput = shader.CreateInput(_tokens->roughness, SdfValueTypeNames->Float);

Expand All @@ -182,23 +220,11 @@ namespace guc
GfVec4f metallicRoughnessFallback(1.0f); // same as glTF spec sec. 5.22.5: "When undefined, the texture MUST be sampled as having 1.0 in G and B components."
setFloatTextureInput(path, metallicInput, pbrMetallicRoughness->metallic_roughness_texture, _tokens->b, GfVec4f(pbrMetallicRoughness->metallic_factor), &metallicRoughnessFallback);
setFloatTextureInput(path, roughnessInput, pbrMetallicRoughness->metallic_roughness_texture, _tokens->g, GfVec4f(pbrMetallicRoughness->roughness_factor), &metallicRoughnessFallback);

if (material->alpha_mode != cgltf_alpha_mode_opaque)
{
GfVec4f opacityFallback(1.0f); // image fallback value is 0.0, but opacity default should be 1.0
setFloatTextureInput(path, opacityInput, pbrMetallicRoughness->base_color_texture, _tokens->a, GfVec4f(pbrMetallicRoughness->base_color_factor[3]), &opacityFallback);

if (material->alpha_mode == cgltf_alpha_mode_mask)
{
auto opacityThresholdInput = shader.CreateInput(_tokens->opacityThreshold, SdfValueTypeNames->Float);
opacityThresholdInput.Set(material->alpha_cutoff);
}
}
setAlphaTextureInput(pbrMetallicRoughness);
}
else
{
diffuseColorInput.Set(GfVec3f(1.0f)); // 0.18 in UsdPreviewSurface spec
opacityInput.Set(1.0f);
metallicInput.Set(1.0f); // 0.0 in UsdPreviewSurface spec
roughnessInput.Set(1.0f); // 0.5 in UsdPreviewSurface spec
}
Expand Down Expand Up @@ -253,6 +279,7 @@ namespace guc
float saturation = (baseColorMaxValue <= std::numeric_limits<float>::min()) ? 0.0f : (baseColorRange / baseColorMaxValue);
float opacity = 0.25f + 0.75f * saturation * (1.0f - transmission->transmission_factor);

auto opacityInput = shader.CreateInput(_tokens->opacity, SdfValueTypeNames->Float); // not set because of OPAQUE mode check
opacityInput.Set(opacity);
}
}
Expand Down

0 comments on commit 03c5f80

Please sign in to comment.