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

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

shader テッセレーションサンプルコード

元ネタ様

コードはこちらのコードにuvとジオメトリシェーダを付与し、こちらの解説をコメントとして付与したものです

テッセレーション基礎 - しゅみぷろ

 

Shader "Unlit/SimpleTessellation"
{
    Properties{
        _TessFactor("Tess Factor",Vector) = (2,2,2,2)
				_MainTex("MainTex",2D) = "white"{}
    }

    SubShader{
      Pass{
				Cull Off
        CGPROGRAM

   			#pragma vertex VS
				#pragma geometry geom
   			#pragma fragment FS
   			#pragma hull HS
   			#pragma domain DS
   			#define INPUT_PATCH_SIZE 3
   			#define OUTPUT_PATCH_SIZE 3

        uniform vector _TessFactor;
				sampler2D _MainTex;

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

        struct v2h {
            float4 pos:POS;
						float2 uv:TEXCOORD0;
        };
        struct h2d_main {
            float3 pos:POS;
						float2 uv:TEXCOORD0;
        };
        struct h2d_const {
            float tess_factor[3] : SV_TessFactor;
            float InsideTessFactor : SV_InsideTessFactor;//ドメインに指定する形状によってはエラーになる
        };
        struct d2g {
            float4 lpos:SV_Position;
						float2 uv:TEXCOORD0;
			  };
				struct g2f {
					float4 pos:SV_POSITION;
					float2 uv:TEXCOORD0;
				};

        struct f_input {
            float4 vertex:SV_Position;
            float4 color:COLOR0;
        };

        v2h VS(appdata i) {
            v2h o = (v2h)0;
            o.pos = i.vertex;
            o.uv = i.uv;
            return o;
        }
		/*
		テッセレーションの流れ
		頂点シェーダ=>

		ハルシェーダ・ステージ=>
		メインハルシェーダ、パッチ定数関数の2つが並列で実行される
		メインハルシェーダ-コントロールポイントごとに1回コール
			-頂点の分割度合いを操作
			パッチ定数関数-パッチごとに1回コールする制御点をセット

			テッセレーションステージ=>
			自動実行,実際に頂点が分割される

		ドメインシェーダステージ=>

				*用語説明
				パッチーポリゴン分割処理を行う際に使用するコントロールポイントの集合
				コントロールポイント・制御点ー頂点分割で使う制御点
				ドメインー分割に利用するプリミティブ形状
				テッセレーション係数ーパッチごとに指定する頂点の分割係数
				*/

				//パッチ定数関数-頂点の分割度合いを操作
				//パッチごとに、どの程度頂点を分割するかを決める係数を構造体に入れる
        //この構造体データは次のTessellatorに渡される。
				//h2d_constはテッセレーションステージを介して、ドメインシェーダに渡される
				h2d_const HSConst(InputPatch<v2h, INPUT_PATCH_SIZE> i) {
            h2d_const o = (h2d_const)0;
            o.tess_factor[0] = _TessFactor.x;
            o.tess_factor[1] = _TessFactor.y;
            o.tess_factor[2] = _TessFactor.z;
            o.InsideTessFactor = _TessFactor.w;
            return o;
        }

				/*
				メインハルシェーダ-制御点を入力
				h2d_mainはドメインシェーダに渡される
				//INPUT_PATCH_SIZE=3:一つのパッチが持つ制御点の数
				*/
        [domain("tri")]//(tri/quad/isoline)から選択
        [partitioning("integer")]//分割方法。(integer/fractional_eve,fractional_odd/pow2)から選択。
        [outputtopology("triangle_cw")]//出力された頂点が形成するトポロジー。(point/line/triangle_cw/triangle_ccw)から選択。
        [outputcontrolpoints(OUTPUT_PATCH_SIZE)]//出力するパッチのサイズ(配列のサイズ的な意味の)
        [patchconstantfunc("HSConst")]//パッチ定数関数の関数名
        h2d_main HS(InputPatch<v2h, INPUT_PATCH_SIZE> i, uint id:SV_OutputControlPointID) {
            h2d_main o = (h2d_main)0;
            o.pos = i[id].pos;//頂点シェーダから渡された値をそのまま入力している
						o.uv = i[id].uv;
            return o;
		}
				/*
				Tessellation Stageの出力をもとに、分割後の頂点を処理。
				Geometry-Shaderを呼び出さない場合はここでWVP変換をする必要がある。

				h2d_const hs_const_data
					パッチ固定関数の出力(頂点の分割度合い)を参照
				const OutputPatch<h2d_main, OUTPUT_PATCH_SIZE>
					ハルシェーダの出力(制御点)
				float3 bary:SV_DomainLocation
					分割後の頂点の位置を求めるためのパラメーター
					(分割後の頂点がそのまま出力されるわけではないので、計算する必要がある)

				ドメインにtri(三角形)を指定している場合、SV_DomainLocationは三角形の重心座標を意味する
				パラメータとなる。
				ドメインが異なると、SV_DomainLocationが意味する値と型が変わる
				*/

        [domain("tri")]
        d2g DS(h2d_const hs_const_data, const OutputPatch<h2d_main, OUTPUT_PATCH_SIZE> i, float3 bary:SV_DomainLocation) {
            d2g o = (d2g)0;
            float3 pos = i[0].pos * bary.x + i[1].pos * bary.y + i[2].pos * bary.z;
            //o.pos = UnityObjectToClipPos(float4(pos, 1));
						o.lpos = float4(pos,1);
						o.uv = i[0].uv * bary.x + i[1].uv * bary.y + i[2].uv * bary.z;
            return o;
		}

		[maxvertexcount(3)]
		void geom(triangle d2g vg[3], inout LineStream<g2f> outStream){
    		[unroll]
    		for (int i = 0; i < 3; i++){
        		d2g v = vg[i];
        		g2f o = (g2f)0;
        		o.pos = UnityObjectToClipPos(v.lpos);
						o.uv = v.uv;
        		outStream.Append(o);
    		}
    		outStream.RestartStrip();
		}

        float4 FS(f_input i) : SV_Target {
            return float4(1, 0, 0, 1);
		}
      	ENDCG
    }
  }
}

