LoginSignup
18
3

More than 1 year has passed since last update.

TouchDesignerでHoudiniから書き出したVATを使用する

Last updated at Posted at 2020-12-18

2023年2月現在最新のVAT3.0の使用方法については以下の記事をご覧ください。

はじめに

この記事では、Houdiniから出力したVAT(Vertex Animation Texture)ファイル群をTouchDesignerで読み込み、再生する方法を解説します。

HoudiniのLabs Vertex Animation Textureノードには、Unreal EngineやUnityなど、ゲームエンジン向けに設定のプリセットが用意されていますが、今回はTouchDesigner側のアニメーション再生機能の実装ができるだけシンプルになるように、手動でパラメーターの設定を行い、書き出し作業を行います。
そのため、他のゲームエンジン用に書き出されたVATファイルをそのまま読み込んだり、本記事を元に作成したVATファイルを他の開発環境で読み込んでも、正しく動作しません。

なおTouchDesignerのVertex Shaderの実装方法は、Houdiniから書き出されたUE4のMaterial Blueprintを参考にしています。

検証環境

サンプルプロジェクト

以下のURLからダウンロードしてください。
https://drive.google.com/file/d/1kchKxh3PpYGo8r71aJLTNSbax0fvW5IX/view?usp=sharing

実装

HoudiniのLabs Vertex Animation TexturesノードのMethodの設定によって、書き出されるファイルやデータが変わるので、TouchDesigner側の実装方法も変わってきます。
Houdini 18.5では、以下の4つのMethodが使用できます。

Method 解説
Soft (Constant Topology) キャラクターアニメーションなど、各頂点の位置は変わるが頂点数は変わらず、エッジやプリミティブの構成も変化しないアニメーションを書き出す際に選択
Rigid (Rigid Body Topology) 破砕アニメーションなど、変形しない複数のピースのアニメーションを書き出す際に選択
Fluid (Changing Topology) 流体アニメーションなど、頂点の位置も頂点数も変わるアニメーションを書き出す際に選択
Sprite (Camera Facing Cards) パーティクルアニメーションなどを書き出す際に選択

以下、Soft, Rigid, FluidのMethodごとに、書き出し設定とTouchDesignerでの実装方法を解説していきます。

Soft (Constant Topology)

Houdiniでアニメーション作成

vat_Soft_houdini.jpg

人間の3Dモデルにmixamoでループする歩行アニメーションをつけました。
フレームによってポイントの色も変化させています。

Houdiniから書き出し

outにLabs vertex Animation Texturesノードを作成します。

vat_Soft_houdini_2.jpg

vat_soft.jpg

パラメーター設定

  1. User interface - Normalを設定
  2. Start/Endにアニメーションの開始フレーム、終了フレームを設定
  3. MethodSoft (Constant Topology)に設定
  4. SOP Pathで書き出したいSOPを選択
  5. Frame Rangeにアニメーションのフレーム数を設定
  6. Normalize data range to 0-1 spaceをオフにする
  7. 必要であれば、Target Texture Sizeを任意のサイズに変更
  8. Paths/Normalのチェックボックスをオンにする
  9. SOPが色情報を持っている場合、Paths/Colorのチェックボックスをオンにする
  10. Settings/Position CoordXYZ, +X +Y +Zに変更する
  11. Scale1に設定する
  12. Renderを押して書き出し

書き出されたファイル群の解説

以下のファイルが出力されます。
Paths/Project, Paths/Componentにチェックを入れ、任意のパスとファイル名で書き出すこともできます。

ファイル名 解説
[Project]/meshes/[Component]_mesh.fbx VATテクスチャ参照用のUVが追加されたFBX
[Project]/textures/[Component]_pos.exr 最初のフレームからの頂点位置の変化量を格納したテクスチャ
[Project]/textures/[Component]_norm.exr 各フレームでの法線を格納したテクスチャ
[Project]/textures/[Component]_col.exr 各フレームでの色情報のテクスチャ
[Project]/materials/[Component]_data.json アニメーション再生時に使用する、各種パラメーターのJson

また、書き出されたFBXには、以下の頂点アトリビュートが追加されています

SOPアトリビュート名 GLSLアトリビュート名 解説
uv(3), uv(4) UV[1].xy VATテクスチャ座標

TouchDesignerでアニメーション再生機能の実装

vat_soft_TD.jpg

