Skip to content

Commit

Permalink
custom models: option to copy mod/eye draws from original model (#3800)
Browse files Browse the repository at this point in the history
Two new flags were added to the Blender plugin to allow reusing the mod
and/or eye draws of the original model that is being replaced. Works
pretty well for eyes, but the blerc draws can cause some Z-fighting with
the non-moving parts of the model.

Also a small refactor to the merc replacement code to de-duplicate some
code by moving stuff to `gltf_util.cpp`.
  • Loading branch information
Hat-Kid authored Dec 9, 2024
1 parent 5458d86 commit c476b84
Show file tree
Hide file tree
Showing 12 changed files with 372 additions and 233 deletions.
85 changes: 85 additions & 0 deletions common/util/gltf_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,4 +756,89 @@ tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>&
return colors;
}

void process_normal_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
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 default texture.");
draw.tree_tex_id = 0;
return;
}
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
if (tex_idx == -1) {
lg::warn("Material {} has no texture, using default texture.", mat.name);
draw.tree_tex_id = 0;
return;
}

const auto& tex = model.textures[tex_idx];
ASSERT(tex.sampler >= 0);
ASSERT(tex.source >= 0);
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);
};

void process_envmap_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
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;
}

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(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
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;
};

} // namespace gltf_util
31 changes: 31 additions & 0 deletions common/util/gltf_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,35 @@ math::Matrix4f matrix_from_trs(const math::Vector3f& trans,

tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>& color_palette);

struct MercExtractData {
TexturePool tex_pool;
std::vector<u32> new_indices;
std::vector<tfrag3::PreloadedVertex> new_vertices;
std::vector<math::Vector<u8, 4>> new_colors;
std::vector<math::Vector3f> normals;
std::vector<JointsAndWeights> joints_and_weights;
tfrag3::MercModel new_model;
};

// Data produced by loading a replacement model
struct MercSwapData {
std::vector<u32> new_indices;
std::vector<tfrag3::MercVertex> new_vertices;
std::vector<tfrag3::Texture> new_textures;
tfrag3::MercModel new_model;
};

void process_normal_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
tfrag3::MercEffect& eff,
int mat_idx,
const tfrag3::MercDraw& d_);
void process_envmap_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
tfrag3::MercEffect& eff,
int mat_idx,
const tfrag3::MercDraw& d_);

} // namespace gltf_util
4 changes: 4 additions & 0 deletions custom_assets/blender_plugins/opengoal.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def draw_func_ob(self, context):
ob = context.object
layout.prop(ob, "set_invisible")
layout.prop(ob, "enable_custom_weights")
layout.prop(ob, "copy_eye_draws")
layout.prop(ob, "copy_mod_draws")
layout.prop(ob, "set_collision")
if (ob.set_collision):
layout.prop(ob, "ignore")
Expand Down Expand Up @@ -118,6 +120,8 @@ def register():
bpy.types.Object.set_invisible = bpy.props.BoolProperty(name="Invisible")
bpy.types.Object.set_collision = bpy.props.BoolProperty(name="Apply Collision Properties")
bpy.types.Object.enable_custom_weights = bpy.props.BoolProperty(name="Use Custom Bone Weights")
bpy.types.Object.copy_eye_draws = bpy.props.BoolProperty(name="Copy Eye Draws")
bpy.types.Object.copy_mod_draws = bpy.props.BoolProperty(name="Copy Mod Draws")
bpy.types.Object.ignore = bpy.props.BoolProperty(name="ignore")
bpy.types.Object.noedge = bpy.props.BoolProperty(name="No-Edge")
bpy.types.Object.noentity = bpy.props.BoolProperty(name="No-Entity")
Expand Down
3 changes: 0 additions & 3 deletions decompiler/IR2/FormExpressionAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2603,9 +2603,6 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
ASSERT(x->parent_form == m_src);
}

