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

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

レイマーチ 差集合のサンプル?

シェーダだけで世界を創る!three.jsによるレイマーチング

こちらのレイマーチのHLSL版です

 

f:id:arumogina:20190728220606p:plain

 

Shader "Custom/Ray9"{
	Properties{
		_BarLoop("BarLoop",Range(0,1)) = 1
		_BarSize("BarSize",Range(0,1)) = 0.1
		_BarOrigin("BarOrigin",Vector) = (0,0,0,0)

		_TubeLoop("TubeLoop",Range(0,1)) = 0.1
		_TubeSize("TubeSize",Range(0,1)) = 0.025
		_TubeOrigin("TubeOrigin",Vector) = (0,0,0,0)
	}
	SubShader{
		Tags { "RenderType" = "Opaque" "LightMode" = "ForwardBase" }
		LOD 100
		Cull Front
		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			float _BarSize;
			float _BarLoop;
			float4 _BarOrigin;

			float _TubeSize;
			float _TubeLoop;
			float4 _TubeOrigin;

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

			struct v2f{
				float2 uv : TEXCOORD0;
				float3 lpos : TEXCOORD1;
				float4 vertex : SV_POSITION;
			};

			v2f vert(appdata v){
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.lpos =v.vertex.xyz;//メッシュのローカル座標を代入
				o.uv = v.uv;
				return o;
			}

			float3 mod(float3 a, float3 b){
		 		return frac(abs(a / b)) * abs(b);
			}

			float2 Repeat(float2 p,float loop){
				return fmod(p,loop) - loop * 0.5;
			}

			float Tube(float2 p){
				p = abs(p);
				return length(Repeat(p,_TubeLoop)) - _TubeSize;
			}

			float Tubes(float3 p){
				p = p - _TubeOrigin;
				float x = Tube(p.yz);
				float y = Tube(p.xz);
				float z = Tube(p.xy);
				return min(min(x,y),z);
			}

			float Bar(float2 p){
				p = abs(p);
				return length(max(abs(Repeat(p,_BarLoop)) - _BarSize,0));
			}

			float Bars(float3 p){
				p = p - _BarOrigin;
				float bar_x = Bar(p.yz);
				float bar_y = Bar(p.xz);
				float bar_z = Bar(p.xy);
				return min(
								min(bar_x,bar_y),bar_z
							 );
			}

			float dist(float3 p){
				return max(Bars(p),-Tubes(p));
			}

			float3 getnormal(float3 p){
				float d = 0.0001;
				return normalize(float3(
					dist(p + float3(d, 0.0, 0.0)) - dist(p + float3(-d, 0.0, 0.0)),
					dist(p + float3(0.0, d, 0.0)) - dist(p + float3(0.0, -d, 0.0)),
					dist(p + float3(0.0, 0.0, d)) - dist(p + float3(0.0, 0.0, -d))
				));
			}


			fixed4 frag(v2f i) : SV_Target{
				float3 start = mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz;//レイのスタート位置をカメラのローカル座標とする
				//メッシュのローカル座標の、視点のローカル座標からの方向を求めることでレイの方向を定義
				float3 onelay = normalize(i.lpos.xyz - mul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz);

				float d =0;
				float t=0.001;
				for (int i = 0; i < 60; ++i) { //レイマーチのループを実行
					d = dist(start + onelay * t);
						t += d;
						//レイがどこにもぶつからずはるか遠くに行くか、ほぼ衝突していて進む距離がほとんどなくなったらループを終了する
						if (d < 0.01 || t > 1000) {
							break;
						}
				}
				float4 col = 1;
				if (d > 0.01||t>1000) { //レイが遠くに行っているか、衝突していないと判断すれば描画しない
					clip(-1);
				}
				else {
					float3 normal = getnormal(start+onelay * t);
					float3 lightdir = normalize(mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz);//オブジェクトスペースで計算しているので、ディレクショナルライトの角度もオブジェクトスペースにする
					float NdotL = max(0, dot(normal, lightdir));
					col = float4(float3(1,1,1)*NdotL,1);//ランバート反射を計算
				}
				return col;
			}
			ENDCG
		}//pass
	}//subshader
}