diff --git a/goalc/build_actor/common/MercExtract.cpp b/goalc/build_actor/common/MercExtract.cpp index e83a26c07d4..9d90ab0ecd4 100644 --- a/goalc/build_actor/common/MercExtract.cpp +++ b/goalc/build_actor/common/MercExtract.cpp @@ -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; diff --git a/goalc/build_actor/common/animation_processing.cpp b/goalc/build_actor/common/animation_processing.cpp index 8f02068932e..55e75d8b6ca 100644 --- a/goalc/build_actor/common/animation_processing.cpp +++ b/goalc/build_actor/common/animation_processing.cpp @@ -21,7 +21,8 @@ int find_max_joint(const tinygltf::Animation& anim, const std::map& no template std::vector compute_keyframes(const std::vector& times, const std::vector& values, - float framerate) { + float framerate, + bool quaternion_interp) { std::vector ret; ASSERT(!times.empty()); ASSERT(times.size() == values.size()); @@ -36,8 +37,15 @@ std::vector compute_keyframes(const std::vector& 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 std::vector> extract_keyframed_gltf_vecn( const tinygltf::Model& model, const tinygltf::AnimationSampler& sampler, - float framerate) { + float framerate, + bool quaternion_interp) { std::vector times = gltf_util::extract_floats(model, sampler.input); std::vector> values = gltf_util::extract_vec(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); }