Fix animation processing interpolation bug, crash on no merc material (#3794)

Fixes the issue with animations doing a full 180 degree rotation and
disappearing. The quaternions in the GLB export "flip", and when
interpolating animation frames in between a flip, we got bogus
quaternions.

Fixes https://github.com/open-goal/jak-project/issues/3786

Also fix a crash in `goalc` when using merc models without any
materials.

Co-authored-by: water111 <awaterford1111445@gmail.com>
This commit is contained in:
water111
2024-12-07 13:42:48 -05:00
committed by GitHub
parent 6e4e5d2bf7
commit a2f9d36332
2 changed files with 21 additions and 11 deletions
+4 -3
View File
@@ -97,7 +97,6 @@ void extract(const std::string& name,
out.new_model.max_draws = 0;
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();
@@ -107,6 +106,8 @@ void extract(const std::string& name,
draw.tree_tex_id = 0;
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 default texture.", mat.name);
@@ -172,8 +173,8 @@ void extract(const std::string& name,
};
for (const auto& [mat_idx, d_] : draw_by_material) {
const auto& mat = model.materials[mat_idx];
if (!gltf_util::material_has_envmap(mat) || !gltf_util::envmap_is_valid(mat)) {
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
process_normal_draw(e, mat_idx, d_);
} else {
envmap_eff.has_envmap = true;
@@ -21,7 +21,8 @@ int find_max_joint(const tinygltf::Animation& anim, const std::map<int, int>& no
template <typename T>
std::vector<T> compute_keyframes(const std::vector<float>& times,
const std::vector<T>& values,
float framerate) {
float framerate,
bool quaternion_interp) {
std::vector<T> ret;
ASSERT(!times.empty());
ASSERT(times.size() == values.size());
@@ -36,8 +37,15 @@ std::vector<T> compute_keyframes(const std::vector<float>& times,
}
const float fraction = (t - times.at(i)) / (times.at(i + 1) - times.at(i));
ret.push_back(values.at(i) * (1.f - fraction) + values.at(i + 1) * fraction);
// lg::info("{} + {:.3f}, {}", i, fraction, ret.back().to_string_aligned());
if (quaternion_interp) {
float multiplier = 1;
if (values.at(i).dot(values.at(i + 1)) < 0) {
multiplier = -1;
}
ret.push_back(values.at(i) * (1.f - fraction) + values.at(i + 1) * fraction * multiplier);
} else {
ret.push_back(values.at(i) * (1.f - fraction) + values.at(i + 1) * fraction);
}
t += 1.f / framerate;
}
return ret;
@@ -47,12 +55,13 @@ template <int n>
std::vector<math::Vector<float, n>> extract_keyframed_gltf_vecn(
const tinygltf::Model& model,
const tinygltf::AnimationSampler& sampler,
float framerate) {
float framerate,
bool quaternion_interp) {
std::vector<float> times = gltf_util::extract_floats(model, sampler.input);
std::vector<math::Vector<float, n>> values =
gltf_util::extract_vec<float, n>(model, sampler.output, TINYGLTF_COMPONENT_TYPE_FLOAT);
ASSERT(times.size() == values.size());
return compute_keyframes(times, values, framerate);
return compute_keyframes(times, values, framerate, quaternion_interp);
}
} // namespace
@@ -75,13 +84,13 @@ UncompressedJointAnim extract_anim_from_gltf(const tinygltf::Model& model,
const auto& sampler = anim.samplers.at(channel.sampler);
if (channel.target_path == "translation") {
out.joints.at(channel_joint).trans_frames =
extract_keyframed_gltf_vecn<3>(model, sampler, framerate);
extract_keyframed_gltf_vecn<3>(model, sampler, framerate, false);
} else if (channel.target_path == "rotation") {
out.joints.at(channel_joint).quat_frames =
extract_keyframed_gltf_vecn<4>(model, sampler, framerate);
extract_keyframed_gltf_vecn<4>(model, sampler, framerate, true);
} else if (channel.target_path == "scale") {
out.joints.at(channel_joint).scale_frames =
extract_keyframed_gltf_vecn<3>(model, sampler, framerate);
extract_keyframed_gltf_vecn<3>(model, sampler, framerate, false);
} else {
lg::die("unknown target_path {}", channel.target_path);
}