はじめに
前回「Houdini Engine for Unity でインスタンスを配置する」という記事を書きました。
この記事では題名のとおり、Houdini Engine for Unityを使ってUnityの中でプロシージャルにオブジェクトのインスタンスを配置する方法をご紹介しています。記事に載っている手順と講演動画、サンプルプロジェクトを見て頂けば比較的簡単に同じことが出来るようになると思います。
ただ、この手法でインスタンス配置が出来るようになった後、多くの方が同じ悩みに突き当たるのではと予想しています。それは**「配置したインスタンスに望んだ向き(回転)を設定するにはどうしたらよいのか」**です。実はHoudini Engineを使ったインスタンス配置は、配置とスケール設定はとても簡単に出来るのですが、回転だけは少し難易度が高く、先日の講演でも意図的に触れるのを避けていました。
その方法を今回の記事で書きたいと思います。
サンプルプロジェクトについて
今回も配布用のサンプルプロジェクトを作成しました。
Houdini Engine Instance Orient Sample.zip
※サンプルはUnity 2019.3.0f3、Houdini Core 18.0.348で作成しています
※動作にはHoudini CoreまたはFXのライセンスが必要になります
サンプルは以下4種類の方法でインスタンスをオブジェクトの表面に配置しています。
・ランダムに回転させて配置
・XYZいずれかの一軸で回転させて配置
・オブジェクトのY軸を配置する地面の傾きに合わせ、その軸で回転させて配置
・オブジェクトのZ軸を配置する壁面の傾きに合わせ、その軸で回転させて配置
PlaneとSphereのそれぞれに配置したものがシーンに置かれていますので、アクティブ/非アクティブを切り替えて結果をご確認ください。またこのサンプルのHDAはTerrainではないメッシュオブジェクトへの配置を行うものですので、Terrain上に配置を行いたい場合はHDAをHoudiniで編集する必要があります。
では、本題に入ります。
Houdini Engine の回転制御はQuaternion
まず、なぜHoudini Engine for Unityでの回転制御が難しいかという理由についてです。答えは見出しに書いたとおりなのですが、回転制御のために設定するアトリビュート**@orientがQuaternion(四元数)**だからです。Quaternionはアーティストが慣れ親しんだ3軸の回転ではなく名前のとおり4つの数字で回転を表現します。そしてこの数字はとても非直感的で、適当な数字を入れてもまず思ったような結果が得られません。
正しい道程としてはQuaternionを理解するところから始めるのでしょうが、(私もそれほどわかっていないので)今回は難しい話は置いてアーティストのための実務的な記事にしようと思います。
Quaternionを理解したい方にはとてもお勧めの動画があるので、最後に紹介します。
結論から書くと、Quaternionはいくつかの別の数値があればHoudiniで簡単に作る事が出来ます。
HoudiniでQuaternionを作る
HoudiniでQuaternionを作る場合はVEXが便利です。VOPでも作れるかもしれませんが、私はまだ試したことがありません。
Quaternionは以下のどちらからの情報があれば作る事ができます。
・1つのベクトル(回転軸)と回転角
・2つのベクトル(UpとNormal)
それぞれ、以下のようにquaternion関数を使う事で値を得る事ができます。
vector axis = {0,0,1}; //回転軸ベクトル
float angle = 360; //回転角(度)
//Quaternionの作成
vector4 @orient;
@orient = quaternion(radians(angle),axis);
※quaternion関数の回転角は度数ではなくラジアンなのでradians()でその変換を行っています。
vector normal = {0,0,1}; //Normalベクトル
vector up = {0,1,0}; //Upベクトル
//Quaternionの作成
vector4 @orient;
@orient = quaternion(maketransform(normal,up));
※こちらも実際に入力するのは3×3の回転行列なのでmaketransform()を使っています。
このサンプルコードはいずれも下の画像のように、HoudiniでScatterノードなどを使いポイントを生成した後にAttribute Wrangleノードを接続し、ノード内のVEXpressionに記載するという想定です。画像では通常のScatterノードを使っていますが、Terrain上に配置する場合はHeightField Scatterノードを使います。
2種類の作成方法を書きましたが、アーティストから見て直感的なのは後者、2つのベクトルから作成する方法だと思います。回転軸と角度は一見シンプルに見えますが、理解するのに少しコツが要る感じです。
しかし基本的にはこれだけで、Unityで配置されるインスタンスの回転をコントロールする事ができます。
具体的な回転制御のサンプル
回転の制御方法については以上なのですが、せっかくなのでより具体的なシチュエーションを想定したサンプルを作成してみました。以下4種類の手法で多くのパターンは網羅できるのではと思っています。また今回のサンプルでは全て個別にランダム回転させていますが、ここを任意の角度に変える事は難しくないと思います。
少し地味ですが、今回Unityでは下のようなオブジェクトのインスタンスを配置しました。Y方向に背が高く、先端がZ方向を向いている形状です。これで概ねインスタンスがどの方向を向いているかがわかると思います。
それでは順番にサンプルコードと結果のスクリーンショットを載せます。
ランダムに回転させて配置
//Unityインスタンスアトリビュートを生成
string @unity_instance = "Assets/Prefab/Test Object.prefab";
//Z方向のランダムなベクトル
vector normal;
normal = rand(@ptnum +10);
normal = normalize((normal *2) -1);
//Y方向のランダムなベクトル
vector up;
up = rand(@ptnum);
up = normalize((up *2) -1);
//2つのベクトルからクォータニオンを生成
vector4 @orient;
@orient = quaternion(maketransform(normal,up));
まずは全方向にランダムな回転を加えた配置です。サンプルのような棒状のオブジェクトではあまり使いませんが、岩の配置などにはよく使われる方法です。
XYZいずれかの一軸で回転させて配置
//Unityインスタンスアトリビュートを生成
string @unity_instance = "Assets/Prefab/Test Object.prefab";
//回転軸のベクトル
vector axis = {0,1,0}; //Y軸の場合
//vector axis = {1,0,0}; //X軸の場合
//vector axis = {0,0,1}; //Z軸の場合
//ランダムな回転(度)
float angle = rand(@ptnum) *360;
//設定した軸で回転
vector4 @orient;
@orient = quaternion(radians(angle),axis);
配置する場所の面の向きに関わらず、任意の軸を作り、その軸に対してランダムな回転をかける配置です。サンプルではY方向を軸としていますが、樹木や建物の配置などにはよくこの方法を使います。また壁面にディティール配置する際などにはこの軸をZ方向に変えたものを使う事もあります。
オブジェクトのY軸を配置する地面の傾きに合わせ、その軸で回転させて配置
//Unityインスタンスアトリビュートを生成
string @unity_instance = "Assets/Prefab/Test Object.prefab";
//ランダムな回転(度)
float angle = rand(@ptnum) *360;
//配置場所の法線をY軸に指定し、最初の回転
vector up = @N;
vector normal = cross(up,{0,1,0});
vector4 firstrot = quaternion(maketransform(normal,up));
//最初の回転に、ランダムの回転を追加
vector4 extrarot = quaternion(radians(angle),{0,1,0});
vector4 @orient;
@orient = qmultiply(firstrot, extrarot);
先ほどと似ていますが、これはインスタンスのY方向を配置位置の法線に合わせた上で、それを軸として回転を掛けるというサンプルです。球体に配置した例がわかりやすいと思います。この方法を使うと地形の傾きに合わせてインスタンスが配置出来るので、草や茂み、あるいは瓦礫のような背が低く設置面が広いオブジェクトを配置する際によく使われます。
オブジェクトのZ軸を配置する壁面の傾きに合わせ、その軸で回転させて配置
//Unityインスタンスアトリビュートを生成
string @unity_instance = "Assets/Prefab/Test Object.prefab";
//ランダムな回転(度)
float angle = rand(@ptnum) *360;
//配置場所の法線をZ軸に指定し、最初の回転
vector normal = @N;
vector up = cross(normal,{1,0,0});
vector4 firstrot = quaternion(maketransform(normal,up));
//最初の回転に、ランダムの回転を追加
vector4 extrarot = quaternion(radians(angle),{0,0,1});
vector4 @orient;
@orient = qmultiply(firstrot, extrarot);
これは先ほどのバリエーションのようなもので、オブジェクトの背を設置面の合わせるような形で、回転を加えています。これも崖や山肌など、壁面に対してインスタンスを設置したい場合によく使われる手法です。
サンプルは以上です。
最後に
Houdini Engine for Unityでのインスタンスの回転制御はVEXが中心でアーティストには少し難しく感じられるかもしれませんが、出来るだけそのままコピペできるようにコードを書いてみたのでぜひお試しください。Houdini Engine for Unityによる配置で回転制御が出来ると、通常考えうるインスタンスの配置パターンはほぼ実現できるのではないかと思います。
また実務面だけでなくもっとQuaternionを理解したいと思われた方には以下の動画をお勧めします。私もこれまで何度か観ていて、観るたびに少しずつ理解が進んでいるような気がしてます。
【Unity道場 大阪スペシャル in モリサワ 2017】クォータニオン完全マスター
プロシージャルなオブジェクト配置がこれまで以上に普及すればいいなと思っています。
ぜひ皆さんの制作にもお役立てください。