フルスクリーンでレイマーチ(RayMarching)
環境
Unity2021.3.4f1
概要
フルスクリーンでRayMarchingをやってみました。
この10個のメタボールからなる形状とその影はRayMarchingで描画しています。
黄色の床はUnityのPlaneのGameObjectです。
「3D Objects > Quad」でQuadを作成して、カメラの階層に置き、このシェーダのマテリアルを設定すれば動作すると思います。
ClusterのワールドクラフトでRayMarchingを実装してみました。
Clusterでは自作スクリプトを動作させることができないのでシェーダで全部やっています。 デスクトップ版でしか試してないのでVRだとまともに見えないかも知れません。
Shader "Custom/Raymarching" { Properties { _RayStep("Ray Step", Range(16, 128)) = 32 _RayDistanceMin("Ray Distance Min", Range(0.001, 0.1)) = 0.1 _SpecularColor("Specular Color", Color) = (1,1,1,1) _SpecularExp("SpecularExp", Range(4, 128)) = 64 } CGINCLUDE #include "UnityCG.cginc" #include "Lighting.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; float2 uv : TEXCOORD0; }; struct fout { float4 col : SV_Target; float depth : SV_Depth; }; uint _RayStep; float _RayDistanceMin; float4 _SpecularColor; float _SpecularExp; float4x4 inverse(float4x4 m) { float4x4 cofactors = float4x4( determinant(float3x3(m._22_23_24, m._32_33_34, m._42_43_44)), -determinant(float3x3(m._21_23_24, m._31_33_34, m._41_43_44)), determinant(float3x3(m._21_22_24, m._31_32_34, m._41_42_44)), -determinant(float3x3(m._21_22_23, m._31_32_33, m._41_42_43)), -determinant(float3x3(m._12_13_14, m._32_33_34, m._42_43_44)), determinant(float3x3(m._11_13_14, m._31_33_34, m._41_43_44)), -determinant(float3x3(m._11_12_14, m._31_32_34, m._41_42_44)), determinant(float3x3(m._11_12_13, m._31_32_33, m._41_42_43)), determinant(float3x3(m._12_13_14, m._22_23_24, m._42_43_44)), -determinant(float3x3(m._11_13_14, m._21_23_24, m._41_43_44)), determinant(float3x3(m._11_12_14, m._21_22_24, m._41_42_44)), -determinant(float3x3(m._11_12_13, m._21_22_23, m._41_42_43)), -determinant(float3x3(m._12_13_14, m._22_23_24, m._32_33_34)), determinant(float3x3(m._11_13_14, m._21_23_24, m._31_33_34)), -determinant(float3x3(m._11_12_14, m._21_22_24, m._31_32_34)), determinant(float3x3(m._11_12_13, m._21_22_23, m._31_32_33)) ); return transpose(cofactors) / determinant(m); } inline bool IsOrtho() { return UNITY_MATRIX_P._m33 == 1.0; } inline float3 GetCameraPos() { float3 cpos = mul(inverse(UNITY_MATRIX_V), float4(0, 0, 0, 1)).xyz; return cpos; } inline float3 GetOrthoCameraForward(float3 posWS) { float3 viewDirWS = UNITY_MATRIX_V[2].xyz; float3 rayDirWS = normalize(posWS - GetCameraPos()); if (dot(viewDirWS, rayDirWS) < 0) viewDirWS *= -1; viewDirWS *= _ProjectionParams.x; return viewDirWS; } float3 GetViewDirectionWS(float3 posWS) { float3 rayDirWS; [branch] if (IsOrtho()) { rayDirWS = GetOrthoCameraForward(posWS); } else { rayDirWS = normalize(posWS - GetCameraPos()); } return rayDirWS; } inline float GetDepthNear() { #if defined(UNITY_REVERSED_Z) float near = 1.0; #else float near = 0.0; #endif return near; } inline float GetDepthFar() { #if defined(UNITY_REVERSED_Z) float far = 0.0; #else float far = 1.0; #endif return far; } inline float GetProjNear() { float near = GetDepthNear(); #if defined(SHADER_API_GLCORE) || defined(SHADER_API_OPENGL) || defined(SHADER_API_GLES) || defined(SHADER_API_GLES3) near = near * 2.0 - 1.0; #endif return near; } inline float ComputeDepth(float4 posPS) { float z = posPS.z / posPS.w; #if defined(SHADER_API_GLCORE) || defined(SHADER_API_OPENGL) || defined(SHADER_API_GLES) || defined(SHADER_API_GLES3) return z * 0.5 + 0.5; #else return z; #endif } void VertCommon(appdata v, inout float4 o_pos, inout float3 o_posWS, inout float3 o_rayWS, inout float3 o_lightWS, inout float3 o_viewWS) { o_pos = float4(v.uv * 2.0 - 1.0, GetProjNear(), 1.0); float4 posWS = mul(inverse(UNITY_MATRIX_VP), o_pos); o_posWS = posWS.xyz / posWS.w; o_rayWS = GetViewDirectionWS(o_posWS); o_lightWS = UnityWorldSpaceLightDir(posWS); o_viewWS = UnityWorldSpaceViewDir(posWS); } inline float DistSphare(float3 posWS, float3 spherePos) { float radius = 0.5; return length(posWS - spherePos) - radius; } inline float SmoothUnion(float d1, float d2, float k) { float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0); return lerp(d2, d1, h) - k * h * (1.0 - h); } float Distance(float3 posWS) { float dist = 1000.0; for (uint i = 0; i < 10; i++) { float d = DistSphare(posWS, float3(0.75 * i, 0.0, sin(_Time.y + 1.0 * i))); dist = SmoothUnion(dist, d, 0.25); } return dist; } float3 Normal(float3 posWS) { float d = 0.0001; return normalize(float3( Distance(posWS + float3(d, 0.0, 0.0)) - Distance(posWS + float3(-d, 0.0, 0.0)), Distance(posWS + float3(0.0, d, 0.0)) - Distance(posWS + float3(0.0, -d, 0.0)), Distance(posWS + float3(0.0, 0.0, d)) - Distance(posWS + float3(0.0, 0.0, -d)) )); } fout FragCommon(float3 i_posWS, float3 i_rayWS, float3 i_lightWS, float3 i_viewWS) { fout o; float3 posWS = i_posWS; float3 rayDirWS = normalize(i_rayWS); const float minDist = _RayDistanceMin; float dist = 1000.0; for (uint s = 0; s < _RayStep && dist > minDist; s++) { dist = Distance(posWS); posWS += rayDirWS * dist; } if (dist < minDist) { #if defined(SHADOWS_DEPTH) o.col = 0.0; #else float3 normalWS = Normal(posWS); float3 lightWS = normalize(i_lightWS); float3 viewWS = normalize(i_viewWS); fixed3 diffuse = _LightColor0.rgb * saturate(dot(normalWS, lightWS)); fixed3 halfDirWS = normalize(lightWS + viewWS); fixed3 specular = _LightColor0.rgb * _SpecularColor.rgb * pow(saturate(dot(halfDirWS, normalWS)), _SpecularExp); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; fixed4 finalColor = fixed4(ambient + diffuse + specular, 1.0); o.col = finalColor; #endif float4 posPS = mul(UNITY_MATRIX_VP, float4(posWS, 1.0)); o.depth = ComputeDepth(posPS); } else { o.col = 0.0; o.depth = GetDepthFar(); } return o; } ENDCG SubShader { Tags { "Queue" = "Geometry-1"} Pass { Tags{"LightMode" = "ForwardBase" } LOD 100 Cull Off Blend SrcAlpha OneMinusSrcAlpha Zwrite On ZTest LEqual CGPROGRAM #pragma vertex vert #pragma fragment frag struct v2f { float4 pos : SV_POSITION; float3 posWS : TEXCOORD1; float3 rayWS : TEXCOORD2; float3 lightWS : TEXCOORD3; float3 viewWS : TEXCOORD4; }; v2f vert(appdata v) { v2f o; VertCommon(v, o.pos, o.posWS, o.rayWS, o.lightWS, o.viewWS); return o; } fout frag(v2f i) { fout o; o = FragCommon(i.posWS, i.rayWS, i.lightWS, i.viewWS);// , _WorldSpaceCameraPos); return o; } ENDCG } Pass { Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} LOD 100 Cull Off Zwrite On ZTest LEqual CGPROGRAM #pragma multi_compile_shadowcaster #pragma vertex vert #pragma fragment frag struct v2f { float4 pos : SV_POSITION; float3 posWS : TEXCOORD1; float3 rayWS : TEXCOORD2; float3 lightWS : TEXCOORD3; float3 viewWS : TEXCOORD4; //V2F_SHADOW_CASTER; }; v2f vert(appdata v) { v2f o; VertCommon(v, o.pos, o.posWS, o.rayWS, o.lightWS, o.viewWS); //TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); return o; } fout frag(v2f i) { fout o; o = FragCommon(i.posWS, i.rayWS, i.lightWS, i.viewWS); return o; } ENDCG } } }