イラスト、モデリング、Unity、VR関連

unityとかblenderとかvr関連の作業メモ

shader クリップ空間におけるBillboard

phiさんのfuwaパーティクルからビルボード以外の機能を除去したバッチングありでビルボードが可能なコードです。クリップ空間でビルボードをしている。

GitHub - phi16/VRC_storage: assets distribution

FuwaParticle 解説 - Imaginantia

 

//original-code
//https://github.com/phi16/VRC_storage#fuwaparticle
Shader "Arumogina-Phi16/BillboardOnClip"{
	Properties{
		_Size ("Particle Size", Float) = 1.0
	}
	SubShader{
		Tags { "RenderType"="Transparent" "Queue"="Transparent" }
		LOD 100
		Cull Off
		Blend SrcAlpha One
		ZWrite Off

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma geometry geom
			#pragma fragment frag

			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2g {
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct g2f
			{
				float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			float _Size;

			v2g vert (appdata v){
				v2g o;
				o.vertex = v.vertex;
				o.uv = v.uv.xy;
				return o;
			}

			[maxvertexcount(4)]
			void geom (triangle v2g vg[3], inout TriangleStream<g2f> stream) {
				g2f o;
				float size = 1.0;
				float3 p = 0, v = 0;
				//quadの中心点
				float3 quad_center = (vg[0].vertex.xyz + vg[1].vertex.xyz)/2;
				p = quad_center;
				float4 vp1 = UnityObjectToClipPos(float4(p, 1));
				//height/width
				float aspectRatio = - UNITY_MATRIX_P[0][0] / UNITY_MATRIX_P[1][1];
				float2 vd = float2(1,0);
				float2 vn = float2(0,1);

				float sz = _Size;
				vd *= sz, vn *= sz;
				vd.x *= aspectRatio, vn.x *= aspectRatio;

				/*
				基本的な原理:
				メッシュがクリップ空間に変換された場合の中心点を取得=>vp1
				その中心点から4方向に伸ばした頂点をappendすることでquadになる。
				この点はクリップ空間、つまり2dの画面上伸ばしてるのでBillboardと同様になる
				*/

				o.uv = float2(-1,-1);
				o.vertex = vp1+float4(vd+vn,0,0);
				stream.Append(o);

				o.uv = float2(-1,1);
				o.vertex = vp1+float4(vd-vn,0,0);
				stream.Append(o);

				o.uv = float2(1,-1);
				o.vertex = vp1+float4(-vd+vn,0,0);
				stream.Append(o);

				o.uv = float2(1,1);
				o.vertex = vp1+float4(-vd-vn,0,0);
				stream.Append(o);

				stream.RestartStrip();
			}

			fixed4 frag (g2f i) : SV_Target{
				return 1;
			}
			ENDCG
		}
	}
}