書き出されたFBXとテクスチャを読み込み、マテリアルを作成します。
サンプルプロジェクト内のVAT_Soft_Simpleでは、Phong MATのVertex Shaderに、アニメーション再生機能を追加しました。
Uniform変数numOfFramesには、HoudiniのLabs vertex Animation TexturesノードのFrame Rangeの値を渡します。

// Phong_VAT_Soft

uniform vec4 uDiffuseColor;
uniform vec4 uAmbientColor;
uniform vec3 uSpecularColor;
uniform float uShininess;
uniform float uShadowStrength;
uniform vec3 uShadowColor;

// 頂点位置の変化量テクスチャ
uniform sampler2D VAT_Pos;
// 法線のテクスチャ
uniform sampler2D VAT_Norm;
// 色のテクスチャ
uniform sampler2D VAT_Col;

// アニメーションの時間(0-1)
uniform float time;
// アニメーションの総フレーム数
uniform int numOfFrames;

out Vertex
{
	vec4 color;
	vec3 worldSpacePos;
	vec3 worldSpaceNorm;
	flat int cameraIndex;
} oVert;

void main()
{
	// 現在のフレームを計算
	float frame = clamp(time, 0.0, 0.99999) * numOfFrames;
	
	// VATテクスチャ読み込み用のUVを作成
	float u = uv[1].x;
	float v = uv[1].y - (floor(frame) / numOfFrames);
	vec2 UV = vec2(u, v);
	
	// 頂点の位置の変化量を読み込み、初期位置に加算
	vec3 newPos = P + texture(VAT_Pos, UV).xyz;
	
	// 色を読み込み
	vec4 newCol = texture(VAT_Col, UV);
	
	// 法線を読み込み
	vec3 newNorm = texture(VAT_Norm, UV).xyz;
	
	
	// Positionを設定
	vec4 worldSpacePos = TDDeform(newPos);
	vec3 uvUnwrapCoord = TDInstanceTexCoord(TDUVUnwrapCoord());
	gl_Position = TDWorldToProj(worldSpacePos, uvUnwrapCoord);

#ifndef TD_PICKING_ACTIVE

	int cameraIndex = TDCameraIndex();
	oVert.cameraIndex = cameraIndex;
	oVert.worldSpacePos.xyz = worldSpacePos.xyz;
	
	// 色を設定
	oVert.color = TDInstanceColor(newCol);
	
	// 法線を設定
	vec3 worldSpaceNorm = normalize(TDDeformNorm(newNorm));
	
	oVert.worldSpaceNorm.xyz = worldSpaceNorm;

#else // TD_PICKING_ACTIVE

	TDWritePickingValues();

#endif // TD_PICKING_ACTIVE
}

実行結果

TDMovieOut.0.gif

Rigid (Rigid Body Topology)

Houdiniでアニメーション作成

vat_rigid_houdini.jpg

Rigid Bodiesシェルフ内のRBD Fractured Objectをもとにして、Voronoi Fractureで分割したSOPから破砕アニメーションを作成しました。

Houdiniから書き出し

vat_rigid_houdini_2.jpg

パラメーター設定

  1. User interface - Normalを設定
  2. Start/Endにアニメーションの開始フレーム、終了フレームを設定
  3. MethodRigid (Rigid Body Topology)に設定
  4. SOP Pathで書き出したいSOPを選択
  5. Frame Rangeにアニメーションのフレーム数を設定
  6. Normalize data range to 0-1 spaceをオフにする
  7. 必要であれば、Target Texture Sizeを任意のサイズに変更
  8. SOPが色情報を持っている場合、Paths/Colorをオンにする
  9. Settings/Position CoordXYZ, +X +Y +Zに変更する
  10. Settings/Rotation Coord+X+Y+Z+Wに変更する
  11. Scale1に設定する
  12. Renderを押して書き出し

書き出されたファイル群の解説

以下のファイルが出力されます

ファイル名 解説
[Project]/meshes/[Component]_mesh.fbx ピースごとの中心点を格納したCdアトリビュート, VATテクスチャ参照用のUVアトリビュートが追加されたFBX
[Project]/textures/[Component]_pos.exr 中心点の位置を格納したテクスチャ
[Project]/textures/[Component]_rot.exr 中心点の回転(クォータニオン)を格納したテクスチャ
[Project]/textures/[Component]_col.exr 色情報のテクスチャ
[Project]/materials/[Component]_data.json アニメーション再生時に使用する、各種パラメーターのJson

書き出されたFBXには、以下の頂点アトリビュートが追加されています

