天天看點

Unity3D手遊項目的總結和思考(5) - 植被擺動3DMAX工具

       以前的部落格有提到如何實作植被擺動的效果:點選打開連結

核心問題就是,擺動的幅度是根據什麼樣的權重.我簡單分為三種.

1.UV坐标作為權重

2.頂點到模型原點的距離作為權重

3.頂點顔色作為權重

       以CE3引擎來講,整體擺動用第二種,細節抖動用第三種,兩種結合使用,就可以實作完美的擺動效果.但是用第二種,就不能用靜态合批了.因為靜态合批以後,模型的原點就變了,這個權重的計算也是錯誤的了.如果要用靜态合批還要完美的擺動,怎麼辦呢?

       我想到一個辦法,就是把第二種的權重,儲存到頂點顔色的一個通道裡面,這樣即使靜态合批了,這個權重值也不會改變的,那麼問題來了,如何儲存呢.打開3DMAX的頂點顔色繪制工具,你會發現根本就刷不出這種權重值,那麼隻能程式來生成了,是以我就用3DMAX的腳本語言寫了一個工具來自動生成這個整體擺動的權重.

工具界面:

Unity3D手遊項目的總結和思考(5) - 植被擺動3DMAX工具

我用藍色通道來儲存這個整體擺動權重值.

Unity3D手遊項目的總結和思考(5) - 植被擺動3DMAX工具

過渡曲線我嘗試了幾種:

Unity3D手遊項目的總結和思考(5) - 植被擺動3DMAX工具

權重過渡支援從上到下或者從下到上,這樣的好處是可以支援燈籠這種倒挂物件的擺動.

至于頂點擺動的代碼,可參考Unity官方地形的植被動畫的代碼,其實都是從CE3改進過來的,我的有改寫過:

inline float4 AnimateVertex2(float4 pos, half3 normal, fixed4 animParams, float4 wind)
			{	
				// animParams stored in vertext color
				// animParams.x = branch phase = unused
				// animParams.y = edge bending factor = green
				// animParams.z = branch bending factor = red 
				// animParams.w = main bending factor = blue

				float fDetailAmp = 0.1f;
				float fBranchAmp = 0.3f;
	
				// Phases (object, vertex, branch)
				float fObjPhase = dot(unity_ObjectToWorld[3].xyz, 1);
				float fBranchPhase = fObjPhase;// + animParams.x;
				float fVtxPhase = dot(pos.xyz, animParams.y + fBranchPhase);
	
				// x is used for edges; y is used for branches
				float2 vWavesIn = _EdgeFrequencyFactor * _Time.yy + pos.xz *.3 + float2(fVtxPhase, fBranchPhase );
				float4 vWaves = (frac( vWavesIn.xxyy * float4(1.975, 0.793, 0.375, 0.193) ) * 2.0 - 1.0);
				vWaves = SmoothTriangleWave( vWaves );
				float2 vWavesSum = vWaves.xz + vWaves.yw;

				// Edge (xz) and branch bending (y)
				// sign important to match normals of both faces!!! otherwise edge fluttering will be corrupted.
				float3 bend = animParams.y * fDetailAmp * normal.xyz * sign(normal.xyz) * _EdgeBendingFactor;
				bend.y = animParams.z * fBranchAmp * _BranchBendingFactor; 
				pos.xyz += vWavesSum.xyx * bend * wind.w;

				// main bending
				float3 mainBend = wind.xyz * wind.w * animParams.w * _MainBendingFactor;
				pos.xyz += mainBend * vWavesSum.y * _MainBendingFactor2; 
				pos.xyz += mainBend; 
	
				return pos;
			}
           

max腳本:

Utility LuoyinanVertexColorTool "LuoyinanVertexColorTool"
(
	global g_CurveType = "cubic"
	global g_FadeDirection = "up"
	
	Dropdownlist ddlist "Curve Type:" items:#("cubic","quadratic","linear")
	on ddlist selected i do
		g_CurveType = ddlist.items[i]
	
	Dropdownlist ddlist2 "Fade Direction:" items:#("up","down")
	on ddlist2 selected i do
		g_FadeDirection = ddlist2.items[i]
	
	button b "Start Paint"
	on b pressed do 
	( 		
		for selectNode in selection do      
		( 					
			Recursion selectNode     
		)  
	)
)

fn Recursion node=
(
    if (Editable_mesh == classOf node) then
    (		
        ModifyVertexColor node
    )
    else
    (
        for i = 1 to node.children.count do Recursion node.children[i]
    )
)

fn ModifyVertexColor node=
(
	addModifier node (vertexPaint())
	collapseStack node		
		
	theMesh = node.mesh
	numtverts = getNumVerts theMesh
	print (format "g_CurveType:% g_FadeDirection:%\n" g_CurveType g_FadeDirection)
    print (format "name:% numfaces:% numtverts:% numcpvverts:% getNumVerts:%\n" node.name theMesh.numfaces theMesh.numtverts theMesh.numcpvverts numtverts)
	
	minHeight = 100000
	maxHeight = -100000
	for v = 1 to numtverts do
	(
		vert = getVert theMesh v
		if (vert.z > maxHeight) then (maxHeight = vert.z) 
		if (vert.z < minHeight) then (minHeight = vert.z)
	)	
	
	for f = 1 to theMesh.numfaces  do
	(
		face = getFace theMesh f
		v1 = getVert theMesh face.x
		v2 = getVert theMesh face.y
		v3 = getVert theMesh face.z
		w1 = (v1.z - minHeight) / (maxHeight - minHeight)
		w2 = (v2.z - minHeight) / (maxHeight - minHeight)
		w3 = (v3.z - minHeight) / (maxHeight - minHeight)
		if (g_FadeDirection == "down")then
		(
			w1 = 1 - w1
			w2 = 1 - w2
			w3 = 1 - w3
		)		
		if (g_CurveType == "cubic") then 
		(
			w1 = 2 * w1 * w1 * w1 / (1 + w1)
			w2 = 2 * w2 * w2 * w2 / (1 + w2)
			w3 = 2 * w3 * w3 * w3 / (1 + w3)
		)
		else if (g_CurveType == "quadratic") then 
		(
			w1 = 2 * w1 * w1 / (1 + w1)
			w2 = 2 * w2 * w2 / (1 + w2)
			w3 = 2 * w3 * w3 / (1 + w3)
		)
		
		vc_face = getVCFace theMesh f
		vc1 = getVertColor theMesh vc_face.x
		vc2 = getVertColor theMesh vc_face.y
		vc3 = getVertColor theMesh vc_face.z
		vc1.b = w1 * 255
		vc2.b = w2 * 255
		vc3.b = w3 * 255
		setVertColor theMesh vc_face.x vc1
		setVertColor theMesh vc_face.y vc2
		setVertColor theMesh vc_face.z vc3
	)
	
	update theMesh
)
           

至于MAX腳本的如何使用,請自行百度...