平滑算法:三次樣條插值(Cubic Spline Interpolation)


https://blog.csdn.net/left_la/article/details/6347373

感謝強大的google翻譯。

我從中認識到了航位推算dead reckoning,立方體樣條Cubic Splines 算法。

我單獨查找了 Cubic Splines ,里面的原理簡單說明:

Cubic Splines 認為在 x 在[a, b]區間中,y對應是一條平滑的曲線,所以 y = f(x); 的一階導函數和二階導函數是平滑連續可導的。

擬定用三次方程,所以得出了一般的三次方程和一階導數方程和二階導數方程。

然后求各個分部的解。

 

這是三次樣條的基本原理。

但文中最開始的鏈接中所得出的

x = At3 + Bt2 + Ct + D
y = Et3 + Ft3 + Gt + H

t是percent(0~1)區間值,如果還有三維向量,我理解是同樣的展開。

然后通過四個位置點來求出 A B C D … 各分部參數的值

A = x3 – 3x2 +3x1 – x0
B = 3x2 – 6x1 + 3x0
C = 3x1 – 3x0
D = x0

E = y3 – 3y2 +3y1 – y0
F = 3y2 – 6y1 + 3y0
G = 3y1 – 3y0
H = y0

相同分量展開。(如果有Z 分量的話)

學藝不精,無法從現有姿勢推出這個分量求解過程。

 

實時運動游戲是通過預測其他玩家的位置來表現的,當服務器有新的輸入的時候,本地玩家會發現其他玩家位置或狀態發生一次跳變(瞬移)。

有兩種思路,

一、預測未來

  1. 通過當前位置和速度,通過預測未來精度(1s或者0.5s)推測出未來位置.
  2. 得出公式參數,通過dt來平滑當前運動軌跡。

二、延遲渲染

  1. 通過延遲渲染參數(延遲1s,0.5s來)來獲得其他玩家的過去狀態位置。
  2. 得出公式參數,通過dt來平滑運動軌跡。

 

上述兩種方案

  1. 如果參數一致,速度不改,則運動軌跡跟預測一致,如果玩家輸入多變,則永遠不會是真實的位置。
  2. 看到的玩家的過去位置,移動軌跡跟目標玩家運動軌跡基本保持一致。

 

https://gist.github.com/svdamani/1015c5c4b673c3297309#file-spline-c-L26

 1 /** Numerical Analysis 9th ed - Burden, Faires (Ch. 3 Natural Cubic Spline, Pg. 149) */
 2 #include <stdio.h>
 3 
 4 int main() {
 5     /** Step 0 */
 6     int n, i, j;
 7     scanf("%d", &n);
 8     n--;
 9     float x[n + 1], a[n + 1], h[n], A[n], l[n + 1],
10         u[n + 1], z[n + 1], c[n + 1], b[n], d[n];
11     for (i = 0; i < n + 1; ++i) scanf("%f", &x[i]);
12     for (i = 0; i < n + 1; ++i) scanf("%f", &a[i]);
13 
14     /** Step 1 */
15     for (i = 0; i <= n - 1; ++i) h[i] = x[i + 1] - x[i];
16 
17     /** Step 2 */
18     for (i = 1; i <= n - 1; ++i)
19         A[i] = 3 * (a[i + 1] - a[i]) / h[i] - 3 * (a[i] - a[i - 1]) / h[i - 1];
20 
21     /** Step 3 */
22     l[0] = 1;
23     u[0] = 0;
24     z[0] = 0;
25 
26     /** Step 4 */
27     for (i = 1; i <= n - 1; ++i) {
28         l[i] = 2 * (x[i + 1] - x[i - 1]) - h[i - 1] * u[i - 1];
29         u[i] = h[i] / l[i];
30         z[i] = (A[i] - h[i - 1] * z[i - 1]) / l[i];
31     }
32 
33     /** Step 5 */
34     l[n] = 1;
35     z[n] = 0;
36     c[n] = 0;
37 
38     /** Step 6 */
39     for (j = n - 1; j >= 0; --j) {
40         c[j] = z[j] - u[j] * c[j + 1];
41         b[j] = (a[j + 1] - a[j]) / h[j] - h[j] * (c[j + 1] + 2 * c[j]) / 3;
42         d[j] = (c[j + 1] - c[j]) / (3 * h[j]);
43     }
44 
45     /** Step 7 */
46     printf("%2s %8s %8s %8s %8s\n", "i", "ai", "bi", "ci", "di");
47     for (i = 0; i < n; ++i)
48         printf("%2d %8.2f %8.2f %8.2f %8.2f\n", i, a[i], b[i], c[i], d[i]);
49     return 0;
50 }

這個上面根據 https://fac.ksu.edu.sa/sites/default/files/numerical_analysis_9th.pdf#page=167

實現了對應 x 求 y 的函數,這里x可以替換成 時間t,分別求 t 跟x 、y、z的abcd參數,最終求出s(t)函數。

 

INPUT

n; x0, x1, ... , xn;

a0 = f (x0), a1 = f (x1), ... , an = f (xn).

OUTPUT aj, bj, cj, dj for j = 0, 1, ... , n − 1.

(Note: S(x) = Sj(x) = aj + bj(x − xj) + cj(x − xj)2 + dj(x − xj)3 for xj ≤ x ≤ xj+1.).

最后通過x在哪個區間調用某個區間的 S(x) 函數。注意S(x)函數是一組函數,x多區間。

(或許上面兩個文章介紹的其實不是一種算法 0.0)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM