Unity中的数学应用 之 插值函数处理角色朝向 (初中难度 +Matlab)
CodeMonkey教程: https://www.youtube.com/watch?v=QDWlGOocKm8
Siki学院汉化教程:如何使用Unity开发分手厨房(胡闹厨房)-Unity2023 - SiKi学院|SiKi学堂 - unity|u3d|虚幻|ue4/5|java|python|人工智能|视频教程|在线课程
版本:Unity6
模板:3D核心(渲染管线:URP)
1.情景
在3D之中,角色移动朝向处理起来非常简单,因为我们可以获取tranform.forward,也就是当前对象的朝向(在unity之中为左手坐标系,所以对象正朝向为(0,0,1))
接上一节:Unity中的数学应用 之 角色移动中单位化向量的妙用 (小学难度)-CSDN博客 只需要如下代码即可更改朝向
if(move!= Vector3.zero) {
transform.forward =move;
}
但是这样直接赋值给朝向向量会比较生硬
我们要采用平滑曲线让其有个旋转的过程
2.Vector3.Lerp:线性插值函数
但不是Mathf.Lerp,因为其是处理单个向量的
我们需要的是让角色朝向 =>输入朝向(transform.forward =>move)
unity中的Vector3就有封装好的Lerp
transform.forward = Vector3.Lerp(transform.forward, move,Time.deltaTime* roteSpeed);
瞅瞅其背后的公式:
- ( a ) 是起始向量
- ( b ) 是结束向量
- ( t ) 是插值因子,范围在 [0, 1] 之间
还是不直观,我直接用用matlab去绘制一下
% 起始向量和结束向量
a = [0, 0, 0];
b = [10, 10, 10];
% 插值因子 t 的范围
t = linspace(0, 1, 100);
% 计算 Lerp 插值
lerp_x = a(1) + (b(1) - a(1)) * t;
lerp_y = a(2) + (b(2) - a(2)) * t;
lerp_z = a(3) + (b(3) - a(3)) * t;
% 绘制曲线
figure;
plot3(lerp_x, lerp_y, lerp_z, '-o');
xlabel('X');
ylabel('Y');
zlabel('Z');
title('Vector3.Lerp 曲线');
grid on;
result = start + t * (end - start),这么来看result的线性的
但是,因为用的是start = start + t * (end - start),而start是复用的不是不变的值,所以就会出现如下的啸问题,我用另外一个例子去直观地描述:
该脚本挂载在A对象,end代表B对象
public Transform end;
private void Update() {
this.transform.position = Vector3.Lerp(this.transform.position,end.position,0.01f);
}
表现为先慢后快,所以在朝向问题上可以选择另外一种插值:球形插值
3.Vector3.SLerp:球形插值函数
这个公式貌似有点复杂,实际上确实有点复杂
请看动画:“四元数的线性插值”与“球面线性插值”的动画理解_哔哩哔哩_bilibili
其中的角度是向量 a 和 b 之间的角,借用matlab来看其曲线似乎能窥探之一二
% 定义两个初始向量(示例中为二维向量,可类比三维情况)
u = [1, 0]; % 可以理解为方向向量,比如Unity中的某个方向
v = [0, 1]; % 另一个方向向量
% 生成插值参数t的一系列值,这里取多个值来体现曲线变化
t = linspace(0, 1, 100); % 从0到1均匀取100个值用于插值
% 计算向量u和v的夹角的余弦值
cos_omega = dot(u, v) / (norm(u) * norm(v));
% 得到夹角(保证在[0, pi]区间)
omega = acos(cos_omega);
% 进行Slerp插值
interpolated_vectors = zeros(length(t), 2); % 用于存储插值后的向量
for i = 1:length(t)
st = sin((1 - t(i)) * omega) / sin(omega);
tt = sin(t(i) * omega) / sin(omega);
interpolated_vectors(i, :) = st * u + tt * v;
end
% 绘制曲线,展示插值过程中向量端点的轨迹
plot(interpolated_vectors(:, 1), interpolated_vectors(:, 2));
xlabel('X');
ylabel('Y');
title('Slerp Interpolation Curve');
grid on;
要是究其根本来讲:四元数存在于四维空间中,Slerp 操作相当于在这个四维超球面上找到两个四元数对应的点,并沿着连接这两点的大圆弧进行插值
这个大圆弧在四维空间中的性质类似于二维圆上的弧,具有某种意义上的 “均匀性”,确保了插值过程中旋转速度和方向的平稳变化
要是简单来讲:因为图像中这个圆弧的曲率在各方向(点)上是一致的,当start点向end点移动,是按照这个曲线去“滑行”的,因此就十分平滑且均匀
实现了以下效果:
4.总结
虽然这个问题初中生来了都能解决,但确实是u3d中不可忽视的细节,我将通过线性代数和微积分深挖unity之中一些背后的数学知识
最后,这个视频说不定可以帮助你理解:有关插值的一切_哔哩哔哩_bilibili