SOPアトリビュート名 GLSLアトリビュート名 解説
Cd(0), Cd(1), Cd(2) Cd.xyz ピースごとの中心点の初期位置
uv(3), uv(4) UV[1].xy VATテクスチャ座標

TouchDesignerでアニメーション再生機能の実装

vat_rigid_TD.jpg

サンプルプロジェクト内のVAT_Rigidを参照してください。
注意点としては、Houdiniからの書き出し時にNormalize data range to 0-1 spaceをオフにしていても、FBXのCdアトリビュートに含まれるピースの中心点の位置情報は0-1に正規化されてしまうため、HoudiniのVATノードのPivot Min / Maxの値をUniform変数で渡し、シェーダー内で初期フレームの中心点を計算する必要があります。


// Phong_VAT_Rigid

uniform vec4 uDiffuseColor;
uniform vec4 uAmbientColor;
uniform vec3 uSpecularColor;
uniform float uShininess;
uniform float uShadowStrength;
uniform vec3 uShadowColor;

// ピースの中心点の位置情報テクスチャ
uniform sampler2D VAT_Pos;
// 回転情報のテクスチャ
uniform sampler2D VAT_Rot;
// 色のテクスチャ
uniform sampler2D VAT_Col;

// アニメーションの時間(0-1)
uniform float time;
// アニメーションの総フレーム数
uniform int numOfFrames;

// 中心点の最小値
uniform float pivot_Min;
// 中心点の最大値
uniform float pivot_Max;

out Vertex
{
	vec4 color;
	vec3 worldSpacePos;
	vec3 worldSpaceNorm;
	flat int cameraIndex;
} oVert;

// ベクトルをクォータニオンで回転
vec3 rotateVectorByQuatenion(vec3 v, vec4 quat) {
	vec3 c1 = cross(quat.xyz, v.xyz);
	vec3 m1 = v.xyz * quat.w;
	vec3 a1 = c1 + m1;
	vec3 c2 = cross(quat.xyz, a1);
	vec3 m2 = c2 * 2.0;
	return m2;
}

void main()
{
	// 現在のフレームを計算
	float frame = clamp(time, 0.0, 0.99999) * numOfFrames;
	
	// VATテクスチャ読み込み用のUVを作成
	float u = uv[1].x;
	float v = uv[1].y - (floor(frame) / numOfFrames);
	vec2 UV = vec2(u, v);
	
	// 初期フレームでの中心点を計算
	vec3 pivot = Cd.rgb;
	pivot *= (pivot_Max - pivot_Min);
	pivot += pivot_Min;
	
	// テクスチャからデータを取得
	vec3 pivot_Pos = texture(VAT_Pos, UV).xyz;
	vec4 pivot_Rot = texture(VAT_Rot, UV).xyzw;
	vec4 color = texture(VAT_Col, UV);
	
	// 現在のフレームの中心点の移動を反映した、頂点の位置を計算
	vec3 newP = P - pivot;
	newP = rotateVectorByQuatenion(newP, pivot_Rot);
	newP -= pivot;
	newP += pivot_Pos;
	newP += P;
	
	// 法線を回転させる
	vec3 newN = rotateVectorByQuatenion(N, pivot_Rot) + N;
	
	// Positionを設定
	vec4 worldSpacePos = TDDeform(newP);
	
	vec3 uvUnwrapCoord = TDInstanceTexCoord(TDUVUnwrapCoord());
	gl_Position = TDWorldToProj(worldSpacePos, uvUnwrapCoord);

#ifndef TD_PICKING_ACTIVE

	int cameraIndex = TDCameraIndex();
	oVert.cameraIndex = cameraIndex;
	oVert.worldSpacePos.xyz = worldSpacePos.xyz;
	
	// 色を設定
	oVert.color = TDInstanceColor(color);
	
	// 法線を設定
	vec3 worldSpaceNorm = normalize(TDDeformNorm(newN));
	
	oVert.worldSpaceNorm.xyz = worldSpaceNorm;

#else // TD_PICKING_ACTIVE

	TDWritePickingValues();

#endif // TD_PICKING_ACTIVE
}


実行結果

rigid.gif

Fluid (Changing Topology)

Houdiniでアニメーション作成

vat_fluid_houdini.jpg

流体シミュレーションをFLIPで作成しました。

Houdiniから書き出し

vat_fluid_houdini_2.jpg

