mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-10-30 23:15:32 +01:00 
			
		
		
		
	Fix interpolating to identity bone overrides (#16609)
The previous code immediately dropped identity overrides, even if there still was an interpolation to be done. Also a little bit of cleanup, and setting an appropriate identity default for the scale property when interpolating. For modders: As a workaround, you can add a tiny offset so that overrides aren't identity overrides.
This commit is contained in:
		| @@ -95,7 +95,7 @@ core.register_entity("testentities:sam", { | ||||
| 		self.object:set_bone_override("Head", { | ||||
| 			scale = { | ||||
| 				vec = vector.new(s, s, s), | ||||
| 				absolute = true, | ||||
| 				absolute = false, | ||||
| 				interpolation = self._head_anim_duration, | ||||
| 			}, | ||||
| 		}) | ||||
|   | ||||
| @@ -66,12 +66,12 @@ struct BoneOverride | ||||
| 		v3f previous; | ||||
| 		v3f vector; | ||||
| 		bool absolute = false; | ||||
| 		f32 interp_timer = 0; | ||||
| 		f32 interp_duration = 0.0f; | ||||
| 	} position; | ||||
| 
 | ||||
| 	v3f getPosition(v3f anim_pos) const { | ||||
| 		f32 progress = dtime_passed / position.interp_timer; | ||||
| 		if (progress > 1.0f || position.interp_timer == 0.0f) | ||||
| 		f32 progress = dtime_passed / position.interp_duration; | ||||
| 		if (progress > 1.0f || position.interp_duration == 0.0f) | ||||
| 			progress = 1.0f; | ||||
| 		return position.vector.getInterpolated(position.previous, progress) | ||||
| 				+ (position.absolute ? v3f() : anim_pos); | ||||
| @@ -85,14 +85,14 @@ struct BoneOverride | ||||
| 		// so that we can return them in the appropriate getters
 | ||||
| 		v3f next_radians; | ||||
| 		bool absolute = false; | ||||
| 		f32 interp_timer = 0; | ||||
| 		f32 interp_duration = 0.0f; | ||||
| 	} rotation; | ||||
| 
 | ||||
| 	v3f getRotationEulerDeg(v3f anim_rot_euler) const { | ||||
| 		core::quaternion rot; | ||||
| 
 | ||||
| 		f32 progress = dtime_passed / rotation.interp_timer; | ||||
| 		if (progress > 1.0f || rotation.interp_timer == 0.0f) | ||||
| 		f32 progress = dtime_passed / rotation.interp_duration; | ||||
| 		if (progress > 1.0f || rotation.interp_duration == 0.0f) | ||||
| 			progress = 1.0f; | ||||
| 		rot.slerp(rotation.previous, rotation.next, progress); | ||||
| 		if (!rotation.absolute) { | ||||
| @@ -107,27 +107,35 @@ struct BoneOverride | ||||
| 
 | ||||
| 	struct ScaleProperty | ||||
| 	{ | ||||
| 		v3f previous; | ||||
| 		v3f vector{1, 1, 1}; | ||||
| 		v3f previous = v3f(1.0f); | ||||
| 		v3f vector = v3f(1.0f); | ||||
| 		bool absolute = false; | ||||
| 		f32 interp_timer = 0; | ||||
| 		f32 interp_duration = 0.0f; | ||||
| 	} scale; | ||||
| 
 | ||||
| 	v3f getScale(v3f anim_scale) const { | ||||
| 		f32 progress = dtime_passed / scale.interp_timer; | ||||
| 		if (progress > 1.0f || scale.interp_timer == 0.0f) | ||||
| 		f32 progress = dtime_passed / scale.interp_duration; | ||||
| 		if (progress > 1.0f || scale.interp_duration == 0.0f) | ||||
| 			progress = 1.0f; | ||||
| 		return scale.vector.getInterpolated(scale.previous, progress) | ||||
| 				* (scale.absolute ? v3f(1) : anim_scale); | ||||
| 				* (scale.absolute ? v3f(1.0f) : anim_scale); | ||||
| 	} | ||||
| 
 | ||||
| 	f32 dtime_passed = 0; | ||||
| 	f32 dtime_passed = 0.0f; | ||||
| 
 | ||||
| 	bool finishedInterpolation() const | ||||
| 	{ | ||||
| 		return dtime_passed >= std::max(std::max( | ||||
| 				position.interp_duration, rotation.interp_duration), | ||||
| 				scale.interp_duration); | ||||
| 	} | ||||
| 
 | ||||
| 	bool isIdentity() const | ||||
| 	{ | ||||
| 		return !position.absolute && position.vector == v3f() | ||||
| 		return finishedInterpolation() | ||||
| 				&& !position.absolute && position.vector == v3f() | ||||
| 				&& !rotation.absolute && rotation.next == core::quaternion() | ||||
| 				&& !scale.absolute && scale.vector == v3f(1); | ||||
| 				&& !scale.absolute && scale.vector == v3f(1.0f); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
|   | ||||
| @@ -702,17 +702,21 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) | ||||
| 			}); | ||||
| 
 | ||||
| 			m_animated_meshnode->setOnAnimateCallback([&](f32 dtime) { | ||||
| 				for (auto &it : m_bone_override) { | ||||
| 					auto* bone = m_animated_meshnode->getJointNode(it.first.c_str()); | ||||
| 					if (!bone) | ||||
| 						continue; | ||||
| 
 | ||||
| 					BoneOverride &props = it.second; | ||||
| 				for (auto it = m_bone_override.begin(); it != m_bone_override.end();) { | ||||
| 					BoneOverride &props = it->second; | ||||
| 					props.dtime_passed += dtime; | ||||
| 
 | ||||
| 					bone->setPosition(props.getPosition(bone->getPosition())); | ||||
| 					bone->setRotation(props.getRotationEulerDeg(bone->getRotation())); | ||||
| 					bone->setScale(props.getScale(bone->getScale())); | ||||
| 					if (props.isIdentity()) { | ||||
| 						it = m_bone_override.erase(it); | ||||
| 						continue; | ||||
| 					} | ||||
| 
 | ||||
| 					if (auto *bone = m_animated_meshnode->getJointNode(it->first.c_str())) { | ||||
| 						bone->setPosition(props.getPosition(bone->getPosition())); | ||||
| 						bone->setRotation(props.getRotationEulerDeg(bone->getRotation())); | ||||
| 						bone->setScale(props.getScale(bone->getScale())); | ||||
| 					} | ||||
| 					++it; | ||||
| 				} | ||||
| 			}); | ||||
| 		} else | ||||
| @@ -1689,9 +1693,9 @@ void GenericCAO::processMessage(const std::string &data) | ||||
| 			props.scale.previous = props.scale.vector; | ||||
| 		} else { | ||||
| 			// Disable interpolation
 | ||||
| 			props.position.interp_timer = 0.0f; | ||||
| 			props.rotation.interp_timer = 0.0f; | ||||
| 			props.scale.interp_timer = 0.0f; | ||||
| 			props.position.interp_duration = 0.0f; | ||||
| 			props.rotation.interp_duration = 0.0f; | ||||
| 			props.scale.interp_duration = 0.0f; | ||||
| 		} | ||||
| 		// Read new values
 | ||||
| 		props.position.vector = readV3F32(is); | ||||
| @@ -1703,19 +1707,15 @@ void GenericCAO::processMessage(const std::string &data) | ||||
| 			props.position.absolute = true; | ||||
| 			props.rotation.absolute = true; | ||||
| 		} else { | ||||
| 			props.position.interp_timer = readF32(is); | ||||
| 			props.rotation.interp_timer = readF32(is); | ||||
| 			props.scale.interp_timer = readF32(is); | ||||
| 			props.position.interp_duration = readF32(is); | ||||
| 			props.rotation.interp_duration = readF32(is); | ||||
| 			props.scale.interp_duration = readF32(is); | ||||
| 			u8 absoluteFlag = readU8(is); | ||||
| 			props.position.absolute = (absoluteFlag & 1) > 0; | ||||
| 			props.rotation.absolute = (absoluteFlag & 2) > 0; | ||||
| 			props.scale.absolute = (absoluteFlag & 4) > 0; | ||||
| 		} | ||||
| 		if (props.isIdentity()) { | ||||
| 			m_bone_override.erase(bone); | ||||
| 		} else { | ||||
| 			m_bone_override[bone] = props; | ||||
| 		} | ||||
| 		m_bone_override[bone] = props; | ||||
| 	} else if (cmd == AO_CMD_ATTACH_TO) { | ||||
| 		u16 parent_id = readS16(is); | ||||
| 		std::string bone = deSerializeString16(is); | ||||
|   | ||||
| @@ -668,7 +668,7 @@ int ObjectRef::l_set_bone_override(lua_State *L) | ||||
| 
 | ||||
| 		lua_getfield(L, -1, "interpolation"); | ||||
| 		if (lua_isnumber(L, -1)) | ||||
| 			prop.interp_timer = lua_tonumber(L, -1); | ||||
| 			prop.interp_duration = lua_tonumber(L, -1); | ||||
| 		lua_pop(L, 1); | ||||
| 	}; | ||||
| 
 | ||||
