Unity公式のスプラインツールで作成した曲線の情報をスクリプトからあれこれしたい場合はどうすればいいの?
Splinesパッケージの公式リファレンスを交えながら解説していくね。
Unity公式のビルトインスプラインツール(Splinesパッケージ)で作成したスプラインをスクリプトから読み書きする方法の紹介です。
これらの情報は以下公式リファレンスにまとめられています。
スプラインとスクリプトを連携させることで、例えば次のようなことが可能になります。
- スプライン上の位置を取得する
- 道のりを計算する
- ある点に最も近いスプライン位置を計算する
- スプラインをスクリプトから作成する
ここに挙げた以外にも、工夫次第で様々なことが実現可能です。
本記事では、このようにスプラインとスクリプトと相互運用する方法について解説していきます。
- Unity 2022.1.0f1
- Splines 1.0.1
目次 非表示
前提条件
Unity 2022.1以降のUnityプロジェクトでSplinesパッケージがインストールされているものとします。
ここまでの手順がわからない方は、以下記事で導入手順をまとめていますのでご覧ください。
スプライン情報へのアクセス方法
スプライン情報は、SplineContainerクラスのコンポーネントが管理しています。
参考:Class SplineContainer| Splines | 1.0.1
スクリプトからは、例えば次のようにアクセスして使います。
ここからは、SplineContainerを通じてスプライン情報を取得したり、編集したりする例をいくつか紹介します。
スプライン上の位置を取得する
スプラインには始点と終点があり、両者を0~1の範囲で補間した位置を取得することができます。
取得には次のSplineContainer.EvaluatePositionメソッドを使います。
引数には、0~1の範囲で割合をしていします。0は始点、1は終点を意味します。言い換えると、視点からの移動距離を0~1に正規化した値を指定します。
戻り値は、計算されたスプライン上のワールド空間の位置です。
参考:Class SplineContainer| Splines | 1.0.1
戻り値の型はfloat3となっていますが、これはMathematicsパッケージで定義された独自のベクトル型です。Vector3型に暗黙的に変換できます。
参考:Struct float3| Mathematics | 1.2.6
ワールド空間の位置を取得する場合、SplineContainer.Spline.EvaluatePositionではなく、SplineContainer.EvaluatePositionメソッドを使用してください。
以下のようにすると、ローカル空間の位置となります。
サンプルスクリプト
オブジェクトをスプライン上の位置に動かすサンプルスクリプトです。
上記スクリプトをSplineFollow.csという名前でUnityプロジェクトに保存し、Spline Container、Follow Targetにそれぞれスプラインオブジェクト、スプラインに沿って移動させたいオブジェクトを指定します。
Percentageには0~1の範囲の割合を指定します。
実行結果
インスペクターからPercentageを変更すると、割合で補間されたスプライン位置にオブジェクトが動きます。
スプラインの場所によらず移動速度が一定になるように調整してくれます。
この辺の仕組みは、以下記事で解説しています。
スクリプトの解説
肝となる部分は以下コードです。
EvaluatePosition()メソッドで計算されたワールド位置をターゲットのワールド位置に指定しています。
これで、ターゲットがスプラインに沿って動くようになります。
スプライン全体の長さを計算する
始点から終点までの道のりは、以下メソッドで計算できます。
戻り値としてスプライン全体の長さが得られます。
参考:Class SplineContainer| Splines | 1.0.1
この全体の道のりを利用すると、割合tを用いて開始からの移動距離を求めたり、逆に移動距離から割合tを求めたりできます。
この始点からの移動距離と割合tの相互変換は、割合tに対してスプライン全体の道のりを掛けたり割ったりすることで求められるのは覚えておくと良いでしょう。
サンプルスクリプト
スプライン全体の道のりを利用して、始点から指定距離進んだ位置に移動するサンプルスクリプトです。
上記スクリプトをSplineLength.csとして保存し、インスペクターより各種設定を行うと機能します。
Distance From Startには、始点から進みたい距離を指定します。
実行結果
距離基準でオブジェクトが動くようになりました。
スクリプトの解説
以下コードで、スプラインの道のりと距離から割合を算出しています。
終点が1になるようにするには、進む距離を全体距離で割れば良いです。
そして、計算した割合をもとにスプライン上の位置を求めています。
コース上を移動するオブジェクトを作りたい場合に使えそうだね!
直近のスプライン位置を計算する
指定された位置に最も近いスプライン上の位置を計算するAPIも用意されています。
SplineUtilityクラスの以下メソッドを使います。
第1引数splineには、スプライン情報を指定します。SplineContainerではないことに注意する必要があります。(後述)
第2引数pointには、入力位置を指定します。
第3引数nearesetには、計算された直近のスプライン位置を受け取る変数を指定します。
第4引数tには、計算された割合を受け取る変数を指定します。
第5引数resolutionには、計算時の精度(セグメントの分割数)を指定します。この値が大きくなるほど計算精度が上がりますが、処理負荷も増大します。
第6引数iterationsには、計算の反復数を指定します。これも値が大きくなるほど計算精度と処理負荷が上がります。
参考:Class SplineUtility| Splines | 1.0.1
GetNearestPointメソッドには、もう一つオーバーロードされたメソッドが存在します。
違いは第2引数rayのみで、レイによる位置判定となっています。点ではなく線で計算したい場合はこちらが適しています。
サンプルスクリプト
直近の位置を視覚化するためのサンプルスクリプトです。
上記スクリプトをNearestPoint.csという名前で保存し、適当なオブジェクトにアタッチし、各種パラメータの設定を行うと機能します。
InputにはGetNearestPoint()メソッドに入力する位置を示すオブジェクトResultには、GetNearestPoint()メソッドの出力結果の位置を反映するオブジェクトを指定します。
実行結果
Inputオブジェクトを動かすと、それに追従するようにResultオブジェクトが直近のスプライン位置に移動します。
レースゲームで、コース上の車の位置や順位を計算したい場合に使えそうだね!
そうね、色々と応用できそうな機能だわ!
スクリプトの解説
今回はワールド空間での位置計算を行いたいため、スプラインの座標系変換を行っています。
生成しているNativeSplineインスタンスはSpline構造体の一種で、読み取り専用のスプライン情報を表します。内部的にはNativeArrayのテンポラリバッファを使っているため、パフォーマンスが最適化されています。
参考:Struct NativeSpline| Splines | 1.0.1
コンストラクタの第1引数にスプライン情報を指定します。通常は、SplineContainerのSplineプロパティを指定すれば良いです。
第2引数にワールド空間への変換行列を指定します。
スプラインのパスはローカル空間となっているためワールド空間への変換を行っています。座標空間が異なった状態で計算処理を進めると、出力結果の位置がずれるなど不具合が生じるためご注意ください。
そして、上で求めたワールド空間のスプライン情報をもとに、直近の位置計算を行っています。
スクリプトからスプラインを編集する
SplineContainerコンポーネントのSplineプロパティにスプラインのパスなど各種情報が格納されています。ここに対してポイントを追加・削除・編集などの操作ができます。
参考:Class Spline| Splines | 1.0.1
サンプルスクリプト
スプラインをスクリプトから作成する例です。
スクリプトをSplineEdit.csという名前で保存し、適当なオブジェクトにアタッチし、Spline Containerにスプラインをアタッチすると機能します。
どのような形状のパスを作成しているかは、コメントをご覧ください。
実行結果
確かにコメント通りのパスがスクリプトから作成されていることが確認できました。
さいごに
Unity公式のスプラインとスクリプトを連携する方法について解説しました。
スプライン情報へのアクセスは、SplineContainerコンポーネントを通じて行うことができます。
スクリプトと連携できれば、スプライン情報をもとにキャラクターを動かしたり、線を描画したりといった具合に、様々な応用が期待できるでしょう。