テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】Unityでベジェ曲線(パス)を描く方法

f:id:tsubaki_t1:20180831144240j:plain

今回はUnityで曲線を描く方法について紹介します。

 

 

Unity 2018.1でVector Graphicが導入可能に

Unity 2018.1からVector Graphicsのプレビュー版が導入可能になり、SVGといったフォーマットのファイルも使用可能になりました。

ファイルサイズの割にエッジの綺麗な絵を出しやすいのが良いですね

https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20180523/20180523000844.jpg

tsubakit1.hateblo.jp

今回はそのランタイムAPIを使用して線を描画してみます。
なおVector Graphicsはその設計上、UIには使用できません。Graphicコンポーネントを拡張すれば行けるかもしれませんが、云々。

 

Vector Graphicsでベジェ曲線を描画する

Vector Graphicsの導入手順は省略して、ランタイムAPIを使用してパスを描画していきます。

まずパスの元となるオブジェクト郡を用意していきます。操作しやすくするため、アイコンの色も変えておいた方が良いです。P0は特別なので、大アイコンとかにしとくと良いです。P1~P2はベジェ曲線のためのものです。

  • S0-P0(青
  • S0-P1(青
  • S0-P2(赤
  • S1-P0(赤
  • S1-P1(赤
  • S1-P2(緑
  • S2-P0(緑

f:id:tsubaki_t1:20180831154723j:plain

次にサンプルコードを導入して設定していきます。

f:id:tsubaki_t1:20180831155323j:plain

gist.github.com

これでゲームを再生すると、線が描画されるようになります。
一致する色のGameObjectを動かせば線が変化します。

f:id:tsubaki_t1:20180831143950g:plain

なお、曲線はあくまでメッシュで描画しているので、あまり複雑なメッシュを描画すると負荷が上がるかもしれません(余程の量出ない限り大したことがないかもしれませんが…)

f:id:tsubaki_t1:20180831155847j:plain

 

Vector GraphicsのAPIを見てみる

線を描画するAPIを見ていきます。詳しい内容はマニュアルで確認できます。PackageManagerはUnityのバージョンに依存しないので、Package Managerからマニュアルを確認します。(URL的にバージョンでアドレスが変わりそうなので、直接リンクで紹介しにくい所)

f:id:tsubaki_t1:20180831145038j:plain

 

VectorGraphicの要素を構成するのは、概ね3つに分かれています。

Scene ジオメトリを生成する単位。SceneManagerのシーンとは別物
SceneNode 描画設定の階層化
IDrawable 描画するベクター情報を格納する。PathやShapeなどが指定できる

 

まず一番子の要素にIDrawableを継承したクラス、PathやShapeがあります。この2つは線や形状の情報で、どのような頂点でどのように塗りつぶすのか…といった形状の情報を格納します。

IDrawableを保持するのはSceneNodeです。SceneNodeは描画する対象情報の他に、クリップの情報やトランスフォーム(gameObject.transformとは別)といった、描画内容やオフセット等の情報を持っています。関係はIDrawableがMeshでSceneNodeがGameObjectと考えるとスッキリします。

Sceneはジオメトリを生成する単位です。基本的にSceneNodeをSceneに登録してメッシュやスプライトを作成します。なおSceneManagerのScene(Unity開発者が日常的に使用しているシーン)とは異なるものです。紛らわしい!!

f:id:tsubaki_t1:20180831170829j:plain

f:id:tsubaki_t1:20180831175350j:plain

実際のコードでは、まず最初にパスを作りSceneNodeに登録。描画する線は一本なのでSceneNode一つだけ作成して、ソレをSceneに登録しています。

f:id:tsubaki_t1:20180831171708j:plain

後は作成したSceneをVectorUtilsを通してMeshもしくはSpriteに変換します。
変換する際に、TessellationOptionに指定したパラメータを要求します。

f:id:tsubaki_t1:20180831172132j:plain

f:id:tsubaki_t1:20180831172823j:plain

 

PathのAPIを見てみる

PathのAPIを見てみます。
PathはBezierPathSegmentの配列とBezierPathSegmentのP0, P1, P2で構築していきます。P0が座標、P1とP2がカーブの為の情報です。

少し厄介なのが、P2が次のBezierPathSegmentから伸びるカーブ情報という点です。例えば下の場合、赤い頂点の左側のカーブの情報は、segment0.p2に強く依存しています。

f:id:tsubaki_t1:20180831154002j:plain

実際のコードでsegmentsのIDと上の画像の各ノードの色合いを比較すると、何となく立ち位置が分かるんじゃないかなと思います。

f:id:tsubaki_t1:20180831173100j:plain

なお毎フレームメシュを更新するのは何となくアレなので、コードではTransformが変化したタイミングでのみTransformの座標にアクセスし情報を抽出しています。

 

感想

VectorGraphicsで曲線を描いてみました。LineRendererで曲線を書くのと異なり保持すべき情報が少ないので、色々と良いんじゃないかなという気がしています。
特にプロシージャルに綺麗な曲線が引けるのは中々に良いです。

なお、単純に動的に画像をロードしたいんだ!という場合には普通にImportSVGしてしまうのが良さそうです。テキストのSVG定義データそのまま読めます。

 

関連

サンプルプロジェクト

github.com