Skip to content

Commit

Permalink
custom models: better error for invalid envmap material (#3784)
Browse files Browse the repository at this point in the history
When a material in Blender has its IOR level changed to anything other
than the default value of 0.5, the `KHR_materials_specular` extension is
applied during the glTF export, which is what we use to check for
envmaps in custom models. If an envmap is undesired, but the IOR value
was accidentally changed, the program would assert during model
processing if there is no metallic roughness texture attached to the
material.

Since this is an easy mistake to make and is hard to spot, this adds a
better error message for such cases.
  • Loading branch information
Hat-Kid authored Nov 27, 2024
1 parent 7848ba0 commit ef719d2
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 17 deletions.
22 changes: 22 additions & 0 deletions common/util/gltf_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,28 @@ EnvmapSettings envmap_settings_from_gltf(const tinygltf::Material& mat) {
return settings;
}

bool material_has_envmap(const tinygltf::Material& mat) {
return mat.extensions.contains("KHR_materials_specular");
}

bool envmap_is_valid(const tinygltf::Material& mat, bool die) {
if (material_has_envmap(mat) && mat.pbrMetallicRoughness.metallicRoughnessTexture.index < 0) {
std::string error = fmt::format(
"Material \"{}\" has specular property set, but is missing a metallic roughness texture! "
"Check "
"that the Specular IOR level for the material is at the default of 0.5 if this is "
"unintended.",
mat.name);
if (die) {
lg::die(error);
} else {
lg::error(error);
}
return false;
}
return true;
}

std::optional<int> find_single_skin(const tinygltf::Model& model,
const std::vector<NodeWithTransform>& all_nodes) {
std::optional<int> skin_index;
Expand Down
2 changes: 2 additions & 0 deletions common/util/gltf_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ struct EnvmapSettings {
};

EnvmapSettings envmap_settings_from_gltf(const tinygltf::Material& mat);
bool material_has_envmap(const tinygltf::Material& mat);
bool envmap_is_valid(const tinygltf::Material& mat, bool die);

/*!
* Find the index of the skin for this model. Returns nullopt if there is no skin, the index of the
Expand Down
12 changes: 4 additions & 8 deletions decompiler/level_extractor/merc_replacement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ using namespace gltf_util;

namespace decompiler {

bool material_has_envmap(const tinygltf::Material& mat) {
return mat.extensions.contains("KHR_materials_specular");
}

void extract(const std::string& name,
MercExtractData& out,
const tinygltf::Model& model,
Expand All @@ -25,7 +21,7 @@ void extract(const std::string& name,
int joints = 3;
auto skin_idx = find_single_skin(model, all_nodes);
if (skin_idx) {
joints = get_joint_count(model, *skin_idx);
joints += get_joint_count(model, *skin_idx);
}

for (const auto& n : all_nodes) {
Expand Down Expand Up @@ -134,14 +130,13 @@ void extract(const std::string& name,
return;
}

int roughness_tex_idx = mat.pbrMetallicRoughness.metallicRoughnessTexture.index;
ASSERT(roughness_tex_idx >= 0);
const auto& base_tex = model.textures[base_tex_idx];
ASSERT(base_tex.sampler >= 0);
ASSERT(base_tex.source >= 0);
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(base_tex.sampler), &draw.mode);
gltf_util::setup_alpha_from_material(mat, &draw.mode);
const auto& roughness_tex = model.textures.at(roughness_tex_idx);
const auto& roughness_tex =
model.textures.at(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
ASSERT(roughness_tex.sampler >= 0);
ASSERT(roughness_tex.source >= 0);

Expand Down Expand Up @@ -169,6 +164,7 @@ void extract(const std::string& name,
if (!material_has_envmap(mat)) {
process_normal_draw(e, mat_idx, d_);
} else {
envmap_is_valid(mat, true);
has_envmaps = true;
envmap_eff.has_envmap = true;
process_envmap_draw(envmap_eff, mat_idx, d_);
Expand Down
14 changes: 5 additions & 9 deletions goalc/build_actor/common/MercExtract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@

#include "goalc/build_level/common/gltf_mesh_extract.h"

bool material_has_envmap(const tinygltf::Material& mat) {
return mat.extensions.contains("KHR_materials_specular");
}

void extract(const std::string& name,
MercExtractData& out,
const tinygltf::Model& model,
Expand All @@ -25,7 +21,7 @@ void extract(const std::string& name,
int joints = 3;
auto skin_idx = find_single_skin(model, all_nodes);
if (skin_idx) {
joints = gltf_util::get_joint_count(model, *skin_idx);
joints += gltf_util::get_joint_count(model, *skin_idx);
}

for (const auto& n : all_nodes) {
Expand Down Expand Up @@ -146,14 +142,13 @@ void extract(const std::string& name,
return;
}

int roughness_tex_idx = mat.pbrMetallicRoughness.metallicRoughnessTexture.index;
ASSERT(roughness_tex_idx >= 0);
const auto& base_tex = model.textures[base_tex_idx];
ASSERT(base_tex.sampler >= 0);
ASSERT(base_tex.source >= 0);
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(base_tex.sampler), &draw.mode);
gltf_util::setup_alpha_from_material(mat, &draw.mode);
const auto& roughness_tex = model.textures.at(roughness_tex_idx);
const auto& roughness_tex =
model.textures.at(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
ASSERT(roughness_tex.sampler >= 0);
ASSERT(roughness_tex.source >= 0);

Expand All @@ -178,9 +173,10 @@ void extract(const std::string& name,

for (const auto& [mat_idx, d_] : draw_by_material) {
const auto& mat = model.materials[mat_idx];
if (!material_has_envmap(mat)) {
if (!gltf_util::material_has_envmap(mat)) {
process_normal_draw(e, mat_idx, d_);
} else {
gltf_util::envmap_is_valid(mat, false);
has_envmaps = true;
envmap_eff.has_envmap = true;
process_envmap_draw(envmap_eff, mat_idx, d_);
Expand Down

0 comments on commit ef719d2

Please sign in to comment.