こんにちは、セガゲームス龍が如くスタジオの伊地知です。
去年もHoudiniのお話をこのSEGA TECH Blogで掲載しており、これで二回目となります。
さる2018年12月2日にCEDEC+KYUSHU2018が開催されたのですが
その時私の方で講演させていただいたTricks of Realtime VFX with Houdiniというセッションがありまして
(セッションのスライドはこちら からダウンロード出来ます。)
そのスライドの後半に
「実際にすぐにゲームに出して使えるエフェクトのテクニック」=「トリック」
を3つご紹介させて頂きました。
その3つのトリックを今回のSEGA TECH Blogで詳細に解説させて頂きます。
加工して戻す(RestSOP) ー processAndRest01.hip
独自シミュレーション(SolverSOP)
最短経路探索(FindShortestPath)
3ついっぺんにやると果てしなく長いので全部で3回に分け、
今回は1つ目である「加工して戻す」というトリックだけを扱うことにします。
シーンファイルもご利用頂けますしHoudiniの体験版(Apprentice版)でも開けますので
実際にご自身のPC(Windows)、Mac、Linuxで確認しながらご覧になるとご理解いただきやすいでしょう。
(HoudiniはいろんなOSに対応しています!)
今回は初心者の方でも安心の詳細解説となっております。
またwrangleの行数も最低限に抑えてあります。
操作方法や基礎知識に関しては1年前の前回のHoudiniの回でも
techblog.sega.jp
御紹介させおりますのでその辺が分からない方はそちらも合わせてご覧下さい。
1.加工して戻す(RestSOP)
では1つ目のトリックの内容から説明させて頂きます。
Houdiniの新規シーンを開いた想定でお話をさせて頂きます。
ダウンロードして頂いた方はシーンを上から順にデータを見ていって下さい。
まず画面一番左下のボタン
を押してGlobal Animation Optionsを開きます。
FPS を30 、End を256 にしてSaveAsDefault ボタンを押します。
ネットワークエディタのオブジェクトレベルでTabキーを押しTabメニューでgeと押すと候補が出ますのでGeometryを選び作ります。
できたgeo1にダブルクリックやiキーなどでジオメトリレベルに潜ります。
たいていの作業はこのジオメトリレベルで行う事になります。
TabメニューからSphere を選択してPrimitiveTypeをPolygon
Frequencyを50 にします。
次にTabメニューからUVTexture を出してつなげます。
TextureTypeをPolar 、Fix Boundary Seamsにチェック します。
この状態でビュー上でSpace+5 を押すとUVの状態が確認出来ます。
UVが01の範囲内からはみ出していると都合が悪いので
TabメニューからUV Transform を出してUV Textureにつなげ
Scale のX の値に 1/$XMAX と入力します。
これはUV値のUの最大値で全体を割るという意味で
こうする事によって01の範囲内に収めます。
ビュー上でSpace+1 を押してPerspectiveに戻します。
TabメニューからPointWrangle を出してUV Transformの出力につなげます。
ポイントアトリビュートの@rest,@Cd,@Alphaを設定します。
VEXpressionの欄に下記のコードを記述します。
v@rest = @P;
f@Alpha = 0.0;
@Cd = {1,1,1};
@はアトリビュートという意味でジオメトリのクラス(Point,Vertex,Primitive,Detail)自体に持たせる変数です。@の前のvやfは型を指定しておりvならベクター、fならフロートを定義します。ここではRunOverがPointになっているのでPointのクラスのアトリビュートを制御するという事になります。
@restはポジション(@P)を保持しておく為のアトリビュート。
頂点α(@Alpha)は0で初期化、頂点カラー(@Cd)は白で初期化という意味になります。
TabメニューからPointWrangle を出して先程のPointWrangleにつなげます。
f@Alpha = 1.0;
VEXpressionの欄にはこの様に記述します。
再度Alphaを1にするのには訳がありますがそれはあとで解説します。
TabメニューからTwist( or Bend) を出して先程のPointWrangleにつなげます。
Limit Deformation to Capture Region のチェックを外し
Twist の値を360 、Capture Origin のZを-1 、Capture Length を2 にします。
こうする事で球がZ軸に沿って360度ねじれます。
TabメニューからMountaion を出して先程のBendにつなげます。
MountainノードのHeight を1.73 、Element Size を2.18 、Scale を0.06 ,0.16 ,0.06、
Offset のX 値を-14 に設定しY 値は20 に設定し1フレーム目 でAltキーを押しながらクリック 、256フレーム目 で18 と設定しAltキーを押しながらクリック 。
これでパラメータの欄が緑色になったのが分かります。
これはアニメーションが設定されていますという事を現しています。
ちなみにShiftを押しながらクリックでアニメーションエディタが開きます。
Max Octaves を9 、Lacunarity を2.19 、Roughness を0.407 とします。
この状態で再生ボタン(画面左下にあります)を押すか、カーソルキーの↑を
押してみて下さい。
球のトゲトゲが蠢きながら下に流れていくアニメーションが確認出来ます。
確認出来たら停止ボタン(画面左下にあります)を押すか、Ctrl+↑を押して止めて下さい。
TabメニューからTransform を出して先程のMountainにつなげます。
Rotate のX 値を31 、Y 値を5 、Z 値を5 とし少し回転させます
TabメニューからClip を出して先程のTransformにつなげます。
先程と同じ要領でDistance の1フレーム目 に-1.25 、256フレーム目 に1.36 とキーを打ちます。
この状態で再生させると下半分が削れた状態が段々と上に上がっていって
トゲトゲの球が消えていくのが分かります。
TabメニューからPointWrangle を出して先程のClipにつなげます。
@P = @rest;
VEXPressionの欄にこの1行を入力すると歪められていたポイントのポジションが元に戻ります。
この挙動を不思議に思う方もいらっしゃるかもしれませんがこれは
単純に@restに保持していた座標で元の位置に戻っただけなのです。
しかし消されたポイントは戻りません。
歪んだ状態で水平に切るという事は座標を戻すと水平では無く歪んだ状態で削れていくのです。
↑キーで再生させるとこの様に動作しているのが確認出来るでしょう。
映像の表現ならここまでで良いですがゲームの場合
ゲーム中で表現する為に工夫が必要です。
CEDEC+KYUSHU2018では私はテクスチャパターンアニメーションでやりましょうと言ってしまいましたが実はもっと良いαカットオフを用いた手法があります。
シェーダ側でαしきい値を用いて透明にするのですが
そのαをどう出すのかがこのトリックの鍵になります。
2つ目のトリックで紹介するSolverというノードをもうここで使います。
毎フレーム値を加工して蓄積させていく事が出来るノードで評価した結果を
キャッシュしておくことが出来ます。
TabメニューからSolver を出して上から4つ目のpointwrangle1から
左から1番目のところにつなげて左から二番目の入力にpointwrangle3をつなげます。
ダブルクリックしてsolver1の中に潜ります。
TabメニューからAttributeTransfer を出してPrev_Frameを第一入力に
Input_2を第二入力につなげPointsにチェックを付けAlphaを指定します。
AttributeTransferは第一入力に対し第二入力のアトリビュートを近いものから転写していくノードです。MayaであればTransferAttribute、Softimageをお使いだった方ならGATORを御存知だと思いますがその万能版だと思って頂ければ理解が早いかと思います。(Softimageユーザーの方ならMayaのTransferAttributeなんかと比べられるのは屈辱だと思いますがHoudiniのAttributeTransferからすればどちらも五十歩百歩です。)
SolverSOPの中でこの様なつなぎ方をすると前のフレームの結果に対し現在のフレームの第二入力のアトリビュートを転写するという意味を持ちます。
TabメニューからPointWrangle を出して第一入力にPrev_Frame、第二入力にAttributeTransferをつなげます
VEXpressionの欄には
@Alpha += @opinput1_Alpha/256;
と記述します。
このコードと接続の意味は前のフレームの結果のアルファに対し
第二入力のアルファを256で割った数値を加算するという意味になります。
つまりこの2つのノードの意味は毎フレーム現在のアルファ値の1/256を
加算し続けるということになります。
uキーで1つ上の階層に戻って256フレーム目まで進めます。
すると球がこの様に見えているはずです。
毎フレームアルファ値を累積して256フレーム分貯めた結果がこれです。
これをUV座標に基づいてテクスチャに書き出してやります。
GameDevelopmentToolsetのSimpleBakerを使うやり方が最も簡単でしょう。
GameDevelopmentToolsetのインストールの最も簡単な方法は左上の
GameDevelopmentToolsetタブのUpdateToolsetボタンを押すことです。
ゲーム会社や映像スタジオ、CGスクールなどでプロキシ環境下であれば
この機能がうまくいかない場合があります。
その際は公式のgithub からダウンロードして手動でインストールして下さい。
GameDevelopmentToolsetがインストールされた状態になったら
TabメニューからGameDev Simple Baker を出して下さい。
ここで普通に考えればアルファにチェックを入れれば出力出来るはずなんですが
何故か真っ白になってしまうので一旦@Cdに@Alphaを移して
basecolorとして出力する事になります。
simple bakerの1つ前にPointWrangle を足して
@Cd = @Alpha;
記述して頂点カラーにアルファを移してからsimple baker でテクスチャを焼きます。
すると
この様なテクスチャが焼き上がりますのでPhotoshop上でレベル補正かけたり
トーンカーブで補正かけたりして1~254くらいの値の範囲にしておくと
シェーダに食わせた時の見た目が良い様です。
モデルの方も同時に出力しておきます。
UVを設定したuvtransform1から出すと良いのですがそのままだと
25,000頂点もありかなりメモリを食ってしまいます。
uvtransform1の下にPolyReduce を作ってつなげます。
Percent To Keep を1 にVertex Attribute Seams を0.4 にして頂点数を252にまで
落とします。ゲーム内で綺麗に見える最低限の頂点数であれば Percent To Keepを
いろいろ試してみても良いでしょう。
TabメニューからROP FBX Output を出してつなげます。
Output File を指定してSave to Disk ボタンを押します。
これでモデルファイルも出力出来ました。
ではUnity上で確認してみましょう。
普通のスタンダードシェーダでは両面に対応していないので
Create -> Shader -> Standard Surface Shader
で作ったものにちょい足ししたシェーダで表示してみましょう。
Shader "Custom/doubleSidedCutOff" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_Cutoff ( "Cutoff", Range(0, 1) ) = 0.5
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_BumpMap ( "Normal Map" , 2D ) = "bump" {}
_BumpScale ( "Normal Scale" , Range(0,1) ) = 1.0
}
SubShader{
Tags {
"Queue" = "AlphaTest"
"RenderType"="TransparentCutout"
}
LOD 200
Cull Off
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows alphatest:_Cutoff
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
sampler2D _BumpMap;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
half _BumpScale;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o)
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
fixed4 n = tex2D( _BumpMap, IN.uv_MainTex);
o.Normal = UnpackScaleNormal(n, _BumpScale);
}
ENDCG
}
FallBack "Transparent/Cutout/VertexLit"
}
このシェーダをアサインしたマテリアルを用意して適当なテクスチャを貼ってあげます。
その際テクスチャのアルファに先程生成したテクスチャを入れ込んでおきます。
するとこの様に表示されます。
VIDEO youtu.be
@restに座標を保持して戻す時に削れたpointが戻らないのは当然としても
生成されたpointがちゃんと良い感じの場所に戻ってくれるのは凄いと思います。
中で一体どういう処理が走ってるんでしょうか?気になります。
累積アルファのカットオフはテクスチャパターンアニメーションでやるより
遥かに質も向上しメモリも削減出来る賢いやり方なので
覚えておいて損は無いでしょう。
さて今回はここまでです、いかがでしたでしょうか? ゲームに出力する部分は様々な手法を考慮し工夫する必要があります。
現状ビルボードが主流のゲームエフェクトですがこんなトリックを用いる事で思いがけない表現をプレイヤーの方々にお見せし感動体験を演出する事も可能になるのです。
ゲームエンジン側の知識もフル動員すればもっと凄いものが表現出来るでしょう。
勉強する事は山程ありますし考えなければいけない事もいっぱいあります。
ですがやりたい表現が達成出来た時の喜びもまたひとしおです。
次回のHoudiniの記事もお楽しみに。
この記事に興味を持って頂けた方は弊社で私達と一緒に働いてみませんか?
弊社ではHoudiniに興味を持って取り組めるような人を募集しています! 我こそはという方、興味のある方は以下のリンクを是非クリックしてみてください。
sega-games.co.jp
©SEGA