Shader "Sample/Tesslation"{
    Properties{
			_Tess("Tess",Range(1,64)) = 10
			_MainTex("MainTex",2D) = "white"{}
    }
    SubShader{
      Pass{
				Cull Off
        CGPROGRAM

   			#pragma vertex vert
				#pragma geometry geom
   			#pragma fragment frag
   			#pragma hull HS
   			#pragma domain DS
				#pragma target 5.0
   			#define INPUT_PATCH_SIZE 3
   			#define OUTPUT_PATCH_SIZE 3

				int _Tess;
				sampler2D _MainTex;

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

        struct v2h {
            float4 pos:POS;
						float2 uv:TEXCOORD0;
        };
        struct h2d_main {
            float3 pos:POS;
						float2 uv:TEXCOORD0;
        };
        struct h2d_const {
            float tess_factor[3] : SV_TessFactor;
            float InsideTessFactor : SV_InsideTessFactor;
        };
        struct d2g {
            float4 lpos:SV_Position;
						float2 uv:TEXCOORD0;
			  };
				struct g2f {
					float4 pos:SV_POSITION;
					float2 uv:TEXCOORD0;
				};

        v2h vert(appdata i) {
            v2h o = (v2h)0;
            o.pos = i.vertex;
            o.uv = i.uv;
            return o;
        }
				h2d_const HSConst(InputPatch<v2h, INPUT_PATCH_SIZE> i) {
      	h2d_const o = (h2d_const)0;
      	o.tess_factor[0] = 1;
      	o.tess_factor[1] = 1;
      	o.tess_factor[2] = 1;
      	o.InsideTessFactor = _Tess;
      	return o;
    	}

    	[domain("tri")]
    	[partitioning("integer")]
    	[outputtopology("triangle_cw")]
    	[outputcontrolpoints(OUTPUT_PATCH_SIZE)]
    	[patchconstantfunc("HSConst")]
    	h2d_main HS(InputPatch<v2h, INPUT_PATCH_SIZE> i, uint id:SV_OutputControlPointID) {
      	h2d_main o = (h2d_main)0;
      	o.pos = i[id].pos;
				o.uv = i[id].uv;
      	return o;
			}

    	[domain("tri")]
    	d2g DS(h2d_const hs_const_data, const OutputPatch<h2d_main, OUTPUT_PATCH_SIZE> i, float3 bary:SV_DomainLocation) {
      	d2g o = (d2g)0;
      	float3 pos = i[0].pos * bary.x + i[1].pos * bary.y + i[2].pos * bary.z;
				o.lpos = float4(pos,1);
				o.uv = i[0].uv * bary.x + i[1].uv * bary.y + i[2].uv * bary.z;
      	return o;
			}

			[maxvertexcount(3)]
			void geom(triangle d2g vg[3], inout LineStream outStream){
    			[unroll]
    			for (int i = 0; i < 3; i++){
        			d2g v = vg[i];
        			g2f o = (g2f)0;
        			o.pos = UnityObjectToClipPos(v.lpos);
							o.uv = v.uv;
        			outStream.Append(o);
    			}
    			outStream.RestartStrip();
				}

      float4 frag(g2f i) : SV_Target {
        return float4(1, 0, 0, 1);
			}
      ENDCG
    }
  }
}    

