< 返回博客

MajiSpline一个关于链条的经验总结

#Spline #经验总结 #Unity

基础概念

Lerp插值

1. 一维lerp

从A到B,走到百分之t, 0<=t<=1

lerp(a, b, t)  = A * (1-t) + B * t

比如一条直线中A=10,B=20,t=0.2

lerp(A,B,t) = 10*(1-0.2)+20*0.2 = 8+4=12

2. 二维Lerp

A是点(ax,ay),B是(bx,by),t依然是百分比 点A到点B的方向向量v=B-A = (xb-xa,yb-ya) lerp(A,B,t)的意思是从点A出发沿着v的方向走到B的百分比t的那个点的坐标是多少。

lerp(A,B,t) = (
xa + t * (xb - xa),
ya + t * (yb-ya)
)

三维同理。

三次贝塞尔曲线

直观看

https://observablehq.com/@mbostock/de-casteljaus-algorithm?utm_source=chatgpt.com#cell-0

三次贝塞尔曲线

利用4个蓝色的点获得一条黑色点形成的路径曲线

4个点:P0,P1,P2,P3 ,图中为蓝色。

先在P0到P1,P1到P2,P2到P3插值,得到三个橘黄色点O1,O2,O3,

再在O1到O2,O2到O3差值,得到黑色点B1.

B1的所有差值点连成一起就是黑色曲线。

除了起点和终点,剩下的两个蓝色点就如Photoshop钢笔工具中的“手柄”。

Hermite曲线

https://spline.sudohub.dev/index.html 我知道起点来的方向,我知道终点走的方向,然后得到这个曲线。

CatmullRom曲线

简称CR曲线

https://www.desmos.com/calculator/9kazaxavsf?utm_source=chatgpt.com&lang=zh-CN

有四个点P0,P1,P2,P3. 目的是我们要得到P1到P2这一段的曲线, 用P0和P2得到P1附近的方向,用P1和P3得到P2附近的方向。 用前后相邻点,自动估计当前点的切线方向。

完全看不懂数学公式,嘻嘻

轨道投影法的问题

问题

我们通过上面的内容可以构造出任意的线。那么可以尝试生成轨道,首先利用”投影法”但会出现下面的问题:

扭曲的轨道

投影法:世界 Y+ 向量投影到切线的法平面上。

一般世界Y都是向上的,切线就是当前点的前进反向,所以在图片中的位置切线和Y反向几乎相同。

当切线趋近竖直(≈ 指向 ±Y)时,|dotTUp| → 1,法平面内几乎没有 Y+ 分量可提取,投影结果接近零向量,法线方向变得数值不稳定——只要轨道稍有左右偏,结果可能朝完全相反的方向,产生 180° 翻转。

竖向回环(Vertical Loop)在顶点处切线完全竖直,这就是问题的发生点。

解决 :平行传输(Parallel Transport)

平行传输不依赖世界坐标系,而是用帧间最小旋转把前一帧的法线”运输”到当前帧

// 每一帧:
const axis  = cross(prevTangent, currentTangent);   // 切线转动轴
const angle = acos(dot(prevTangent, currentTangent)); // 转动角
ptNormal = prevNormal.applyAxisAngle(axis, angle);   // 旋转传递

这样法线的传递完全由曲线几何自身决定,不涉及世界 Y+ 方向,切线垂直时也不会退化。

总结

有竖直的地方设置这一段采用平行传输,其他地方可以正常使用投影法。

平行传输的出口需要特别的考虑,进入平行传输段直接切换即可,但是退出需要做Holonomy补偿+100帧渐变。

Skills

详见 TrackNormalAndPT