if (auto test0 = m_src->to_string(env) == "(* 0.00024414062 (-> arg0 y))") {
printf("");
}
if (m_src->is_single_element()) {
auto src_as_se = dynamic_cast<SimpleExpressionElement*>(m_src->back());
if (src_as_se) {
Expand Down
10 changes: 10 additions & 0 deletions decompiler/level_extractor/extract_level.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ void extract_art_groups_from_level(const ObjectFileDB& db,
if (db.obj_files_by_dgo.count(dgo_name)) {
const auto& files = db.obj_files_by_dgo.at(dgo_name);
MercSwapInfo swapped_info;
// build list of models to replace
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[db.version()] / "merc_replacements";
if (file_util::file_exists(merc_replacements_path.string())) {
auto custom_models =
file_util::find_files_in_dir(merc_replacements_path, std::regex(".*\\.glb"));
for (auto& mdl : custom_models) {
swapped_info.add_to_swap_list(mdl.stem().string());
}
}
for (const auto& file : files) {
if (file.name.length() > 3 && !file.name.compare(file.name.length() - 3, 3, "-ag")) {
const auto& ag_file = db.lookup_record(file);
Expand Down
7 changes: 7 additions & 0 deletions decompiler/level_extractor/extract_level.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ namespace decompiler {

// info about what models have been replaced/added per level
struct MercSwapInfo {
std::vector<std::string> swap_list;
std::map<std::string, std::vector<std::string>> per_level_merc_swaps;
std::map<std::string, std::vector<std::string>> per_level_custom_mdls;

bool should_swap(const std::string& model) {
return std::find(swap_list.begin(), swap_list.end(), model) != swap_list.end();
}

bool already_swapped(const std::string& model, const std::string& level) {
auto mdls_it = per_level_merc_swaps.find(level);
if (mdls_it != per_level_merc_swaps.end()) {
Expand All @@ -35,6 +40,8 @@ struct MercSwapInfo {
return false;
}

void add_to_swap_list(const std::string& model) { swap_list.push_back(model); }

void add_to_swapped_list(const std::string& model, const std::string& level) {
per_level_merc_swaps[level].push_back(model);
}
Expand Down
38 changes: 20 additions & 18 deletions decompiler/level_extractor/extract_merc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1624,7 +1624,7 @@ void replace_model(tfrag3::Level& lvl, tfrag3::MercModel& model, const fs::path&
}
}

auto swap_info = load_replacement_merc_model(model.name, lvl.merc_data.indices.size(),
auto swap_info = load_replacement_merc_model(model, lvl.merc_data.indices.size(),
lvl.merc_data.vertices.size(), lvl.textures.size(),
mdl_path.string(), old_verts, false);
model = swap_info.new_model;
Expand All @@ -1647,8 +1647,8 @@ void add_custom_model_to_level(tfrag3::Level& lvl,
auto lvl_name = lvl.level_name == "" ? "common" : lvl.level_name;
lg::info("Adding custom model {} to {}", name, lvl_name);
auto merc_data =
load_replacement_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
lvl.textures.size(), mdl_path.string(), {}, true);
load_custom_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
lvl.textures.size(), mdl_path.string(), {}, true);
for (auto& idx : merc_data.new_indices) {
lvl.merc_data.indices.push_back(idx);
}
Expand Down Expand Up @@ -1798,23 +1798,25 @@ void extract_merc(const ObjectFileData& ag_data,

// do model replacement if present
for (auto& ctrl : ctrls) {
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "merc_replacements";
if (!swapped_info.already_swapped(ctrl.name, out.level_name)) {
if (file_util::file_exists(merc_replacements_path.string())) {
std::string file_name(ctrl.name + ".glb");
auto mdl_path = merc_replacements_path / file_name;
if (file_util::file_exists(mdl_path.string())) {
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
[&](const auto& m) { return m.name == ctrl.name; });
if (it != out.merc_data.models.end()) {
auto& model = *it;
replace_model(out, model, mdl_path);
swapped_info.add_to_swapped_list(ctrl.name, out.level_name);
if (swapped_info.should_swap(ctrl.name)) {
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "merc_replacements";
if (!swapped_info.already_swapped(ctrl.name, out.level_name)) {
if (file_util::file_exists(merc_replacements_path.string())) {
std::string file_name(ctrl.name + ".glb");
auto mdl_path = merc_replacements_path / file_name;
if (file_util::file_exists(mdl_path.string())) {
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
[&](const auto& m) { return m.name == ctrl.name; });
if (it != out.merc_data.models.end()) {
auto& model = *it;
replace_model(out, model, mdl_path);
swapped_info.add_to_swapped_list(ctrl.name, out.level_name);
}
}
} else {
lg::info("{} in level {} was already swapped, skipping", ctrl.name, out.level_name);
}
} else {
lg::info("{} in level {} was already swapped, skipping", ctrl.name, out.level_name);
}
}

Expand Down
Loading

0 comments on commit c476b84

Please sign in to comment.