shader ノイズ

 

Shader "Custom/sonic1" {
	Properties{
		_MainTex("MainTex",2D) = "white"{}
		_Frec("Frec",Range(0,1000)) = 100
		_SPD("SPD",Float)  = 0
		_Seed("Seed",Float) = 0
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 lpos:POSITION1;
				float4 uv:TEXCOORD0;
			};

			float _Frec;
			float _SPD;
			float _Seed;

			float rand(float2 co){
				return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453);
			}

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			sampler2D _MainTex;
			float4 frag(v2f i) :SV_Target {
				float ux = i.uv.x*_Frec;
				float fux = frac(ux);
				float id = trunc(ux);
				float t = trunc(_Time.y*_SPD);
				id += t;
				float yaid = trunc(id*1000)/1000;
				float ybid = trunc((id+1)*100000)/100000;
				float ya = rand(float2(yaid/1000,_Seed));
				float yb = rand(float2(ybid/1000,_Seed));
				if(i.uv.y <= lerp(ya,yb,fux)){
					return float4(0,0,0,1);
				}
				return float4(1,1,1,1);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

shader surf base

zwriteが別パスになってるのはsurfがコンパイル時にZWrite Offで上書きしてしまうため

Shader "Custom/SurfBase" {
	Properties {
		[Enum(UnityEngine.Rendering.CullMode)]
		_Cull("Cull", Float) = 2                // Off
		[Enum(UnityEngine.Rendering.CompareFunction)]
		_ZTest("ZTest", Float) = 4              // LEqual
		[Enum(Off, 0, On, 1)]
		_ZWrite("ZWrite", Float) = 1
		_MainTex ("Texture", 2D) = "white" {}
		[HDR] _Color("Color",Color) = (1,1,1,1)
		_NormalTex ("Normal Tex", 2D) = "bump" {}
		_NormalPow ("Normal Pow", Range(0, 1)) = 1
		[HDR] _Emission("Emission",Color) = (0,0,0,0)
		_Smoothness ("Smoothness", Range(0,1)) = 0.5
		_Metallic ("Metallic", Range(0,1)) = 0.0
		_Occlusion ("Occlusion",Range(0,1)) = 1

    //ステンシル
    _StencilRef("StencilRef",Float) = 0
    [Enum(UnityEngine.Rendering.StencilOp)]
    _StencilPass("StencilPass",Float) = 0
    //https://docs.unity3d.com/ScriptReference/Rendering.CompareFunction.html
    [Enum(UnityEngine.Rendering.CompareFunction)]
    _StencilComp("StencilComp",Float) = 0
	}
	SubShader {
    Pass{
      ColorMask 0
      ZWrite [_ZWrite]
    }

		Tags { "Queue" = "Transparent" }
		Cull [_Cull]
		ZTest [_ZTest]
    Stencil{
			Ref [_StencilRef]
			Comp [_StencilComp]
			Pass [_StencilPass]
		}

		//surfにおいては機能しないっっぽいのでコメントアウト
		CGPROGRAM

		#pragma surface surf Standard fullforwardshadows alpha:fade vertex:vert

		#pragma target 3.0
		struct Input {
				float2 uv_MainTex;
				float dammy_val;
				/*
				float3 viewDir;
				float4 screenPos;
				float3 worldPos;
				float3 worldNormal;
				*/
		};

		sampler2D _MainTex;
		float4 _Color;
		sampler2D _NormalTex;
		float _NormalPow;
		float4 _Emission;
		float _Smoothness;
		float _Metallic;
		float _Occlusion;

		void vert (inout appdata_full v,out Input o) {
			//初期化
			UNITY_INITIALIZE_OUTPUT(Input, o);
			o.dammy_val = 1;
		}

		void surf (Input IN, inout SurfaceOutputStandard o) {
			float4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			o.Emission = _Emission;
			o.Smoothness = _Smoothness;
			o.Metallic = _Metallic;
			o.Occlusion = _Occlusion;
			o.Alpha = c.a;
			o.Normal = UnpackScaleNormal(tex2D(_NormalTex, IN.uv_MainTex), _NormalPow);
		}
		ENDCG
	}
	Fallback "Diffuse"
}
    

shader モーフィングサンプル

 

 

Shader "Custom/Base" {
	Properties{
		_MainTex("MainTex",2D) = "white"{}
		_A("A",Float) = 0.5
		_B("B",Float) = 0.5
	}
	SubShader{
		Tags{"RenderType"="Opaque" "Queue" = "Geometry"}
		//透明部分のあるテクスチャを使う場合
		//Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		//Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			float _A;
			float _B;

			float2 square(float2 p){
				return float2(abs(p.x) + abs(p.y),_A);
			}

			float2 circle(float2 p){
				return float2(length(p),_B);
			}

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			sampler2D _MainTex;
			float4 frag(v2f i) :SV_Target {
				float2 p = 2*i.uv-1;
				float a = sin(_Time.y * 5.0) * 0.5 + 0.5;
				float2 d = lerp(circle(p),square(p),a);
				float c = lerp(1,0,step(d.x,d.y));
				return float4(c,c,c,1);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

shader volonoi

 

f:id:arumogina:20190827010604p:plain

Shader "Custom/Volonoi" {
	Properties{
		_Split("Split",Int) = 5
		_P("P",Float) = 0
		_RDM("RDM",Float) = 4
		_SPD("SPD",Float) = 1
		_Color("Color",Color) = (0,0,0,1)
		_Color2("Color2",Color) = (0,0,0,1)
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			int _Split;
			float _P;
			float _RDM;
			float _SPD;
			float4 _Color;
			float4 _Color2;

			float rand(float2 co){
				return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453);
			}

			float2 rand2(float2 st){
					 st = float2(dot(st, float2(127.1, 311.7)),
											 dot(st, float2(269.5, 183.3)));
					 return frac(sin(st) * 43758.5453123);
			 }

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			float dist = 100;
			float4 frag(v2f i) :SV_Target {
				float2 auv = i.uv*_Split;
				float2 uv = frac(auv);
				float2 id = floor(auv);
				float min_dist = 100;
				float2 min_p = float2(0,0);
				//各マスのランダムな位置に頂点を配置
				//周囲8マスと現在のマスに配置されたランダムな頂点を探索し
				//処理対象のピクセルと最も近い点を探す
				for(int k=-1;k<=1;k++){
					for(int m=-1;m<=1;m++){
						float2 km = float2(k,m);
						float2 rand_p = rand2(id+km);
						//各マスの中心位置(0.5,0.5)から各成分+0.5までの移動を許している
						rand_p = float2(0.5,0.5)+0.5*sin(_Time.y*_SPD+_RDM*rand_p);
						float dist = length(rand_p+km-uv);
						if(dist<min_dist){
							min_dist = dist;
							min_p = rand_p;
						}

					}
				}

				float4 col = _Color + min_dist*2;
				col.rg = min_p;
				//col -= abs(sin(80*min_dist))*0.07; //縞模様
				//col += 1-step(0.02,min_dist); //中央の点
				return float4(col.rgb,1);

				//return float4(dist,dist,0,1);
				//return clamp(_Color,_Color2,dist);
				//return lerp(_Color,_Color2,dist);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}
Shader "Custom/Base" {
	Properties{
		_Split("Split",Int) = 5
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			int _Split;

			float rand(float2 co){
				return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453);
			}

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			float4 frag(v2f i) :SV_Target {
				float2 auv = i.uv*_Split;
				float2 uv = frac(auv);
				float2 id = floor(auv);
				float2 rp = float2(rand(id.xy+1),rand(float2(id.x,id.y)));
				float len = length(rp-uv);
				return float4(len,0,0,1);


			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

Shader "Custom/Base" {
	Properties{
		_Split("Split",Int) = 5
		_P("P",Float) = 0
		_RDM("RDM",Float) = 4
		_SPD("SPD",Float) = 1
		_Color("Color",Color) = (0,0,0,1)
		_Color2("Color2",Color) = (0,0,0,1)
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			int _Split;
			float _P;
			float _RDM;
			float _SPD;
			float4 _Color;
			float4 _Color2;

			float rand(float2 co){
				return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453);
			}

			float2 rand2(float2 st){
					 st = float2(dot(st, float2(127.1, 311.7)),
											 dot(st, float2(269.5, 183.3)));
					 return frac(sin(st) * 43758.5453123);
			 }

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			float dist = 100;
			float4 frag(v2f i) :SV_Target {
				float2 auv = i.uv*_Split;
				float2 uv = frac(auv);
				float2 id = floor(auv);
				float min_dist = 100;
				float2 min_p = float2(0,0);
				//各マスのランダムな位置に頂点を配置
				//周囲8マスと現在のマスに配置されたランダムな頂点を探索し
				//処理対象のピクセルと最も近い点を探す
				for(int k=-1;k<=1;k++){
					for(int m=-1;m<=1;m++){
						float2 km = float2(k,m);
						float2 rand_p = rand2(id+km);
						//各マスの中心位置(0.5,0.5)から各成分+0.5までの移動を許している
						rand_p = float2(0.5,0.5)+0.5*sin(_Time.y*_SPD+_RDM*rand_p);
						float dist = length(rand_p+km-uv);
						if(dist<min_dist){
							min_dist = dist;
							min_p = rand_p;
						}

					}
				}

        fixed4 col = min_dist;
				//グレースケール
				//col = dot(min_p, float2(0.3, 0.6));
				//カラー
				col = min_dist * 0.1;
				col.rg += min_p;
				//col -= abs(sin(10*min_dist+_Time.y*_SPD))*0.7;
				col -= step(0.2,abs(sin(10*min_dist+_Time.y*_SPD))*0.7);
				//col += 1-step(0.5,min_dist);
				col.a = 1;
        return col;
				/*
				float4 col = _Color + min_dist*2;
				col.rg = min_p;
				col -= abs(sin(80*min_dist))*0.07;
				col += 1-step(0.02,min_dist);
				return float4(col.rgb,1);
				*/
				//return float4(dist,dist,0,1);
				//return clamp(_Color,_Color2,dist);
				//return lerp(_Color,_Color2,dist);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

Shader "Custom/Volonoi" {
	Properties{
		_Split("Split",Int) = 5
		_P("P",Float) = 0
		_RDM("RDM",Float) = 4
		_SPD("SPD",Float) = 1
		_Color("Color",Color) = (0,0,0,1)
		_Color2("Color2",Color) = (0,0,0,1)
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			int _Split;
			float _P;
			float _RDM;
			float _SPD;
			float4 _Color;
			float4 _Color2;

			float rand(float2 co){
				return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453);
			}

			float2 rand2(float2 st){
					 st = float2(dot(st, float2(127.1, 311.7)),
											 dot(st, float2(269.5, 183.3)));
					 return frac(sin(st) * 43758.5453123);
			 }

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			float dist = 100;
			float4 frag(v2f i) :SV_Target {
				float2 auv = i.uv*_Split;
				float2 uv = frac(auv);
				float2 id = floor(auv);
				float m_dist[5] = {9,9,9,9,9};//距離が小さい順に先頭から入れる
				float2 m_p[5];//同じインデックスに対応する座標を入れる
				//各マスのランダムな位置に頂点を配置
				//周囲8マスと現在のマスに配置されたランダムな頂点を探索し
				//処理対象のピクセルと最も近い点を探す
				for(int k=-1;k<=1;k++){
					for(int m=-1;m<=1;m++){
						float2 km = float2(k,m);
						float2 rand_p = rand2(id+km);
						//各マスの中心位置(0.5,0.5)から各成分+0.5までの移動を許している
						rand_p = float2(0.5,0.5)+0.5*sin(_Time.y*_SPD+_RDM*rand_p);
						float dist = length(rand_p+km-uv);
						for(int n=0;n<5;n++){
							if(dist<m_dist[n]){
								[unroll]
								for(int o=4;o>n;o--){
									m_dist[o] = m_dist[o-1];
									m_p[o] = m_p[o-1];
								}
								m_dist[n] = dist;
								m_p[n] = rand_p;
								break;
							}
						}
					}
				}
				//float md = m_dist[0]*m_dist[1]*m_dist[2]*m_dist[3]*m_dist[4];
				//float2 mp = m_p[0]*m_p[1]*m_p[2]*m_p[3]*m_p[4];
				float md = m_dist[4]-m_dist[3]+m_dist[2]-m_dist[1]+m_dist[0];
				float2 mp = m_p[0]/m_p[1]*m_p[2]/m_p[1]*m_p[0];
				float4 col = _Color + md*2;
				col.rg = mp;
				//col -= abs(sin(80*md))*0.07; //縞模様
				//col += 1-step(0.3,md); //中央の点
				return float4(col.rgb,1);

				//return float4(dist,dist,0,1);
				//return clamp(_Color,_Color2,dist);
				//return lerp(_Color,_Color2,dist);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

Shader "Custom/Base" {
	Properties{
		_Split("Split",Int) = 5
		_P("P",Float) = 0
		_RDM("RDM",Float) = 4
		_SPD("SPD",Float) = 1
		_Color("Color",Color) = (0,0,0,1)
		_Color2("Color2",Color) = (0,0,0,1)
	}
	SubShader{
		Tags{"Queue" = "Transparent" "RenderType" = "Transparent"}
		Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

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

			struct v2f {
				float4 pos:SV_POSITION;
				float4 uv:TEXCOORD0;
			};

			int _Split;
			float _P;
			float _RDM;
			float _SPD;
			float4 _Color;
			float4 _Color2;

			float rand(float2 co){
				return frac(sin(dot(co.xy ,float2(12.9898,78.233))) * 43758.5453);
			}

			float2 rand2(float2 st){
					 st = float2(dot(st, float2(127.1, 311.7)),
											 dot(st, float2(269.5, 183.3)));
					 return frac(sin(st) * 43758.5453123);
			 }

			v2f vert(appdata v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			float dist = 100;
			float4 frag(v2f i) :SV_Target {
				float2 auv = i.uv*_Split;
				float2 uv = frac(auv);
				float2 id = floor(auv);
				float dist = 100;
				//各マスのランダムな位置に頂点を配置
				//周囲8マスと現在のマスに配置されたランダムな頂点を探索し
				//処理対象のピクセルと最も近い点を探す
				for(int k=-1;k<=1;k++){
					for(int m=-1;m<=1;m++){
						float2 km = float2(k,m);
						float2 rand_p = rand2(id+km);
						//各マスの中心位置(0.5,0.5)から各成分+0.5までの移動を許している
						rand_p = float2(0.5,0.5)+0.5*sin(_Time.y*_SPD+_RDM*rand_p);
						dist = min(dist,length(rand_p+km-uv));
					}
				}
				//return float4(dist,dist,0,1);
				//return clamp(_Color,_Color2,dist);
				return lerp(_Color,_Color2,dist);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

shader ジオメトリシェーダでquadを生成してuvを貼り付ける

Shader "Custom/GeoBase" {
	Properties{
		_MainTex("MainTex",2D) = "white"{}
	}
	SubShader{
		Tags{"RenderType"="Opaque" "DisableBatching"="true"}
		//透明部分のあるテクスチャを使う場合
		//Tags{"Queue" = "Transparent" "RenderType" = "Transparent" "DisableBatching"="true"}
		//Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			Cull Off
			CGPROGRAM
			#pragma vertex vert
			#pragma geometry geom
			#pragma fragment frag
			#pragma target 4.0
			//インスペクタに Enable GPU Instanceが追加される
			#pragma multi_compile_instancing

			#include "UnityCG.cginc"

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

			struct g2f {
				float4 pos:SV_POSITION;
				float2 uv:TEXCOORD0;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			//SV_VertexID:頂点のid(こちらはGPU Instancingがオンになってなくても有効なはず)
			appdata vert(appdata v,uint vid : SV_VertexID){
				v.vid = vid;//GPU
				return v;
			}

			sampler2D _MainTex;
			float4 _MainTex_ST;

			[maxvertexcount(4)]
			void geom(triangle appdata vg[3], inout TriangleStream<g2f> outStream){
				float p = 0.5;

				g2f gf = (g2f)0;

				gf.pos = UnityObjectToClipPos(float4(p,p,0,1));
				gf.uv = float2(1,1);
				outStream.Append(gf);

				gf.pos = UnityObjectToClipPos(float4(p,-p,0,1));
				gf.uv = float2(1,0);
				outStream.Append(gf);

				gf.pos = UnityObjectToClipPos(float4(-p,p,0,1));
				gf.uv = float2(0,1);
				outStream.Append(gf);

				gf.pos = UnityObjectToClipPos(float4(-p,-p,0,1));
				gf.uv = float2(0,0);
				outStream.Append(gf);

				outStream.RestartStrip();
			}

			float4 frag(g2f i) :SV_Target {
				return tex2D(_MainTex,i.uv);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}

shader ジオメトリシェーダ、増やした頂点の面にテクスチャを貼る

f:id:arumogina:20190824180558p:plain


右側がジオメトリシェーダで増やした頂点の面

Shader "Custom/GeoBase" {
	Properties{
		_MainTex("MainTex",2D) = "white"{}
	}
	SubShader{
		Tags{"RenderType"="Opaque" "DisableBatching"="true"}
		//透明部分のあるテクスチャを使う場合
		//Tags{"Queue" = "Transparent" "RenderType" = "Transparent" "DisableBatching"="true"}
		//Blend SrcAlpha OneMinusSrcAlpha

		Pass{
			Cull Off
			CGPROGRAM
			#pragma vertex vert
			#pragma geometry geom
			#pragma fragment frag
			#pragma target 4.0
			//インスペクタに Enable GPU Instanceが追加される
			#pragma multi_compile_instancing

			#include "UnityCG.cginc"

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

			struct g2f {
				float4 pos:SV_POSITION;
				float2 uv:TEXCOORD0;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			//SV_VertexID:頂点のid(こちらはGPU Instancingがオンになってなくても有効なはず)
			appdata vert(appdata v,uint vid : SV_VertexID){
				v.vid = vid;//GPU
				return v;
			}

			sampler2D _MainTex;
			float4 _MainTex_ST;

			[maxvertexcount(6)]
			void geom(triangle appdata vg[3], inout TriangleStream<g2f> outStream){
    		[unroll]
    		for (int i = 0; i < 3; i++){
        	appdata v = vg[i];
					UNITY_SETUP_INSTANCE_ID(v);
        	g2f o = (g2f)0;
        	o.pos = UnityObjectToClipPos(v.vertex);
					o.uv = TRANSFORM_TEX(v.uv, _MainTex);
        	outStream.Append(o);
    		}
				outStream.RestartStrip();
				for (int i = 0; i < 3; i++){
					appdata v = vg[i];
					UNITY_SETUP_INSTANCE_ID(v);
					float4 wpos = mul(unity_ObjectToWorld,v.vertex);
					wpos.x += 2;
					g2f o = (g2f)0;
					o.pos = mul(UNITY_MATRIX_VP,wpos);
					o.uv = TRANSFORM_TEX(v.uv, _MainTex);
					outStream.Append(o);
				}
    		outStream.RestartStrip();
			}

			float4 frag(g2f i) :SV_Target {
				return tex2D(_MainTex,i.uv);
			}
			ENDCG
		}//Pass
	}//SubShader
	FallBack "Diffuse"
}