mirror of
https://github.com/open-goal/jak-project
synced 2026-08-09 10:54:39 -04:00
custom models: envmap support (#3777)
Custom models and model replacements now support environment mapping. Also fixed some cases in Jak 3 where tfrags had missing textures (defaulting to texture 0 from tpage 0, which in Jak 3 is the default eye texture) and replaced them with more suitable alternatives. Fixes #3776 https://github.com/user-attachments/assets/7c11b0de-b254-40cb-9719-11238dfb3d43  
This commit is contained in:
@@ -3,6 +3,11 @@
|
||||
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,
|
||||
@@ -16,6 +21,7 @@ void extract(const std::string& name,
|
||||
std::map<int, tfrag3::MercDraw> draw_by_material;
|
||||
int mesh_count = 0;
|
||||
int prim_count = 0;
|
||||
bool has_envmaps = false;
|
||||
|
||||
for (const auto& n : all_nodes) {
|
||||
const auto& node = model.nodes[n.node_idx];
|
||||
@@ -72,42 +78,108 @@ void extract(const std::string& name,
|
||||
}
|
||||
|
||||
tfrag3::MercEffect e;
|
||||
tfrag3::MercEffect envmap_eff;
|
||||
out.new_model.name = name;
|
||||
out.new_model.max_bones = 120;
|
||||
out.new_model.max_bones = 100; // idk
|
||||
out.new_model.max_draws = 200;
|
||||
for (const auto& [mat_idx, d_] : draw_by_material) {
|
||||
e.all_draws.push_back(d_);
|
||||
auto& draw = e.all_draws.back();
|
||||
draw.mode = make_default_draw_mode();
|
||||
|
||||
auto process_normal_draw = [&](tfrag3::MercEffect& eff, int mat_idx, const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Draw had a material index of -1, using bogus texture.");
|
||||
lg::warn("Draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = 0;
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (tex_idx == -1) {
|
||||
lg::warn("Material {} has no texture, using bogus texture.", mat.name);
|
||||
lg::warn("Material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = 0;
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& tex = model.textures[tex_idx];
|
||||
ASSERT(tex.sampler >= 0);
|
||||
ASSERT(tex.source >= 0);
|
||||
setup_alpha_from_material(mat, &draw.mode);
|
||||
setup_draw_mode_from_sampler(model.samplers.at(tex.sampler), &draw.mode);
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(tex.sampler), &draw.mode);
|
||||
gltf_util::setup_alpha_from_material(mat, &draw.mode);
|
||||
|
||||
const auto& img = model.images[tex.source];
|
||||
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
|
||||
};
|
||||
|
||||
auto process_envmap_draw = [&](tfrag3::MercEffect& eff, int mat_idx, const tfrag3::MercDraw& d_) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
eff.all_draws.push_back(d_);
|
||||
auto& draw = eff.all_draws.back();
|
||||
draw.mode = gltf_util::make_default_draw_mode();
|
||||
|
||||
if (mat_idx == -1) {
|
||||
lg::warn("Envmap draw had a material index of -1, using default texture.");
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
return;
|
||||
}
|
||||
int base_tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
|
||||
if (base_tex_idx == -1) {
|
||||
lg::warn("Envmap material {} has no texture, using default texture.", mat.name);
|
||||
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
|
||||
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);
|
||||
ASSERT(roughness_tex.sampler >= 0);
|
||||
ASSERT(roughness_tex.source >= 0);
|
||||
|
||||
draw.tree_tex_id =
|
||||
tex_offset + gltf_util::texture_pool_add_envmap_control_texture(
|
||||
&out.tex_pool, model, base_tex.source, roughness_tex.source,
|
||||
!draw.mode.get_clamp_s_enable(), !draw.mode.get_clamp_t_enable());
|
||||
|
||||
// now, setup envmap draw:
|
||||
auto envmap_settings = gltf_util::envmap_settings_from_gltf(mat);
|
||||
const auto& envmap_tex = model.textures[envmap_settings.texture_idx];
|
||||
ASSERT(envmap_tex.sampler >= 0);
|
||||
ASSERT(envmap_tex.source >= 0);
|
||||
auto env_mode = gltf_util::make_default_draw_mode();
|
||||
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(envmap_tex.sampler), &env_mode);
|
||||
eff.envmap_texture = tex_offset + gltf_util::texture_pool_add_texture(
|
||||
&out.tex_pool, model.images[envmap_tex.source]);
|
||||
env_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
|
||||
env_mode.enable_ab();
|
||||
eff.envmap_mode = env_mode;
|
||||
};
|
||||
|
||||
for (const auto& [mat_idx, d_] : draw_by_material) {
|
||||
const auto& mat = model.materials[mat_idx];
|
||||
if (!material_has_envmap(mat)) {
|
||||
process_normal_draw(e, mat_idx, d_);
|
||||
} else {
|
||||
has_envmaps = true;
|
||||
envmap_eff.has_envmap = true;
|
||||
process_envmap_draw(envmap_eff, mat_idx, d_);
|
||||
}
|
||||
}
|
||||
|
||||
lg::info("total of {} unique materials ({} normal, {} envmap)",
|
||||
e.all_draws.size() + envmap_eff.all_draws.size(), e.all_draws.size(),
|
||||
envmap_eff.all_draws.size());
|
||||
// in case a model only has envmap draws, we don't push the normal merc effect
|
||||
if (!e.all_draws.empty()) {
|
||||
out.new_model.effects.push_back(e);
|
||||
}
|
||||
if (has_envmaps) {
|
||||
out.new_model.effects.push_back(envmap_eff);
|
||||
}
|
||||
lg::info("total of {} unique materials", e.all_draws.size());
|
||||
e.has_mod_draw = false;
|
||||
out.new_model.effects.push_back(e);
|
||||
out.new_model.effects.push_back(e);
|
||||
out.new_model.effects.push_back(e);
|
||||
out.new_model.effects.push_back(e);
|
||||
|
||||
lg::info("Merged {} meshes and {} prims into {} vertices", mesh_count, prim_count,
|
||||
out.new_vertices.size());
|
||||
|
||||
Reference in New Issue
Block a user