TouchDesignerでHoudini VAT3.0を使用する 3 (Fluid)

2023-02-01

2023-02-01

TouchDesigner上で、HoudiniのLabs Vertex Animation Textures 3.0ノードから書き出したファイル群を使用し、Fluidアニメーションを実行する方法を解説します。

サンプルプロジェクト

https://github.com/yasuhirohoshino/TouchDesigner_VAT3.0/tree/main/VAT_3_Fluid

動作環境

  • Windows 10 22H2
  • Houdini 19.5.493
    • SideFX Labs 19.5.493インストール済み
  • TouchDesigner 2022.31030 (Commercial License)

Houdini側の設定

  1. OBJ Network内に、書き出したいGeometryを用意します。(各フレームで頂点数が違っていても問題ありません) houdini_1
  2. ROP Network内に、Labs Vertex Animation Texturesノードを作成します。 houdini_2

Labs Vertex Animation Texturesの設定

基本設定

  1. Mode/Target EngineDynamic Remeshing(Fluid),Customに変更します。
  2. Start/Endで書き出したいアニメーションの開始フレームと終了フレームを設定します。
    1. ノード作成時には、Expressionによりタイムラインの開始フレームと終了フレームが自動で設定されています。
  3. Input Geometryに書き出したいジオメトリのパスを設定します。 houdini_3

Settings

  1. Lookup Table FormatNon-HDR(Any Format asRGBA8 in Engine).pngになっていることを確認します。
  2. Texture FormatHDR(EXR/TIFF as RGBA 16/32 in Engine).exrになっていることを確認します。
  3. 必要であればTarget Texture Widthを適宜変更します。 houdini_4

Export

  1. 必要であればExport Pathで書き出し先のフォルダ名を設定します。
  2. Includeに、書き出したいデータがすべて含まれているか確認します。(もしColorデータが必要なければ、Geometry, Position(s), Rotationに変更してColor以外を書き出すことなどもできます。) houdini_5

Target Engine

  1. Coordinate SystemY-X-Z Clockwise (Right-Handed Y-Up)に変更します。
  2. 1 Metre in Engine Units1に設定します。 houdini_6

書き出し

  1. Settingsに戻り、Render PassFirst Pass(Geometry, Lookup Table, Data/Material)に設定し、Render Allを押します。 houdini_7
  2. 書き出しが完了したら、Render PassSecond Pass(Animation Textures)に設定し、再度Render Allを押します。 houdini_8

書き出されたファイル群

ファイル名 説明
geo/[AssetName]_mesh.fbx VATテクスチャ参照用のUVが追加されたFBX
tex/[AssetName]_lookup.exr fbxのUVを、以下のテクスチャ群からデータを取り出すためのUVに変換するテクスチャ
tex/[AssetName]_pos.exr 頂点位置を格納したテクスチャ
tex/[AssetName]_rot.exr 各フレームでの法線の回転情報を格納したテクスチャ
tex/[AssetName]_col.exr 各フレームでの色情報のテクスチャ

TouchDesigner

サンプルファイルを参照してください。 td_1

注意点

  • 手動で総フレーム数を指定する必要があります。 td_2
  • MAT OPで読み込むVATの各テクスチャは、Extend U, Extend VHoldにしてください。 td_3
  • 書き出されたテクスチャを読み込む際の、Movie File InTOPのPre-Multiply RGB by AlphaOffにしてください。 td_4

Vertex Shader

以下、サンプルプロジェクトで使用しているVertex Shaderを記載します。

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

// FBXのUVから各フレームでのVAT参照用UVに変換するためのルックアップテーブル
uniform sampler2D VAT_Table;
// 頂点位置のテクスチャ
uniform sampler2D VAT_Pos;
// 法線の回転用テクスチャ
uniform sampler2D VAT_Rot;
// 色のテクスチャ
uniform sampler2D VAT_Col;
// アニメーションのフレーム
uniform float currentFrame;
// アニメーションの総フレーム数
uniform int numOfFrames;

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

// Positionを取得
vec3 getVATPosition(vec2 uv) {
	vec3 currentPos = texture(VAT_Pos, uv).xyz;
    return currentPos;
}

// Colorを取得
vec4 getVATColor(vec2 uv) {
	vec4 currentCol = texture(VAT_Col, uv);
    return currentCol;
}

// Normalを取得
vec3 getVATNormal(vec2 uv) {
	vec3 n = vec3(0.0, 1.0, 0.0);
    vec4 currentQuat = texture(VAT_Rot, uv).xyzw;
	vec3 currentNormal = rotateVectorByQuatenion(n, currentQuat);
    return currentNormal;
}

void main()
{
	vec3 position = vec3(0.0);
	vec4 color = vec4(0.0);
	vec3 normal = vec3(0.0, 1.0, 0.0);
	vec3 tempUV = uv[0];

	// 頂点がVAT参照用のUVを持っている場合
	if(tempUV.x != 0.0 && tempUV.y != 0.0) {
		// ピクセルをサンプリングする間隔を計算
		float stride = 1.0 / numOfFrames;
		
		// 現在のフレームを取得
		float frame = floor(currentFrame);
		// Lookup Tableからテクスチャ参照用のUVを作成
		vec4 tableData = texture(VAT_Table, vec2(tempUV.x, tempUV.y - (frame / numOfFrames)));
		vec2 currentUV = vec2((tableData.r + tableData.g / 255.0), 1.0 - (tableData.b + tableData.a / 255.0));
		
		// 頂点位置を取得
		position = getVATPosition(currentUV);
		// 法線を取得
		normal = getVATNormal(currentUV);
		// 色を取得
		color = getVATColor(currentUV);
	}
	
	// Positionを設定
	vec4 worldSpacePos = TDDeform(position);
	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(Cd * color);
	
	// 法線を設定
	vec3 worldSpaceNorm = normalize(TDDeformNorm(normal));
	
	oVert.worldSpaceNorm.xyz = worldSpaceNorm;

#else // TD_PICKING_ACTIVE

	TDWritePickingValues();

#endif // TD_PICKING_ACTIVE
}