[TouchDesigner] Sprinkle SOPの応用

2023-02-15

2023-02-15

TouchDesignerのSprinkle SOPを使い、ジオメトリのサーフェス上にポイントを生成する方法を解説します。

検証環境

  • Windows 10 22H2
  • TouchDesigner 2022.32120 (Commercial License)

サンプルプロジェクト

https://github.com/yasuhirohoshino/TouchDesignerExamples/tree/master/SOP/sprinkleSOP

ポイントにアニメーションを適用する

In 1にDeform前のジオメトリを、In 2にDeform後のジオメトリを入力することで、サーフェス上に撒いたポイントをアニメーションに追従させることができます。

td_1

なお、FBXアニメーションにSprinkle SOPを適用したい場合、Select SOPDeform SOPを使うことで、CPUでアニメーションを実行する必要があります。

td_2

アトリビュートを転送し、インスタンシングに使用する

Surface Attributesをオンにすると、入力ジオメトリのポイントアトリビュートを転送できます。

td_3

入力ジオメトリがNormalアトリビュートを持っていれば、アトリビュートを転送することで、インスタンシングでオブジェクトの向きを指定するために使えますが、アップベクトルが無いとGeometry COMPに警告が発生し、意図した方向にオブジェクトが向かない恐れがあります。

td_5

対策としては、入力前のジオメトリに、Attribute Create SOPでNormalとTangentを付与し、Script SOPで外積を計算しアップベクトルを作成する方法があります。

td_4

Script SOP

def onPulse(par):
	return

def onCook(scriptOp):
	scriptOp.clear()
	
	# 入力ジオメトリをコピー
	a = scriptOp.inputs[0]
	scriptOp.copy(a)
	
	# アップベクトルのアトリビュートを作成し初期化
	scriptOp.pointAttribs.create('upVector', (0.0, 1.0, 0.0))
	
	# 頂点からTangentを集めるための空の配列
	tList = [[] for i in range(scriptOp.numPoints)]
	
	for prim in scriptOp.prims:
		for vert in prim:
			# TangentをPointごとに集める
			id = vert.point.index
			tList[id].append(tdu.Vector(vert.T[0], vert.T[1], vert.T[2]))
			
	for i, t in enumerate(tList):
		# ポイントごとのTangentの平均を計算
		meanT = sum(t) / len(t)
		meanT.normalize()
		# Normalを取得
		n = tdu.Vector(scriptOp.points[i].N[0], scriptOp.points[i].N[1], scriptOp.points[i].N[2])
		# NormalとTangentの外積を計算し、アップベクトルとする
		u = n.cross(meanT)
		u.normalize()
		# アップベクトルを付与
		scriptOp.points[i].upVector[0] = u[0]
		scriptOp.points[i].upVector[1] = u[1]
		scriptOp.points[i].upVector[2] = u[2]
		
	return