| @@ -718,7 +718,7 @@ static void push_bone_override(lua_State *L, const BoneOverride &props) | ||||
| 		lua_newtable(L); | ||||
| 		push_v3f(L, vec); | ||||
| 		lua_setfield(L, -2, "vec"); | ||||
| 		lua_pushnumber(L, prop.interp_timer); | ||||
| 		lua_pushnumber(L, prop.interp_duration); | ||||
| 		lua_setfield(L, -2, "interpolation"); | ||||
| 		lua_pushboolean(L, prop.absolute); | ||||
| 		lua_setfield(L, -2, "absolute"); | ||||
|   | ||||
| @@ -312,9 +312,9 @@ std::string UnitSAO::generateUpdateBoneOverrideCommand( | ||||
| 	props.rotation.next.toEuler(euler_rot); | ||||
| 	writeV3F32(os, euler_rot * core::RADTODEG); | ||||
| 	writeV3F32(os, props.scale.vector); | ||||
| 	writeF32(os, props.position.interp_timer); | ||||
| 	writeF32(os, props.rotation.interp_timer); | ||||
| 	writeF32(os, props.scale.interp_timer); | ||||
| 	writeF32(os, props.position.interp_duration); | ||||
| 	writeF32(os, props.rotation.interp_duration); | ||||
| 	writeF32(os, props.scale.interp_duration); | ||||
| 	writeU8(os, (props.position.absolute & 1) << 0 | ||||
| 	          | (props.rotation.absolute & 1) << 1 | ||||
| 	          | (props.scale.absolute & 1) << 2); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user