パラメーター設定

  1. User interface - Normalを設定
  2. Start/Endにアニメーションの開始フレーム、終了フレームを設定
  3. MethodFluid (Changing Topology)に設定
  4. SOP Pathで書き出したいSOPを選択
  5. Frame Rangeにアニメーションのフレーム数を設定
  6. Normalize data range to 0-1 spaceをオフにする
  7. Packed normal into Position Alphaのチェックボックスをオフにする
  8. 必要であれば、Target Texture Sizeを任意のサイズに変更
  9. Target Prim Countにプリミティブの最大数を設定
  10. Paths/Normalのチェックボックスをオンにする
  11. SOPが色情報を持っている場合、Paths/Colorのチェックボックスをオンにする
  12. Settings/Position CoordXYZ, +X +Y +Zに変更する
  13. Renderを押して書き出し

書き出されたファイル群の解説

以下のファイルが出力されます

ファイル名 解説
[Project]/meshes/[Component]_mesh.fbx VATテクスチャ参照用のUVが追加されたFBX
[Project]/textures/[Component]_pos.exr 頂点の位置を格納したテクスチャ
[Project]/textures/[Component]_norm.exr 法線を格納したテクスチャ
[Project]/textures/[Component]_col.exr 色情報のテクスチャ
[Project]/materials/[Component]_data.json アニメーション再生時に使用する、各種パラメーターのJson

書き出されたFBXには、以下の頂点アトリビュートが追加されています

SOPアトリビュート名 GLSLアトリビュート名 解説
uv(0), uv(1) UV[0].xy VATテクスチャ座標

TouchDesignerでアニメーション再生機能の実装

vat_fluid_TD.jpg

サンプルプロジェクト内のVAT_Fluidを参照してください。
Softの時と大体同じですが、VATテクスチャの参照に使うUVが、uv[1]ではなくuv[0]になっています。
(なお、サンプルではHoudiniから色情報を書き出してはおらず、Vertex Shader内で単色を設定しています)

// Phong_VAT_Fluid

uniform vec4 uDiffuseColor;
uniform vec4 uAmbientColor;
uniform vec3 uSpecularColor;
uniform float uShininess;
uniform float uShadowStrength;
uniform vec3 uShadowColor;

// 頂点位置の変化量テクスチャ
uniform sampler2D VAT_Pos;
// 法線のテクスチャ
uniform sampler2D VAT_Norm;

// アニメーションの時間(0-1)
uniform float time;
// アニメーションの総フレーム数
uniform int numOfFrames;

out Vertex
{
	vec4 color;
	vec3 worldSpacePos;
	vec3 worldSpaceNorm;
	flat int cameraIndex;
} oVert;

void main()
{
	// 現在のフレームを計算
	float frame = clamp(time, 0.0, 0.99999) * numOfFrames;
	
	// VATテクスチャ読み込み用のUVを作成
	float u = uv[0].x;
	float v = uv[0].y - (floor(frame) / numOfFrames);
	vec2 UV = vec2(u, v);
	
	// 頂点の位置を読み込み
	vec3 newPos = texture(VAT_Pos, UV).xyz;
	
	// 法線を読み込み
	vec3 newNorm = texture(VAT_Norm, UV).xyz;
	
	// Positionを設定
	vec4 worldSpacePos = TDDeform(newPos);
	vec3 uvUnwrapCoord = TDInstanceTexCoord(TDUVUnwrapCoord());
	gl_Position = TDWorldToProj(worldSpacePos, uvUnwrapCoord);

#ifndef TD_PICKING_ACTIVE

	int cameraIndex = TDCameraIndex();
	oVert.cameraIndex = cameraIndex;
	oVert.worldSpacePos.xyz = worldSpacePos.xyz;
	
	oVert.color = TDInstanceColor(vec4(0.5, 0.75, 1.0, 1.0));
	
	// 法線を設定
	vec3 worldSpaceNorm = normalize(TDDeformNorm(newNorm));
	
	oVert.worldSpaceNorm.xyz = worldSpaceNorm;

#else // TD_PICKING_ACTIVE

	TDWritePickingValues();

#endif // TD_PICKING_ACTIVE
}

実行結果

fluid.gif

おわりに

後日、応用編を書く予定です。

  • 法線マップを使用するための方法(Tangentアトリビュートを作成する方法)
  • 破砕シミュレーション以外のRigidの使い方
  • テクスチャのサイズを減らす方法(法線情報をPositionのアルファに書き込み、TD側で読み出す方法)
  • Fluidのアニメーションをきれいにする方法

などのトピックを考えています。

18
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
3