【Houdini/Unity】旗を作成して頂点シェーダーで動かす

 
 

はじめに

Houdiniを使用して旗を作成し、Unityの頂点シェーダーで旗を動かすまでの手順を解説します。
旗にシェーダーを適用した結果

旗にシェーダーを適用した結果

Houdiniを利用した旗の作成

以下のような旗を作成します。
Houdiniで作成する旗

Houdiniで作成する旗

必要なパラメータの洗い出し

今回は、以下のような旗を作ることを考えてみます。
パラメータを洗い出し

パラメータを洗い出し

 
 
以下のパラメータが必要になりそうです。
  • 柱の高さ (Height )
  • 旗の大きさ (Field Scale X, Field Scale Z)
  • 柱のてっぺんのすき間 (Field Margin Top)

パラメータを定義し、モデルの形状として利用したい場合、

HoudiniではSubnetworkを利用するのが定番です。

Subnetworkはフォルダみたいなもので、内部にノードを持つことができます。

Subnetworkの作成

Networkビュー上でTabキーを押し、Subnetworkノードを作成します。
Subnetwork作成

Subnetwork作成

 

Subnetworkの名前はFlagにします。

 

名前をFlagにする

名前をFlagにする

Subnetworkへパラメータ登録

Subnetworkの歯車アイコンをクリックします。

歯車アイコンをクリック

歯車アイコンをクリック

Edit Parameter Interfaces… を選択します。

Edit Parameter_Interface を選択

Edit Parameter_Interface を選択

 

以下のようなパラメータ編集画面が出現します。

 

パラメータ追加方法

左側のリストからFloatを選択した状態で矢印をクリックすることでFloatパラメータ(実数を扱うパラメータ)を追加することができます。

画面右側からはパラメータの範囲やパラメータ初期値を設定できます。

 

以下はパラメータ名がheight、ウィンドウ上に表示されるラベルがHeight、

値の範囲 0 ~ 10、初期値3のFloatパラメータを追加する手順をキャプチャしたGIF動画です。

パラメータの追加方法

パラメータの追加方法

 

追加するパラメータ

今回は height, field_margin_top, field_size_x, field_size_yを定義します。

定義するパラメータ

定義するパラメータ

今回は以下のような数値を設定しました。

パラメータの設定値

パラメータの設定値

 

パラメータの設定が終わったらSubnetworkを選択した状態でIキーを押し、中に入ります。

 

今回作成したSubnetworkの中身

今回作成したSubnetwork

今回作成したSubnetwork

柱を作成する

旗の柱の部分を作成するノード構成です。
今回作成する柱

今回作成する柱

 

順番に見ていきます。

 

Boxノード

Boxノードで縦に細長い箱を作成します。
Boxノードの設定

Boxノードの設定

 

ch(“../height”)について
BoxノードのSizeのYの部分にch(“../height”)と入力されていますが、
これはSubnetworkノードのパラメータheightの数値を利用するという意味です。
Boxパラメータについて

Boxパラメータについて

 

たとえば、Subnetworkのheightに3.0が入力されていた場合、BoxのSizeのYの部分にも3.0が入ります。
heightに2.0が入力されていた場合、BoxのSizeのYの部分には2.0が入ります。

 

Transformノード

Transformノード

Transformノード

Transformノードを利用して、Y方向に高さの半分だけ動かします。
ch(“../height”)/2と入力することで、パラメータheightを2.0で割った数値だけ移動します。

Groupノード

最後のGroupノードを使って、柱にグループを設定しています。
グループは、マテリアルを設定する際に必要となる情報です。
グループ設定

グループ設定

 

以上で柱は完成です。

 

旗を作成する

次に旗を作成します。

 

Gridノード

Gridノードを使うことで、四角形が作成されます。
Gridノード

Gridノード

 

旗をそのまま重ねると位置がずれてしまう

形状はこれで完成ですが、そのまま重ねると旗に柱が突き刺さったような配置になっており、形状が破綻しています。
 
不正な重ね方

不正な重ね方

 

旗の位置修正

