HN 日本語サマリー

← 一覧へ戻る
プログラミング

曲率ベジェ曲線 – 時代を超えたレシピの改良

Curvature Beziers – Improving on a timeless recipe (acko.net)

16 pointsby boxed1 コメント

要約

ベジェ曲線はCADやコンピュータグラフィックスの基本的な要素ですが、その単純さゆえに欠点も抱えています。この記事では、既存のベジェ曲線の技術基盤を維持しつつ、曲率を直接操作することで編集体験を大幅に向上させる新しいアプローチを提案しています。これにより、より直感的で安定した曲線編集が可能になります。

全文翻訳

2026年8月16日 曲率ベジェ曲線 – 時代を超えたレシピの改良 ベジェ曲線はCADやコンピュータグラフィックスの定番です。Bicペンと同じように、そのデザインは数十年前のもので、どこにでもあります。多くのイラストレーションやアニメーションツールで、デフォルトまたは唯一の選択肢として見かけることが多いでしょう。 1959年にポール・ド・カステリョ(Paul de Casteljau)によって考案され、1960年代にルノーでピエール・ベジェ(Pierre Bézier)によって洗練されたベジェ曲線の永続的な魅力は、その単純さにあります。より洗練された曲線が発明され、新しいものが提案され続けていますが、それらは高精度CADや道路設計のような特定のドメインに限定されています。一般的な用途では、欠点があるにもかかわらず、ベジェ曲線は王座から退くことを頑なに拒否しています。したがって、ベジェ曲線は私たちが stuck with(付き合わざるを得ない)レガシー技術の一部なのです。 ソフトウェアエンジニアとして、私の疑問はこうです。それらとその上で構築されたすべての技術を無効にすることなく、ベジェ曲線をより良くすることはできるでしょうか?答えは「はい」です。 ソース: Lerp-a-derp ベジェ曲線の描画は、驚くほどシンプルで線形なプロセスです。 ヒント: この投稿のすべての図は完全にインタラクティブです。 制御点の系列を線で結びます。次に、それらの線に沿って同時に実行し、新しい点を生成します。これを繰り返し、最終的に曲線上の単一の点に至ります。この構成により、ベジェ曲線は最初に現れるよりもはるかに規則的になります。 線形補間(lerpとも呼ばれる)は、単一のコンパクトな数式に要約できます。例えば、4つの制御点 $ \left(A, B, C, D\right) $ の場合: $$ \gamma \left( t \right) = A \cdot \left(1 - t\right)^3 + B \cdot 3 \left(1 - t\right)^2 t + C \cdot 3 \left(1 - t\right) t^2 + D \cdot t^3 $$ ルールは単純です: $ \left(1 - t\right) $ のべき乗は減少し、 $ t $ のべき乗は増加し、係数はパスカルの三角形のn行目から取られます: $$ \begin{array}{ccccccccccccc} &&&&&& 1 \ &&&&& 1 && 1 \ &&&& 1 && 2 && 1 \ &&& 1 && 3 && 3 && 1 \ && 1 && 4 && 6 && 4 && 1 \ &1 && 5 && 10 && 10 && 5 && 1 \ ... &&&&&& ... &&&&&& ... \ \end{array} $$ 2Dおよび3Dの曲線では、この数式は個々のX、Y、またはZ座標に適用されます。ベジェ曲線は任意の数の制御点で構築できますが、一般的な慣習では4つの制御点を持つ3次ベジェ曲線のみが使用されます。これは、曲線が最初と最後の制御点を通ることが保証されているだけで、高次のベジェ曲線は形状を整えるのが難しいためです。より大きな曲線は、複数の3次ベジェセグメントを結合して構築され、接線が揃えられて滑らかに見えるセグメント化された曲線が作成されます。 これが一般的に理解されている3次ベジェスプラインです。ほとんどの描画アプリの「ペンツール」は、曲線自体を直接描画するのではなく、制御点を描画および編集することで構成されています。 どこでも語られる嘘 ペンツールには通常、制御点のいくつかの異なるモードがあります。 直感的には、これらは様々な程度の滑らかさを表します。対称な接線は最も滑らかなオプションとして提供され、制約を緩和するとある程度の滑らかさが失われます。実際にはこれは完全に間違っており、簡単に証明できます。 ベジェ曲線は、補間図から新しい制御点を読み取ることで正確に分割できます。 左右のセグメントは元の曲線と100%同一であり、常に継ぎ目で完璧に結合します。しかし、中央の接線は、中央付近の1つの分割を除いて非対称になります。これは、曲率(または曲率半径の逆数)を各点で表す曲率コームを使用して確認できます。 曲率コームは、ジャンプなしで連続しています。これは、隣接する接線の長さが等しいかどうか、つまり対称であるかどうかは完全に無関係であることを意味します。このように滑らかで直感的なベジェ曲線を描こうとするのは、徒労です。 これを改善する簡単な方法は、接線を絶対的なものとしてではなく相対的なものとして扱うことです。例えば、それらを各セグメントの始点と終点の間の距離に比例させることができます。 このスプラインは編集が容易です。なぜなら、各曲線点を移動すると、隣接するセグメントが邪魔にならないように自然にたわむからです。この方法では、尖点(cusp)の発生がはるかに少なくなります。接線の編集は同じままです。しかし、曲率を再びプロットすると、これは良い解決策ではないことがわかります。 接線を比例的にスケーリングしても、編集時に曲率が保存されることは保証されませんし、セグメント間で曲率が連続したままになることもありません。これはまた、ユーザーに「役立つツール」として曲率コームの可視化を提供することが実際には非常に意地悪であることを示しています。片方の端の曲率を調整すると、反対側にも影響するため、十分な値になるまで繰り返し調整する必要があります。 慎重に扱う より効果的な戦略は、曲率を直接扱うことです。これは一般的に難しい問題ですが、直接観察できる驚くべき関係があることがわかります。 セグメント $ A-B-C-D $ の開始点での曲率を考えます。これは $ A $、$ B $、$ C $ の位置のみに影響されます。 $ D $ は $ C $ から切り離されていれば自由に移動できます。さらに、接線 $ A-B $ が水平であるため、$ C $ の垂直位置のみが重要です。これは、数式で多くの項がキャンセルされる、基盤となる線形補間の結果です。したがって、$ A $ における曲率は、$ A-B $ の長さと、$ C $ から $ A-B $ までの垂直距離のみに影響されます。 $ D $ についても、$ C-D $ と $ B $ を用いて同様に適用されます。 これだけではあまり役に立ちません。曲線点($ A $ または $ D $)を移動すると、通常、接線を維持するために隣接する制御点($ B $ または $ C $)も移動されます。そして、対称または非対称な接線を回転させると、次のセグメントの隣接する接線も同じ角度で回転し、その側の曲率が変化します。 それでも、これは曲率を維持することが単に狂った考えではなく、接線を適切にスケーリングするだけで簡単に行えることを示しています。ルールは単純になります。 曲線点を移動する場合、隣接するセグメントの始点と終点の曲率を維持する必要があります。 接線を移動する場合、現在のセグメントの反対側の端の曲率、および隣接するセグメントの両側の曲率を維持する必要があります。 これにより、曲線が意図を実際に尊重する編集体験が得られるはずです。ただし、完全ではありません。 曲線点の移動はうまく機能しますが、接線を回転させるとき、その接線の長さ自体がユーザーの意図の乏しい表現になります。小さな変更が大きな曲率の変化を引き起こし、一致する解を見つけようとする際に、曲線が予期せずジャンプして爆発する可能性があります。 したがって、長さが直接曲率に対応する曲率ハンドルを使用する方が良いです。 曲率コームとは異なり、ハンドルの長さは曲率の非逆数であり、より自然な選択です。これらのハンドルは非常に安定しており、2つの表現の間を行き来することなく、必要に応じて(just-in-time)従来のベジェ制御点に変換できます。これは数値ドリフトを回避するのにも役立ちます。 ゴルディロックス これを実際に実現するには、所望の曲率 $ k_0 $ と $ k_1 $、始点/終点 $ A $ と $ D $、および始点/終点の単位長接線が与えられた場合に、接線の長さ $ l_0 $ と $ l_1 $ を解く必要があります。曲線 $ \gamma\left(t\right) $ を与えると、単位接線ベクトル $ \mathbf{T}\left(t\right) $ を正規化された導関数として表現できます。 $$ \mathbf{T}\left(t\right) = \frac{\displaystyle \gamma'\left(t\right)}{\displaystyle |\gamma'\left(t\right)|} $$ これを使用して、最初の導関数と2番目の導関数との2つのベクトル外積により、曲率ベクトル $ \mathbf{K}\left(t\right) $ を見つけることができます。 $$ \mathbf{K}\left(t\right) = \mathbf{T}\left(t\right) \times \frac{\gamma''\left(t\right)}{|\gamma'\left(t\right)|^2} \times \mathbf{T}\left(t\right) $$ 外積は $ \mathbf{K}\left(t\right) $ が $ \mathbf{T}\left(t\right) $ に垂直であることを保証します。つまり、それらは抽出します