diff options
| -rw-r--r-- | 2ner.cginc | 19 | ||||
| -rw-r--r-- | 2ner.shader | 32 | ||||
| -rw-r--r-- | features.cginc | 9 | ||||
| -rw-r--r-- | fog.cginc | 136 | ||||
| -rw-r--r-- | globals.cginc | 18 |
5 files changed, 113 insertions, 101 deletions
@@ -230,23 +230,20 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace FogParams fog_params = {
_Raymarched_Fog_Color.rgb,
_Raymarched_Fog_Steps,
- _Raymarched_Fog_Density,
_Raymarched_Fog_Y_Cutoff,
_Raymarched_Fog_Dithering_Noise,
_Raymarched_Fog_Dithering_Noise_TexelSize,
_Raymarched_Fog_Density_Noise,
_Raymarched_Fog_Density_Noise_Scale,
_Raymarched_Fog_Velocity.xyz,
- #if defined(_RAYMARCHED_FOG_DENSITY_EXPONENT)
- _Raymarched_Fog_Density_Exponent,
- #endif
- #if defined(_RAYMARCHED_FOG_HEIGHT_DENSITY)
- _Raymarched_Fog_Height_Density_Start,
- _Raymarched_Fog_Height_Density_Half_Life,
- #endif
- #if defined(_CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM)
- _Custom30_Fog_Height_Density_Minimum,
- #endif
+ _Raymarched_Fog_Mean_Free_Path,
+ _Raymarched_Fog_Albedo,
+ _Raymarched_Fog_G,
+ _Raymarched_Fog_Height_Scale,
+ _Raymarched_Fog_Height_Offset,
+ _Raymarched_Fog_Turbulence,
+ _Raymarched_Fog_Step_Size,
+ _Raymarched_Fog_Step_Growth,
#if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE)
_Raymarched_Fog_Emitter_Texture,
_Raymarched_Fog_Emitter_Texture_TexelSize,
diff --git a/2ner.shader b/2ner.shader index 3dffe34..3472187 100644 --- a/2ner.shader +++ b/2ner.shader @@ -830,35 +830,19 @@ Shader "yum_food/2ner" [ThryToggle(_RAYMARCHED_FOG)] _Raymarched_Fog_Enabled("Enable", Float) = 0 _Raymarched_Fog_Steps("Steps", Range(1, 32)) = 32 _Raymarched_Fog_Color("Color", Color) = (0.3, 0.3, 0.3, 1) - _Raymarched_Fog_Density("Density", Float) = 1.0 _Raymarched_Fog_Dithering_Noise("Dithering noise", 2D) = "black" {} _Raymarched_Fog_Density_Noise("Density noise", 3D) = "black" {} _Raymarched_Fog_Density_Noise_Scale("Density noise scale", Vector) = (1, 1, 1, 0) _Raymarched_Fog_Y_Cutoff("Y cutoff", Float) = -1000 _Raymarched_Fog_Velocity("Velocity", Vector) = (1, -.2, 0, 0) - - //ifex _Raymarched_Fog_Density_Exponent_Enabled==0 - [HideInInspector] m_start_Raymarched_Fog_Density_Exponent("Density exponent", Float) = 0 - [ThryToggle(_RAYMARCHED_FOG_DENSITY_EXPONENT)] _Raymarched_Fog_Density_Exponent_Enabled("Enable", Float) = 0 - _Raymarched_Fog_Density_Exponent("Exponent", Float) = 1 - [HideInInspector] m_end_Raymarched_Fog_Density_Exponent("Density exponent", Float) = 0 - //endex - - //ifex _Raymarched_Fog_Height_Density_Enabled==0 - [HideInInspector] m_start_Raymarched_Fog_Height_Density("Height density", Float) = 0 - [ThryToggle(_RAYMARCHED_FOG_HEIGHT_DENSITY)] _Raymarched_Fog_Height_Density_Enabled("Enable", Float) = 0 - _Raymarched_Fog_Height_Density_Start("Start elevation", Float) = 0 - _Raymarched_Fog_Height_Density_Half_Life("Half life", Float) = 1 - - //ifex _Custom30_Fog_Height_Density_Minimum_Enabled==0 - [HideInInspector] m_start_Custom30_Fog_Height_Density_Minimum("Minimum", Float) = 0 - [ThryToggle(_CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM)] _Custom30_Fog_Height_Density_Minimum_Enabled("Enable", Float) = 0 - _Custom30_Fog_Height_Density_Minimum("Minimum factor", Float) = 0 - [HideInInspector] m_end_Custom30_Fog_Height_Density_Minimum("Minimum", Float) = 0 - //endex - [HideInInspector] m_end_Raymarched_Fog_Height_Density("Height density", Float) = 0 - //endex - + _Raymarched_Fog_Mean_Free_Path("Mean free path", Float) = 1 + _Raymarched_Fog_Albedo("Albedo", Float) = 1 + _Raymarched_Fog_G("G", Float) = 1 + _Raymarched_Fog_Height_Scale("Height scale", Float) = 10 + _Raymarched_Fog_Height_Offset("Height offset", Float) = 0 + _Raymarched_Fog_Turbulence("Turbulence", Float) = 1 + _Raymarched_Fog_Step_Size("Step size", Float) = 0.8 + _Raymarched_Fog_Step_Growth("Step growth", Float) = 1.25 //ifex _Raymarched_Fog_Emitter_Texture_Enabled==0 [HideInInspector] m_start_Raymarched_Fog_Emitter_Texture("Emitter texture", Float) = 0 [ThryToggle(_RAYMARCHED_FOG_EMITTER_TEXTURE)] _Raymarched_Fog_Emitter_Texture_Enabled("Enable", Float) = 0 diff --git a/features.cginc b/features.cginc index 589e4cf..b46c97e 100644 --- a/features.cginc +++ b/features.cginc @@ -317,15 +317,6 @@ #pragma shader_feature_local _RAYMARCHED_FOG //endex -//ifex _Raymarched_Fog_Height_Density_Enabled==0 -#pragma shader_feature_local _RAYMARCHED_FOG_HEIGHT_DENSITY -#pragma shader_feature_local _CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM -//endex - -//ifex _Raymarched_Fog_Density_Exponent_Enabled==0 -#pragma shader_feature_local _RAYMARCHED_FOG_DENSITY_EXPONENT -//endex - //ifex _Raymarched_Fog_Emitter_Texture_Enabled==0 #pragma shader_feature_local _RAYMARCHED_FOG_EMITTER_TEXTURE //endex @@ -5,29 +5,28 @@ #include "cnlohr.cginc" #include "interpolators.cginc" #include "globals.cginc" +#include "LightVolumes.cginc" #if defined(_RAYMARCHED_FOG) struct FogParams { float3 color; float steps; - float density; float y_cutoff; texture2D dithering_noise; float4 dithering_noise_texelsize; texture3D density_noise; float4 density_noise_scale; float3 velocity; -#if defined(_RAYMARCHED_FOG_DENSITY_EXPONENT) - float density_exponent; -#endif -#if defined(_RAYMARCHED_FOG_HEIGHT_DENSITY) - float height_density_start; - float height_density_half_life; -#endif -#if defined(_CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM) - float height_density_minimum; -#endif + // Physical description of the medium (all in metres or unit-less) + float mean_free_path; // ⟨s⟩ = 1 / σ_t + float albedo; // ω = σ_s / σ_t (0 … 1) + float g; // Henyey-Greenstein anisotropy (−1 … 1) + float height_scale; // H where ρ(y)=ρ₀·exp(−y/H) + float height_offset; + float turbulence; // Strength of noise modulation (0 … 1) + float step_size; + float step_growth; #if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE) texture2D emitter_texture; float4 emitter_texture_texelsize; @@ -66,6 +65,16 @@ float3 getEmitterData(FogParams p, float3 pp) } #endif +// --------------------------------------------------------------------------- +// Henyey–Greenstein phase function +static const float INV_FOUR_PI = 0.079577471545947667884f; // 1/(4π) + +inline float PhaseHG(float cosTheta, float g) +{ + float g2 = g * g; + return INV_FOUR_PI * (1.0 - g2) / pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5); +} + struct FogResult { float4 color; float depth; @@ -96,7 +105,6 @@ FogResult raymarched_fog(v2f i, FogParams p) } } linearZ = min(linearZ, distance_to_y); - linearZ = min(linearZ, 1200); linearZ -= ro_epsilon; float dither = p.dithering_noise.SampleLevel(point_repeat_s, @@ -104,54 +112,88 @@ FogResult raymarched_fog(v2f i, FogParams p) const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x); dither = frac(dither + PHI * frame); - ro += rd * dither; - linearZ -= dither; - float step_size = linearZ / p.steps; + // Exponential stepping parameters + float step_size = p.step_size; + float step_growth = p.step_growth; + float3 pp = ro; - float4 color = 0; + float max_dist = linearZ; + + float T = 1; // Transmittance + float3 L = 0; // Accumulated radiance + float traveled = 0; + [loop] - for (uint ii = 0; ii < p.steps; ++ii) { - pp += step_size * rd; - + for (uint ii = 0; ii < p.steps && traveled < max_dist; ++ii) + { + // Clamp step size to avoid missing dense features + float current_step = min(step_size, 2.0 * p.mean_free_path); + + // Apply dithering to this step + float dithered_step = current_step * (1.0 - dither + dither * 2.0); + + // Advance position + pp += dithered_step * rd; + traveled += dithered_step; + + // --- Density ---------------------------------------------------------- float3 noise_coord = (pp + _Time[0] * p.velocity) * p.density_noise_scale.xyz; + float noise_sample = p.density_noise.SampleLevel(bilinear_repeat_s, noise_coord, 0).r; + float noise_factor = lerp(1.0 - 0.5 * p.turbulence, 1.0 + 0.5 * p.turbulence, noise_sample); - float cur_d = p.density_noise.SampleLevel(bilinear_repeat_s, - noise_coord, 0); + float height_factor = exp(-max(pp.y - p.height_offset, 0.0) / p.height_scale); -#if defined(_RAYMARCHED_FOG_DENSITY_EXPONENT) - cur_d = pow(cur_d, p.density_exponent); -#endif + float sigma_t = noise_factor * height_factor / max(p.mean_free_path, 1e-4); + float sigma_s = sigma_t * p.albedo; - cur_d *= p.density * step_size; - -#if defined(_RAYMARCHED_FOG_HEIGHT_DENSITY) - float height_clamped = max(pp.y - p.height_density_start, 0); - // if half_life = 2 and start = 0, then - // y=2 -> density = 1/2 - // y=4 -> density = 1/4 - // y=6 -> density = 1/8 - // if half_life = 3 and start = 0, then - // y=3 -> density = 1/2 - // y=6 -> density = 1/4 - // y=9 -> density = 1/8 - float exponent = height_clamped / p.height_density_half_life; - float factor = pow(2, -exponent); -#if defined(_CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM) - factor = max(factor, p.height_density_minimum); -#endif - cur_d *= factor; -#endif + // Analytic integration over the segment + float exp_term = exp(-sigma_t * dithered_step); - cur_d = saturate(cur_d); + // If the segment is almost transparent, skip expensive work + if (sigma_t < 1e-6) + { + T *= exp_term; + continue; + } + // --- Incoming radiance ------------------------------------------------ + float3 L_in; #if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE) - float4 cur_c = float4(getEmitterData(p, pp) * cur_d, cur_d); + L_in = getEmitterData(p, pp); #else - float4 cur_c = float4(p.color * cur_d, cur_d); + // Indirect from SH / light volumes + float3 l00, l01r, l01g, l01b; + LightVolumeSH(pp, l00, l01r, l01g, l01b); + float3 indirect = LightVolumeEvaluate(float3(0, 1, 0), l00, l01r, l01g, l01b); + + // Direct from the dominant realtime light + float3 to_light = (_WorldSpaceLightPos0.w == 0.0) ? normalize(_WorldSpaceLightPos0.xyz) + : normalize(_WorldSpaceLightPos0.xyz - pp); + float phase = PhaseHG(dot(to_light, -rd), p.g); + float3 direct = _LightColor0.rgb * phase; + + L_in = (direct + indirect) * p.color; #endif - color += (1.0f - color.a) * cur_c; + + // --- Accumulate radiance --------------------------------------------- + float scattering_integral = (sigma_s / sigma_t) * (1.0 - exp_term); + L += T * scattering_integral * L_in; + + // Update transmittance + T *= exp_term; + + // Early exit if virtually opaque + if (T < 1e-3) + break; + + // Grow step size exponentially + step_size *= step_growth; } + + float4 color; + color.rgb = L; + color.a = 1 - T; // Alpha for proper compositing FogResult r; r.color = color; diff --git a/globals.cginc b/globals.cginc index 8c11d15..e18e796 100644 --- a/globals.cginc +++ b/globals.cginc @@ -563,16 +563,14 @@ texture3D _Raymarched_Fog_Density_Noise; float4 _Raymarched_Fog_Density_Noise_Scale;
float _Raymarched_Fog_Y_Cutoff;
float3 _Raymarched_Fog_Velocity;
-#if defined(_RAYMARCHED_FOG_DENSITY_EXPONENT)
-float _Raymarched_Fog_Density_Exponent;
-#endif
-#if defined(_RAYMARCHED_FOG_HEIGHT_DENSITY)
-float _Raymarched_Fog_Height_Density_Start;
-float _Raymarched_Fog_Height_Density_Half_Life;
-#endif
-#if defined(_CUSTOM30_FOG_HEIGHT_DENSITY_MINIMUM)
-float _Custom30_Fog_Height_Density_Minimum;
-#endif
+float _Raymarched_Fog_Mean_Free_Path;
+float _Raymarched_Fog_Albedo;
+float _Raymarched_Fog_G;
+float _Raymarched_Fog_Height_Scale;
+float _Raymarched_Fog_Height_Offset;
+float _Raymarched_Fog_Turbulence;
+float _Raymarched_Fog_Step_Size;
+float _Raymarched_Fog_Step_Growth;
#if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE)
texture2D _Raymarched_Fog_Emitter_Texture;
float4 _Raymarched_Fog_Emitter_Texture_TexelSize;
|
