Curves & interpolation

Non-Uniform Rational B-Spline

NURBS

重みとノットを使って円弧などを精密に表す。

5 / 10

Interactive demo

Preparing the demo…

Non-Uniform Rational B-Spline

Drag to orbit, Ctrl/⌘ + scroll to zoom. Use two fingers on touch screens.

This explanation is currently available in Japanese.

ひとことで

Non-Uniform Rational B-Spline の略で、B スプラインの各制御点に重みを持たせ、ノット間隔も自由(非一様)にした曲線です。重みを使った有理式にすることで、多項式では表せない円・楕円・円弧を誤差ゼロで表現できます。CAD や 3D モデリングツールの標準的な曲線・曲面表現です。

ゲームでの使いどころ

  • 正確な円軌道:衛星、回転する砲台の射程、円形のアリーナの縁など、半径がずれると困る軌道。
  • CAD データの取り込み:工業製品や建築データは NURBS 曲面で作られていることが多く、ゲームに取り込む際にテッセレーション(三角形化)します。
  • エディタツール:直線・円弧・自由曲線を 1 つの表現で扱えるため、道路やレールの設計ツールの内部表現に使われます。
  • 重みによる局所的な引き寄せ:特定の制御点だけ曲線を強く引き寄せたいとき、位置を動かさずに重みで調整できます。

しくみ

各制御点 Pi\mathbf{P}_i に重み wiw_i を与え、重み付き平均を取ります。

C(u)=∑iNi,p(u) wi Pi∑iNi,p(u) wi\mathbf{C}(u) = \frac{\sum_i N_{i,p}(u)\,w_i\,\mathbf{P}_i}{\sum_i N_{i,p}(u)\,w_i}

分母があるので「有理(rational)」と呼びます。計算上は、点を同次座標 (wixi, wiyi, wizi, wi)(w_i x_i,\, w_i y_i,\, w_i z_i,\, w_i) に持ち上げて普通の B スプラインとして評価し、最後に ww で割るだけです。

円が正確に描ける理由は、円錐曲線(円・楕円・放物線・双曲線)が 2 次の有理式で表せるからです。4 分の 1 円は、角の制御点の重みを

w=cos⁡θ2=cos⁡45∘=22≈0.7071w = \cos\frac{\theta}{2} = \cos 45^\circ = \frac{\sqrt{2}}{2} \approx 0.7071

にした 2 次の有理ベジェで表せます。デモの円は、この 4 分の 1 円を 4 つつないだ 9 点のクランプ NURBS です。

  • w>22w > \frac{\sqrt{2}}{2}:その制御点に引き寄せられ、角ばった形(双曲線寄り)になる
  • w=1w = 1:通常の B スプライン(放物線)
  • w<22w < \frac{\sqrt{2}}{2}:制御点の影響が弱まり、内側へしぼむ(楕円寄り)

実装のポイント

  • three.js にもある:three/addons/curves/NURBSCurve.js と NURBSSurface.js で評価できます。
  • ゲーム内ではテッセレーションして使う:実行時に NURBS を直接評価するより、読み込み時にポリラインやメッシュへ変換するのが一般的です。
  • 重みは正の値に:0 や負の重みは分母が 0 になる箇所を生み、曲線が無限遠に飛びます。

つまずきやすい点

  • パラメータが等速にならない:正確な円でも、uu に対して角度は一定の速さで進みません(中央が速い)。等速で回したいなら弧長パラメータ化か、円なら角度を直接使います。
  • 扱いが複雑:ノット列、次数、重みの 3 つを正しく管理する必要があります。単に滑らかな経路が欲しいだけなら、ベジェやカトマル・ロムで十分なことがほとんどです。
  • 非一様ノットの意味:ノット間隔を変えると、区間ごとのパラメータの割り当てが変わり、形と速度分布の両方に影響します。

デモで試すこと

  1. 初期値の w≈0.707w \approx 0.707 では、青い曲線と灰色の真円が完全に重なり、「真円からの最大ずれ」が 0.0000 になります。
  2. スライダーで重みを 1.6 程度まで上げると、曲線が角の制御点(黄色)に引き寄せられ、四角に近づきます。赤い線は真円とのずれです。
  3. 重みを 0.3 程度まで下げると、曲線は内側へしぼみます。最後に「w = √2/2 に戻す」を押してください。

References

The Book of Shaders — Shaping Functions ↗

A general reference for this subcategory.