diff --git a/src/animation/state_machine.cpp b/src/animation/state_machine.cpp index 3b0b0061a..b927d6faf 100644 --- a/src/animation/state_machine.cpp +++ b/src/animation/state_machine.cpp @@ -339,12 +339,14 @@ struct AnimationNodeInstance : public NodeInstance Transform end_anim = resource->getBoneTransform(resource->getLength(), bone_idx); Transform start_anim = resource->getBoneTransform(0, bone_idx); Transform after = resource->getBoneTransform(time, bone_idx); - root_motion = (end_anim * before.inverted()) * (after * start_anim.inverted()); + root_motion.pos = end_anim.pos - before.pos + after.pos - start_anim.pos; + root_motion.rot = end_anim.rot * before.rot.conjugated() * (after.rot * start_anim.rot.conjugated()); } else { Transform after = resource->getBoneTransform(time, bone_idx); - root_motion = after * before.inverted(); + root_motion.pos = after.pos - before.pos; + root_motion.rot = before.rot.conjugated() * after.rot; } } else diff --git a/src/renderer/editor/import_asset_dialog.cpp b/src/renderer/editor/import_asset_dialog.cpp index e2a9a985d..a746288cf 100644 --- a/src/renderer/editor/import_asset_dialog.cpp +++ b/src/renderer/editor/import_asset_dialog.cpp @@ -193,6 +193,15 @@ int setParams(lua_State* L) else if (equalStrings(tmp, "-z")) dlg->m_model.orientation = ImportAssetDialog::Orientation::Z_MINUS_UP; } lua_pop(L, 1); + if (lua_getfield(L, 2, "root_orientation") == LUA_TSTRING) + { + const char* tmp = LuaWrapper::toType(L, -1); + if (equalStrings(tmp, "+y")) dlg->m_model.root_orientation = ImportAssetDialog::Orientation::Y_UP; + else if (equalStrings(tmp, "+z")) dlg->m_model.root_orientation = ImportAssetDialog::Orientation::Z_UP; + else if (equalStrings(tmp, "-y")) dlg->m_model.root_orientation = ImportAssetDialog::Orientation::X_MINUS_UP; + else if (equalStrings(tmp, "-z")) dlg->m_model.root_orientation = ImportAssetDialog::Orientation::Z_MINUS_UP; + } + lua_pop(L, 1); if (lua_getfield(L, 2, "lods") == LUA_TTABLE) @@ -1357,7 +1366,14 @@ struct ConvertTask LUMIX_FINAL : public MT::Task out_pos.x *= scale.x; out_pos.y *= scale.y; out_pos.z *= scale.z; - out_pos = fixOrientation(out_pos); + if (channel_idx == import_animation.root_motion_bone_idx) + { + out_pos = fixRootOrientation(out_pos); + } + else + { + out_pos = fixOrientation(out_pos); + } file.write(&out_pos, sizeof(out_pos)); } @@ -1372,7 +1388,14 @@ struct ConvertTask LUMIX_FINAL : public MT::Task for (const auto& rot : rotations) { Quat out_rot(rot.mValue.x, rot.mValue.y, rot.mValue.z, rot.mValue.w); - out_rot = fixOrientation(out_rot); + if (channel_idx == import_animation.root_motion_bone_idx) + { + out_rot = fixRootOrientation(out_rot); + } + else + { + out_rot = fixOrientation(out_rot); + } file.write(&out_rot, sizeof(out_rot)); } } @@ -1656,6 +1679,20 @@ struct ConvertTask LUMIX_FINAL : public MT::Task } + Quat fixRootOrientation(const Quat& v) const + { + switch (m_dialog.m_model.root_orientation) + { + case ImportAssetDialog::Y_UP: return Quat(v.x, v.y, v.z, v.w); + case ImportAssetDialog::Z_UP: return Quat(v.x, v.z, -v.y, v.w); + case ImportAssetDialog::Z_MINUS_UP: return Quat(v.x, -v.z, v.y, v.w); + case ImportAssetDialog::X_MINUS_UP: return Quat(v.y, -v.x, v.z, v.w); + } + ASSERT(false); + return Quat(v.x, v.y, v.z, v.w); + } + + aiQuaternion fixOrientation(const aiQuaternion& v) const { switch (m_dialog.m_model.orientation) @@ -1688,10 +1725,24 @@ struct ConvertTask LUMIX_FINAL : public MT::Task { switch (m_dialog.m_model.orientation) { - case ImportAssetDialog::Y_UP: return Vec3(v.x, v.y, v.z); - case ImportAssetDialog::Z_UP: return Vec3(v.x, v.z, -v.y); - case ImportAssetDialog::Z_MINUS_UP: return Vec3(v.x, -v.z, v.y); - case ImportAssetDialog::X_MINUS_UP: return Vec3(v.y, -v.x, v.z); + case ImportAssetDialog::Y_UP: return Vec3(v.x, v.y, v.z); + case ImportAssetDialog::Z_UP: return Vec3(v.x, v.z, -v.y); + case ImportAssetDialog::Z_MINUS_UP: return Vec3(v.x, -v.z, v.y); + case ImportAssetDialog::X_MINUS_UP: return Vec3(v.y, -v.x, v.z); + } + ASSERT(false); + return Vec3(v.x, v.y, v.z); + } + + + Vec3 fixRootOrientation(const Vec3& v) const + { + switch (m_dialog.m_model.root_orientation) + { + case ImportAssetDialog::Y_UP: return Vec3(v.x, v.y, v.z); + case ImportAssetDialog::Z_UP: return Vec3(v.x, v.z, -v.y); + case ImportAssetDialog::Z_MINUS_UP: return Vec3(v.x, -v.z, v.y); + case ImportAssetDialog::X_MINUS_UP: return Vec3(v.y, -v.x, v.z); } ASSERT(false); return Vec3(v.x, v.y, v.z); @@ -2436,6 +2487,7 @@ ImportAssetDialog::ImportAssetDialog(StudioApp& app) m_model.lods[2] = -1000; m_model.lods[3] = -10000; m_model.orientation = Y_UP; + m_model.root_orientation = Y_UP; m_model.position_error = 100.0f; m_model.rotation_error = 10.0f; m_model.time_scale = 1.0f; @@ -3315,6 +3367,7 @@ void ImportAssetDialog::onWindowGUI() ImGui::Checkbox("Remove doubles", &m_model.remove_doubles); ImGui::DragFloat("Scale", &m_model.mesh_scale, 0.01f, 0.001f, 0); ImGui::Combo("Orientation", &(int&)m_model.orientation, "Y up\0Z up\0-Z up\0-X up\0"); + ImGui::Combo("Root Orientation", &(int&)m_model.orientation, "Y up\0Z up\0-Z up\0-X up\0"); ImGui::Checkbox("Make physics convex", &m_model.make_convex); } diff --git a/src/renderer/editor/import_asset_dialog.h b/src/renderer/editor/import_asset_dialog.h index 464f405c8..1278f1c00 100644 --- a/src/renderer/editor/import_asset_dialog.h +++ b/src/renderer/editor/import_asset_dialog.h @@ -157,6 +157,7 @@ class ImportAssetDialog LUMIX_FINAL : public StudioApp::IPlugin bool gen_smooth_normal; bool remove_doubles; Orientation orientation; + Orientation root_orientation; bool make_convex; bool all_nodes; float position_error;