godot 简单实用的旋转和位移平滑插值方案, tween 版本, 方案1 是通用的 unity 支持


#相机平滑视角移动
 
#旧方案  移动超过360 或者负数的角度,会转大圈,也有可能会遇到万向节死锁的问题
func camera_move_old(move_node,move_pos:Vector3,move_rot:Vector3,time):
	var tween=create_tween().set_parallel()
	tween.tween_property(move_node,"global_position",Vector3(move_pos),time)
	tween.tween_property(move_node,"global_rotation",Vector3(move_rot),time)
	pass

#方案1 采用四元数完成 平滑插值 
func camera_move(move_node,move_pos:Vector3,move_rot:Vector3,time):
	var tween=create_tween().set_parallel()
	tween.tween_property(move_node,"global_position",Vector3(move_pos),time)
	# init 初始化 旋转的平滑插值 
	var basis = Basis()
#	欧拉角的默认旋转顺序: YXZ 
	var axisX = Vector3(1, 0, 0)
	var rotation_amountX = (move_rot.x)
	var axisY = Vector3(0, 1, 0)
	var rotation_amountY = (move_rot.y)
	var axisZ = Vector3(0, 0, 1)
	var rotation_amountZ = (move_rot.z)
	
	basis = Basis(axisZ, rotation_amountZ) * basis
	basis = Basis(axisX, rotation_amountX) * basis
	basis = Basis(axisY, rotation_amountY) * basis
	
	var my_lambda = func (weight): 
		var a = Quaternion(basis)
		var b = Quaternion(move_node.transform.basis)
		var c = a.slerp(b,weight/100.0)
		move_node.transform.basis = Basis(c)
	pass
	
	tween.tween_method(func(weight): my_lambda.call(weight), 0, 100,time)

	pass

#方案2 采用I3D 的提供的API interpolate_with 完成平滑插值
func camera_move_2(move_node,move_pos:Vector3,move_rot:Vector3,time):
	var tween=create_tween().set_parallel()
	
	# init 初始化 旋转的平滑插值 
	var basis = Basis()
#	欧拉角的默认旋转顺序: YXZ 
	var axisX = Vector3(1, 0, 0)
	var rotation_amountX = (move_rot.x)
	var axisY = Vector3(0, 1, 0)
	var rotation_amountY = (move_rot.y)
	var axisZ = Vector3(0, 0, 1)
	var rotation_amountZ = (move_rot.z)
	
	basis = Basis(axisZ, rotation_amountZ) * basis
	basis = Basis(axisX, rotation_amountX) * basis
	basis = Basis(axisY, rotation_amountY) * basis
	
	var target_transform = Transform3D(basis,move_pos) #init 旋转和位移
	var my_lambda = func (weight): 
		move_node.transform  = move_node.transform.interpolate_with(target_transform, weight/100.0)
	pass
	
	tween.tween_method(func(weight): my_lambda.call(weight), 0, 100,time)

	pass

  


 
godot 引擎源码的实现方案:interpolate_with 方法的实现(考虑了缩放和归一化的问题)

Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const {
    Transform3D interp;

    Vector3 src_scale = basis.get_scale();
    Quaternion src_rot = basis.get_rotation_quaternion();
    Vector3 src_loc = origin;

    Vector3 dst_scale = p_transform.basis.get_scale();
    Quaternion dst_rot = p_transform.basis.get_rotation_quaternion();
    Vector3 dst_loc = p_transform.origin;

    interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c));
    interp.origin = src_loc.lerp(dst_loc, p_c);

    return interp;
}

 

posted @ 2023-12-20 16:58  porter_代码工作者  阅读(937)  评论(0)    收藏  举报