シェーダだけで世界を創る!three.jsによるレイマーチング
こちらのレイマーチのHLSL版です
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 }