Transformノードを使って旗の位置を合わせたものが以下です。
正しい重ね方

正しい重ね方

 

実際にノードを見ていきます。
 

Gridノード(動かす前の旗)

動かす前の旗は以下のような配置になっています。
動かす前の旗の位置

動かす前の旗の位置

 

旗のX方向の位置を合わせる

Transformノードを使って 旗の横サイズfield_size_xの半分だけX方向に動かします。
TransformノードのXの部分に以下を入力します。
ch("../field_size_x")/2
 
旗をX方向に動かす

旗をX方向に動かす

 

柱の高さに合わせる

旗の横サイズheightのY方向へ動かします。
TransformノードのYの部分に以下を入力します。
ch("../height")
 
旗をY方向に動かす

旗をY方向に動かす

 
 
この状態では、旗が半分だけはみ出ているので半分だけ下に動かす必要があります。
旗がY方向に半分はみ出ている

旗がY方向に半分はみ出ている

 

旗のY方向の位置を合わせる

旗を半分だけ下に動かします。
TransformノードのYの部分に以下を入力します。
-ch("../field_size_y")/2
 
旗をY方向に大きさの半分だけ動かす

旗をY方向に大きさの半分だけ動かす

 

旗のマージンだけ動かす

最後に、旗の位置を後から調整できるように マージン値field_margin_topだけ下にずらして位置の調整は終わりです。
TransformノードのYの部分に以下を入力します。
-ch("../field_margin_top")
 
旗をY方向にマージンの長さだけ動かす

旗をY方向にマージンの長さだけ動かす

 

以上で位置調整は完了です。

 

グループ設定

後からマテリアルを設定できるようにGroupノードを使ってグループを設定します。
旗のグループ設定

旗のグループ設定

 

OBJ出力

ROP Geometryノードを使ってobjファイルをエクスポートします。
OBJファイルエクスポート

OBJファイルエクスポート

 

 

Unity上の作業

エクスポートしたobjをUnityにインポートすると、以下のようにマテリアルがモデルが分けられた状態になっています。
旗OBJをUnityに取り込んだ状態

旗OBJをUnityに取り込んだ状態

 
 
FlagFieldとFlagPoleという二つのモデルが見えますが、これはHoudini上で設定したグループに対応したものとなっています。
Houdini上のグループとUnity上で読まれるモデルの対応関係

Houdini上のグループとUnity上で読まれるモデルの対応関係

 

シェーダー・マテリアルの設定

Projectビューで右クリックして、シェーダーを作成します。
シェーダーを作成

シェーダーを作成

 
 
シェーダーを以下のように書き換えます。
sin波を利用して頂点座標をZ方向に揺らすシェーダーです。
 
 
Shader "Unlit/UnlitFlag"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
        _WaveSpeed ("WaveSpeed", Float) = 8.0
        _WaveFreq("Wave Frequency", Float) = 1.0
        _WaveAmp("Wave Amplitude", Float) = 0.25
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Cull Off
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };
            #define PI 3.14159265358979
            
            sampler2D _MainTex;
            float4 _Color;
            float4 _MainTex_ST;
            float _WaveFreq;
            float _WaveSpeed;
            float _WaveAmp;
            
            v2f vert (appdata v)
            {
                v2f o;
                float wave = sin(v.vertex.x * _WaveFreq * 2.0 * PI + _Time.y * _WaveSpeed) * _WaveAmp; // sin wave
                wave *= v.vertex.x;
                v.vertex.z += wave;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv) * _Color;
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}
 
 
 
シェーダーを右クリックして、メニューの中からCreate/Materialを選択してマテリアルを作成します。
シェーダーを右クリックしてマテリアルを作成

シェーダーを右クリックしてマテリアルを作成

 
 
作成したマテリアルを旗にアタッチすることで旗が揺れるようになります。
マテリアルを旗モデルに登録する

マテリアルを旗モデルに登録する

旗にシェーダーを適用した結果

旗にシェーダーを適用した結果

 

STYLYにPrefabをアップロードする方法

STYLYにPrefabをアップロードする方法については下記リンクをご覧ください