Shader "Custom/SDFRaymarchFog"
_MainTex ("Texture", 3D) = "white" {}
_LightColor ("Light Color", Color) = (1, 1, 1, 1)
_FogDensity ("Fog Density", Range(0.0, 1.0)) = 0.1
_MaxDistance ("Max Distance", Range(0.0, 100.0)) = 50.0
_StepSize ("Step Size", Range(0.001, 1.0)) = 0.1
_BoxMin ("Box Min", Vector) = (-1, -1, -1, 1)
_BoxMax ("Box Max", Vector) = (1, 1, 1, 1)
_DensityThreshold ("Density Threshold", Range(0.0, 1.0)) = 0.01
Tags { "Queue" = "Transparent" "RenderType"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
float4 vertex : POSITION;
float4 pos : SV_POSITION;
float3 worldPos : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = mul((float3x3)unity_ObjectToWorld, v.normal);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
// Transform point to [0,1] range for texture sampling
vec3 boxSize = _BoxMax.xyz - _BoxMin.xyz;
vec3 localPos = (p - _BoxMin.xyz) / boxSize;
return tex3D(_MainTex, localPos).r;
float3 getRayBoxIntersection(vec3 ro, vec3 rd, vec3 boxMin, vec3 boxMax)
vec3 tMin = (boxMin - ro) * invDir;
vec3 tMax = (boxMax - ro) * invDir;
vec3 t1 = min(tMin, tMax);
vec3 t2 = max(tMin, tMax);
float tNear = max(max(t1.x, t1.y), t1.z);
float tFar = min(min(t2.x, t2.y), t2.z);
return float3(tNear, tFar, tFar >= tNear ? 1.0 : 0.0);
float raymarch(vec3 ro, vec3 rd, out float3 color)
// Get the intersection of the ray with the box
float3 tHit = getRayBoxIntersection(ro, rd, _BoxMin.xyz, _BoxMax.xyz);
float t = max(0.0, tHit.x);
for (int i = 0; i < 256; i++)
float3 pos = ro + t * rd;
density += _FogDensity * (1.0 - exp(-d * _FogDensity));
if (t > min(tHit.y, _MaxDistance)) break;
color = _LightColor.rgb * density;
fixed4 frag (v2f i) : SV_Target
float3 rd = normalize(i.worldNormal);
float density = raymarch(ro, rd, color);
if (density < _DensityThreshold)
return fixed4(0, 0, 0, 0); // Transparent
return fixed4(color, density);