【UnityShader】ポリゴン分解シェーダー #76
前回の成果
シンプルなGeometry Shaderの中身を理解した。
今回やること
Geometry Shaderを使用して、ポリゴンを分解します。
事前準備
Scene上にSphereを配置します。
そして、今回制作するMaterialをアタッチしてください。
ソースコード
Shader "Unlit/MovePolygon" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) _ScaleFactor ("Scale Factor", float) = 0.5 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma geometry geom #pragma fragment frag #include "UnityCG.cginc" fixed4 _Color; float _ScaleFactor; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct g2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; appdata vert (appdata v) { return v; } [maxvertexcount(3)] void geom (triangle appdata input[3], inout TriangleStream<g2f> stream) { float3 vec1 = input[1].vertex - input[0].vertex; float3 vec2 = input[2].vertex - input[0].vertex; float3 normal = normalize(cross(vec1, vec2)); [unroll] for (int i = 0; i < 3; i++) { appdata v = input[i]; g2f o; v.vertex.xyz += normal * (_SinTime.w * 0.5 + 0.5) * _ScaleFactor; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; stream.Append(o); } stream.RestartStrip(); } fixed4 frag (g2f i) : SV_Target { fixed4 col = _Color; return col; } ENDCG } } FallBack "Unlit/Color" }
前回のシンプルなシェーダーから大きな変更は特にありません。
Shaderの解説
geom関数の中を解説します。
法線の取得
float3 vec1 = input[1].vertex - input[0].vertex; float3 vec2 = input[2].vertex - input[0].vertex; float3 normal = normalize(cross(vec1, vec2));
三角ポリゴンには3つの頂点が存在します。
1つの頂点から、他の2つの頂点を減算し2つのベクトルを出します。
そして、この2つのベクトルの外積を出します。
すると、それは三角ポリゴンの法線ベクトルとなります。
三角ポリゴンの法線ベクトルのイメージ
法線方向に移動させる
v.vertex.xyz += normal * (_SinTime.w * 0.5 + 0.5) * _ScaleFactor;
三角ポリゴンの法線が取得出来たので、その方向に移動させてみます。
_SinTimeは定義済のもので、時間の正弦となっています。
定義 | 意味 |
---|---|
_SinTime.x | t / 8 |
_SinTime.y | t / 4 |
_SinTime.z | t / 2 |
_SinTime.w | t |
正弦なので、-1.0 ~ 1.0の間を往復します。
それを0 ~ 1.0に修正するために、
_SinTime.w * 0.5 + 0.5
をしています。
結果
下記のgifのようにポリゴンが時間に応じて、分解されれば成功です。
inspector
カメラの距離に応じて分解
SinTimeを使用して分解できました。
次はカメラとの距離に応じてポリゴンを分解してみます。
事前準備
先ほどと全く同じです。
Scene上にSphereを配置します。
そして、今回制作するMaterialをアタッチしてください。
ソースコード
Shader "Unlit/CameraPolygon" { Properties { _FarColor ("Far Color", Color) = (1, 1, 1, 1) _NearColor ("Near Color", Color) = (0, 0, 0, 1) _ScaleFactor ("Scale Factor", float) = 0.5 _StartDistance ("Start Distance", float) = 3.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma geometry geom #pragma fragment frag #include "UnityCG.cginc" fixed4 _FarColor; fixed4 _NearColor; float _ScaleFactor; float _StartDistance; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct g2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; fixed4 color : COLOR; }; float rand(float2 seed) { return frac(sin(dot(seed.xy, float2(12.9898, 78.233))) * 43758.5453); } appdata vert (appdata v) { return v; } [maxvertexcount(3)] void geom (triangle appdata input[3], inout TriangleStream<g2f> stream) { float3 center = (input[0].vertex + input[1].vertex + input[2].vertex) / 3; float4 worldPos = mul(unity_ObjectToWorld, float4(center, 1.0)); float3 dist = length(_WorldSpaceCameraPos - worldPos); float3 vec1 = input[1].vertex - input[0].vertex; float3 vec2 = input[2].vertex - input[0].vertex; float3 normal = normalize(cross(vec1, vec2)); fixed destruction = clamp(_StartDistance - dist, 0.0, 1.0); fixed gradient = clamp(dist - _StartDistance, 0.0, 1.0); fixed random = rand(center.xy); fixed3 random3 = random.xxx; [unroll] for (int i = 0; i < 3; i++) { appdata v = input[i]; g2f o; v.vertex.xyz += normal * destruction * _ScaleFactor * random3; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; o.color = fixed4(lerp(_NearColor.rgb, _FarColor.rgb, gradient), 1); stream.Append(o); } stream.RestartStrip(); } fixed4 frag (g2f i) : SV_Target { fixed4 col = i.color; return col; } ENDCG } } FallBack "Unlit/Color" }
ベースは同じとなります。
Shaderの解説
主な処理はカメラとポリゴンの距離ですので、そこを解説します。
カメラとポリゴンの距離
float3 center = (input[0].vertex + input[1].vertex + input[2].vertex) / 3; float4 worldPos = mul(unity_ObjectToWorld, float4(center, 1.0)); float3 dist = length(_WorldSpaceCameraPos - worldPos);
まずは、三角ポリゴンの中心座標を取得しています。
次に中心座標をワールド座標系に変換しています。
unity_ObjectToWorldは現在のモデルの行列ですので、乗算してあげることでワールド座標系へと変換できます。
最後にカメラとの距離を出して、dist変数で保持しています。
結果
カメラとの距離に応じて、ポリゴンが分解されれば成功です。
inspector
ソースコードにコメントを付与
Shader "Unlit/CameraPolygon" { Properties { _FarColor ("Far Color", Color) = (1, 1, 1, 1) _NearColor ("Near Color", Color) = (0, 0, 0, 1) _ScaleFactor ("Scale Factor", float) = 0.5 _StartDistance ("Start Distance", float) = 3.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma geometry geom #pragma fragment frag #include "UnityCG.cginc" fixed4 _FarColor; fixed4 _NearColor; float _ScaleFactor; float _StartDistance; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct g2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; fixed4 color : COLOR; }; float rand(float2 seed) { return frac(sin(dot(seed.xy, float2(12.9898, 78.233))) * 43758.5453); } appdata vert (appdata v) { return v; } [maxvertexcount(3)] void geom (triangle appdata input[3], inout TriangleStream<g2f> stream) { // カメラとポリゴンとの距離 float3 center = (input[0].vertex + input[1].vertex + input[2].vertex) / 3; float4 worldPos = mul(unity_ObjectToWorld, float4(center, 1.0)); float3 dist = length(_WorldSpaceCameraPos - worldPos); // ポリゴンの法線ベクトル float3 vec1 = input[1].vertex - input[0].vertex; float3 vec2 = input[2].vertex - input[0].vertex; float3 normal = normalize(cross(vec1, vec2)); // カメラとの距離に応じてポリゴンを変化 fixed destruction = clamp(_StartDistance - dist, 0.0, 1.0); // カメラとの距離に応じて色を変化 fixed gradient = clamp(dist - _StartDistance, 0.0, 1.0); // ランダムな値 fixed random = rand(center.xy); fixed3 random3 = random.xxx; [unroll] for (int i = 0; i < 3; i++) { appdata v = input[i]; g2f o; // 法線方向へ移動 v.vertex.xyz += normal * destruction * _ScaleFactor * random3; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; // 色を変化 o.color = fixed4(lerp(_NearColor.rgb, _FarColor.rgb, gradient), 1); stream.Append(o); } stream.RestartStrip(); } fixed4 frag (g2f i) : SV_Target { fixed4 col = i.color; return col; } ENDCG } } FallBack "Unlit/Color" }
今回は以上となります。
ここまでご視聴ありがとうございました。
+α
モデルを分解させてみた。
ソースコード
Shader "Unlit/CameraTexturePolygon" { Properties { _MainTex ("Texture", 2D) = "white" {} _FarColor ("Far Color", Color) = (1, 1, 1, 1) _NearColor ("Near Color", Color) = (0, 0, 0, 1) _ScaleFactor ("Scale Factor", float) = 0.5 _StartDistance ("Start Distance", float) = 3.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma geometry geom #pragma fragment frag #include "UnityCG.cginc" fixed4 _FarColor; fixed4 _NearColor; float _ScaleFactor; float _StartDistance; sampler2D _MainTex; float4 _MainTex_ST; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct g2f { float4 vertex : POSITION; float2 uv : TEXCOORD0; fixed4 color : COLOR; }; float rand(float2 seed) { return frac(sin(dot(seed.xy, float2(12.9898, 78.233))) * 43758.5453); } appdata vert (appdata v) { return v; } [maxvertexcount(3)] void geom (triangle appdata input[3], inout TriangleStream<g2f> stream) { // カメラとポリゴンとの距離 float3 center = (input[0].vertex + input[1].vertex + input[2].vertex) / 3; float4 worldPos = mul(unity_ObjectToWorld, float4(center, 1.0)); float3 dist = length(_WorldSpaceCameraPos - worldPos); // ポリゴンの法線ベクトル float3 vec1 = input[1].vertex - input[0].vertex; float3 vec2 = input[2].vertex - input[0].vertex; float3 normal = normalize(cross(vec1, vec2)); // カメラとの距離に応じてポリゴンを変化 fixed destruction = clamp(_StartDistance - dist, 0.0, 1.0); // カメラとの距離に応じて色を変化 fixed gradient = clamp(dist - _StartDistance, 0.0, 1.0); // ランダムな値 fixed random = rand(center.xy); fixed3 random3 = random.xxx; [unroll] for (int i = 0; i < 3; i++) { appdata v = input[i]; g2f o; // 法線方向へ移動 v.vertex.xyz += normal * destruction * _ScaleFactor * random3; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); // 色を変化 o.color = fixed4(lerp(_NearColor.rgb, _FarColor.rgb, gradient), 1); stream.Append(o); } stream.RestartStrip(); } fixed4 frag (g2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } FallBack "Unlit/Color" }
_MainTexにしただけ。
結果
inspector