223 lines
6.6 KiB
HLSL
223 lines
6.6 KiB
HLSL
#ifndef VOLUMETRIC_FOG_2_RAYMARCH
|
|
#define VOLUMETRIC_FOG_2_RAYMARCH
|
|
|
|
sampler2D _MainTex;
|
|
sampler3D _DetailTex;
|
|
float jitter;
|
|
float _NoiseScale;
|
|
half4 _Color;
|
|
|
|
float3 _SunDir;
|
|
float _ShadowIntensity;
|
|
float _DeepObscurance;
|
|
float _LightDiffusionIntensity, _LightDiffusionPower;
|
|
float3 _WindDirection;
|
|
half4 _LightColor;
|
|
half _Density;
|
|
|
|
float4 _BoundsBorder;
|
|
#define BORDER_SIZE_SPHERE _BoundsBorder.x
|
|
#define BORDER_START_SPHERE _BoundsBorder.y
|
|
#define BORDER_SIZE_BOX _BoundsBorder.xz
|
|
#define BORDER_START_BOX _BoundsBorder.yw
|
|
|
|
float3 _BoundsData;
|
|
#define BOUNDS_VERTICAL_OFFSET _BoundsData.x
|
|
#define BOUNDS_BOTTOM _BoundsData.y
|
|
#define BOUNDS_SIZE_Y _BoundsData.z
|
|
|
|
|
|
half4 _DetailData; // x = strength, y = offset, z = scale, w = importance
|
|
half4 _DetailColor;
|
|
#define DETAIL_STRENGTH _DetailData.x
|
|
#define DETAIL_OFFSET _DetailData.y
|
|
#define DETAIL_SCALE _DetailData.z
|
|
#define USE_BASE_NOISE _DetailData.w
|
|
|
|
float4 _RayMarchSettings;
|
|
|
|
#define FOG_STEPPING _RayMarchSettings.x
|
|
#define DITHERING _RayMarchSettings.y
|
|
#define JITTERING _RayMarchSettings.z
|
|
#define MIN_STEPPING _RayMarchSettings.w
|
|
|
|
float loop_t;
|
|
|
|
#include "PointLights.cginc"
|
|
#include "FogVoids.cginc"
|
|
#include "FogOfWar.cginc"
|
|
#include "FogDistance.cginc"
|
|
#include "Surface.cginc"
|
|
|
|
TEXTURE2D(_BlueNoise);
|
|
SAMPLER(sampler_PointRepeat);
|
|
float4 _BlueNoise_TexelSize;
|
|
|
|
float3 _VFRTSize;
|
|
|
|
void SetJitter(float4 scrPos) {
|
|
|
|
float2 screenSize = lerp(_ScreenParams.xy, _VFRTSize.xy, _VFRTSize.z);
|
|
float2 uv = (scrPos.xy / scrPos.w) * screenSize;
|
|
|
|
#if defined(FOG_BLUE_NOISE)
|
|
float2 noiseUV = uv * _BlueNoise_TexelSize.xy;
|
|
jitter = SAMPLE_TEXTURE2D(_BlueNoise, sampler_PointRepeat, noiseUV).r;
|
|
#else
|
|
//Jitter = frac(dot(float2(2.4084507, 3.2535211), (scrPos.xy / scrPos.w) * _ScreenParams.xy));
|
|
const float3 magic = float3( 0.06711056, 0.00583715, 52.9829189 );
|
|
jitter = frac( magic.z * frac( dot( uv, magic.xy ) ) );
|
|
#endif
|
|
}
|
|
|
|
|
|
inline float3 ProjectOnPlane(float3 v, float3 planeNormal) {
|
|
float sqrMag = dot(planeNormal, planeNormal);
|
|
float dt = dot(v, planeNormal);
|
|
return v - planeNormal * dt / sqrMag;
|
|
}
|
|
|
|
inline float3 GetRayStart(float3 wpos) {
|
|
float3 cameraPosition = GetCameraPositionWS();
|
|
#if defined(ORTHO_SUPPORT)
|
|
float3 cameraForward = UNITY_MATRIX_V[2].xyz;
|
|
float3 rayStart = ProjectOnPlane(wpos - cameraPosition, cameraForward) + cameraPosition;
|
|
return lerp(cameraPosition, rayStart, unity_OrthoParams.w);
|
|
#else
|
|
return cameraPosition;
|
|
#endif
|
|
}
|
|
|
|
|
|
half4 SampleDensity(float3 wpos) {
|
|
|
|
float3 boundsCenter = _BoundsCenter;
|
|
float3 boundsExtents = _BoundsExtents;
|
|
|
|
SurfaceApply(boundsCenter, boundsExtents);
|
|
|
|
#if VF2_DETAIL_NOISE
|
|
half detail = tex3Dlod(_DetailTex, float4(wpos * DETAIL_SCALE - _WindDirection, 0)).a;
|
|
half4 density = _DetailColor;
|
|
if (USE_BASE_NOISE) {
|
|
wpos.xyz -= boundsCenter;
|
|
wpos.y /= boundsExtents.y;
|
|
density = tex2Dlod(_MainTex, float4(wpos.xz * _NoiseScale - _WindDirection.xz, 0, 0));
|
|
density.a -= abs(wpos.y);
|
|
}
|
|
density.a += (detail + DETAIL_OFFSET) * DETAIL_STRENGTH;
|
|
#else
|
|
wpos.xyz -= boundsCenter;
|
|
wpos.y /= boundsExtents.y;
|
|
half4 density = tex2Dlod(_MainTex, float4(wpos.xz * _NoiseScale - _WindDirection.xz, 0, 0));
|
|
density.a -= abs(wpos.y);
|
|
#endif
|
|
|
|
return density;
|
|
}
|
|
|
|
|
|
#define dot2(x) dot(x,x)
|
|
|
|
void AddFog(float3 rayStart, float3 wpos, float rs, half4 baseColor, inout half4 sum) {
|
|
|
|
half4 density = SampleDensity(wpos);
|
|
|
|
#if VF2_VOIDS
|
|
density.a -= ApplyFogVoids(wpos);
|
|
#endif
|
|
|
|
#if VF2_SHAPE_SPHERE
|
|
float3 delta = wpos - _BoundsCenter;
|
|
delta.y += BOUNDS_VERTICAL_OFFSET;
|
|
float distSqr = dot2(delta);
|
|
float border = 1.0 - saturate( (distSqr - BORDER_START_SPHERE) / BORDER_SIZE_SPHERE );
|
|
density.a *= border * border;
|
|
#else
|
|
float2 dist2 = abs(wpos.xz - _BoundsCenter.xz);
|
|
float2 border2 = saturate( (dist2 - BORDER_START_BOX) / BORDER_SIZE_BOX );
|
|
float border = 1.0 - max(border2.x, border2.y);
|
|
density.a *= border * border;
|
|
#endif
|
|
|
|
|
|
if (density.a > 0) {
|
|
half4 fgCol = baseColor * half4((1.0 - density.a * _DeepObscurance).xxx, density.a);
|
|
#if VF2_RECEIVE_SHADOWS
|
|
half shadowAtten = GetLightAttenuation(wpos);
|
|
fgCol.rgb *= lerp(1.0, shadowAtten, _ShadowIntensity);
|
|
#endif
|
|
#if VF2_NATIVE_LIGHTS
|
|
int additionalLightCount = GetAdditionalLightsCount();
|
|
for (int i = 0; i < additionalLightCount; ++i) {
|
|
#if UNITY_VERSION >= 202030
|
|
Light light = GetAdditionalLight(i, wpos, 1.0.xxxx);
|
|
#else
|
|
Light light = GetAdditionalLight(i, wpos);
|
|
#endif
|
|
fgCol.rgb += light.color * (light.distanceAttenuation * light.shadowAttenuation);
|
|
}
|
|
#endif
|
|
fgCol.rgb *= density.rgb * fgCol.aaa;
|
|
#if VF2_FOW
|
|
fgCol *= ApplyFogOfWar(wpos);
|
|
#endif
|
|
#if VF2_DISTANCE
|
|
fgCol *= ApplyFogDistance(rayStart, wpos);
|
|
#endif
|
|
#if VF2_DEPTH_GRADIENT
|
|
fgCol *= ApplyDepthGradient(rayStart, wpos);
|
|
#endif
|
|
#if VF2_HEIGHT_GRADIENT
|
|
fgCol *= ApplyHeightGradient(wpos);
|
|
#endif
|
|
|
|
fgCol *= min(1.0, _Density * rs);
|
|
sum += fgCol * (1.0 - sum.a);
|
|
}
|
|
}
|
|
|
|
|
|
half4 GetFogColor(float3 rayStart, float3 viewDir, float t0, float t1) {
|
|
|
|
t0 = min(t0 + jitter * JITTERING, t1);
|
|
float len = t1 - t0;
|
|
float rs = MIN_STEPPING + max(log(len), 0) / FOG_STEPPING; // stepping ratio with atten detail with distance
|
|
half4 sum = half4(0,0,0,0);
|
|
float diffusion = 1.0 + pow(max(dot(viewDir, _SunDir.xyz), 0), _LightDiffusionPower) * _LightDiffusionIntensity;
|
|
half3 diffusionColor = _LightColor.rgb * diffusion;
|
|
half4 lightColor = half4(diffusionColor, 1.0);
|
|
|
|
float3 wpos = rayStart + viewDir * t0;
|
|
float3 endPos = rayStart + viewDir * t1;
|
|
SurfaceComputeEndPoints(wpos, endPos);
|
|
|
|
wpos.y -= BOUNDS_VERTICAL_OFFSET;
|
|
viewDir *= rs;
|
|
|
|
float energyStep = rs;
|
|
rs /= len + 0.001;
|
|
rs = max(rs, 1.0 / MAX_ITERATIONS);
|
|
|
|
float t = 0;
|
|
|
|
// Use this Unroll macro to support WebGL. Increase 50 value if needed.
|
|
#if defined(WEBGL_COMPATIBILITY_MODE)
|
|
UNITY_UNROLLX(50)
|
|
#endif
|
|
while (t < 1.0) {
|
|
loop_t = t;
|
|
AddFog(rayStart, wpos, energyStep, lightColor, sum);
|
|
if (sum.a > 0.99) break;
|
|
t += rs;
|
|
wpos += viewDir;
|
|
}
|
|
AddFog(rayStart, endPos, len * (rs - (t-1.0)), lightColor, sum);
|
|
|
|
sum = max(0, sum - jitter * DITHERING);
|
|
sum *= _LightColor.a;
|
|
return sum;
|
|
}
|
|
|
|
|
|
#endif // VOLUMETRIC_FOG_2_RAYMARCH |