The jonki

呼ばれて飛び出てじょじょじょじょーんき

【Unity】Particle Systemでvertexとtexcoordで回転アニメーション

前回の記事ではParticle Systemをuv座標(texcoord)を使って回転アニメーションを実現しました。今回は頂点(vertex)を使って回転を実現したいと思います。動画を見るとその違いが歴然ですが、最終的な見栄えは変わりません。左が前回のものでUV情報だけ回転、右側は頂点ごと回転しているものになります。


解説

texcoordは通常の使い方であれば0.0-1.0に正規化されているので使いやすいですが、Particle Systemの各パーティクルの中心座標を求めようとすると少し面倒です。座標としてはParticle SystemのGameObjectが存在するところが原点となり、vertexにはこの原点から見た座標が入っています。回転のアニメーションをするためには各パーティクルの中心座標を求め、そのオフセットを引いて回転行列をかけ、そして元に戻すといったことをする必要があります。また今回はサイズを固定にしています。というのもtexcoordを使って各パーティクルの中心座標からどれぐらいずれているのか計算する際に利用するため、あらかじめサイズを知っている必要が有るためです。つまりParticle SystemのInspectorで指定するSizeは固定にしておき、拡縮はShader内で行うのが良いと思います。メッシュの1辺の頂点数10×Inspectorで指定したパーティクルのサイズ=Shader内で利用するサイズのパラメタとして使っています。今回はUnityに元からあるPlaneメッシュ(1辺10頂点)でパーティクルシステムではサイズを1に固定しています。


ソースコード

中心座標を計算するところは上の図を参考にしてください。x, y, zの座標軸は環境によって異なるかもしれません。Sceneビューでローカル座標表示モードに切り替えて、どういった回転軸を設定するかアプリに合わせて決めてください。

Shader "Custom/VertexRot" {
	Properties {
		_MainTex ("Particle Texture", 2D) = "white" {}
	}
	
	SubShader {
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		
		ZWrite Off
		Blend SrcAlpha OneMinusSrcAlpha 
	
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
				
			#include "UnityCG.cginc"
			#define PI 3.14159265359
			
			sampler2D _MainTex;
		
			struct v2f {
				float4 pos : POSITION;
				fixed4 col : COLOR;
				float2 uv : TEXCOORD0;
			};
			
			v2f vert (appdata_base v)
			{
				float _RotationSpeed = 2.0;
				float rnd = 2.0 * PI * (1.0 + sin(_Time.x * 50.0)) * 0.5;
				float sinX = sin ( _RotationSpeed * _Time.z );
				float cosX = cos ( _RotationSpeed * _Time.z );
				float sinY = sin ( _RotationSpeed * _Time.z );
				float2x2 rotationMatrix = float2x2( cosX, -sinX, sinY, cosX);

				float size = 10.0;
				float centX = v.vertex.x + size * (v.texcoord.x - 0.5);
				float centZ = v.vertex.z + size * (v.texcoord.y - 0.5);
				float3 center = float3(centX, 0.0, centZ);
				v.vertex.xyz -= center;
				v.vertex.xz = mul(rotationMatrix, v.vertex.xz);
//				v.vertex.xy = mul(rotationMatrix, v.vertex.xy);
//				v.vertex.yz = mul(rotationMatrix, v.vertex.yz);
				v.vertex.xyz += center;

				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = float2(v.texcoord.x, v.texcoord.y);
				return o;
			}
			
			half4 frag (v2f i) : COLOR
			{
				half4 col = tex2D(_MainTex, i.uv);
				
				return col;
			}
			ENDCG
		}
	}
}

最後に

ただシンプルに回転させるだけであればカスタムシェーダーは使わず、Particle SystemのInspectorから指定できる回転を使ったほうが良いと思います。今回はもっと複雑な表現をするための前段階として、勉強の意味を込めて日記を書いています。sizeの説明部分は若干の不安が残りますが、一応この考えで挙動があっているので良しとします。(え)