Files
3d-tower/Assets/Enviro 3 - Sky and Weather/Resources/Shader/Fog/EnviroVolumetricsURP.shader
2026-05-09 09:10:52 +08:00

407 lines
14 KiB
GLSL

Shader "Hidden/VolumetricsURP"
{
Properties
{
//_MainTex ("Texture", any) = "white" {}
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile __ ENVIROURP
#pragma shader_feature_local __ ENVIROURP17
#if defined (ENVIROURP)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#if defined (ENVIROURP17)
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#endif
float4x4 _LeftWorldFromView;
float4x4 _RightWorldFromView;
float4x4 _LeftViewFromScreen;
float4x4 _RightViewFromScreen;
sampler2D _DitherTexture;
TEXTURE2D_X_FLOAT(_CameraDepthTexture);
SAMPLER(sampler_CameraDepthTexture);
uniform sampler3D _NoiseTexture;
uniform int _Steps;
uniform float3 _CameraPosition;
uniform float4 _VolumetricLight;
uniform float4 _HeightFog;
uniform float4 _HeightParams;
uniform float4 _NoiseData;
uniform float3 _WindDirection;
uniform float4 _MieG;
uniform float _MaxRayLength;
uniform float _MaxRayLengthLights;
uniform float4 _AmbientColor;
uniform float3 _DirLightDir;
uniform float4 _Randomness;
#if !SHADER_API_GLES3
struct PointLight
{
float3 pos;
float range;
float3 color;
float padding;
};
StructuredBuffer<PointLight> _PointLights;
float _PointLightsCount;
struct SpotLight
{
float3 pos;
float range;
float3 color;
float3 lightDirection;
float lightCosHalfAngle;
float padding;
};
StructuredBuffer<SpotLight> _SpotLights;
float _SpotLightsCount;
#endif
struct v2f
{
float2 uv : TEXCOORD0;
float4 position : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
struct appdata
{
#if defined (ENVIROURP17)
uint vertex : SV_VertexID;
#else
float4 vertex : POSITION;
#endif
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
v2f vert (appdata v)
{
v2f o = (v2f)0;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if defined (ENVIROURP17)
float4 pos = GetFullScreenTriangleVertexPosition(v.vertex);
float2 uv = GetFullScreenTriangleTexCoord(v.vertex);
o.position = pos;
o.uv = DYNAMIC_SCALING_APPLY_SCALEBIAS(uv);
#else
o.position = float4(v.vertex.xyz,1);
#if UNITY_UV_STARTS_AT_TOP
o.position.y *= -1;
#endif
o.uv = v.texcoord;
#endif
return o;
}
float anisotropy(float costheta)
{
float g = _MieG.x;
float gsq = g*g;
float denom = 1 + gsq - 2.0 * g * costheta;
denom = denom * denom * denom;
denom = sqrt(max(0, denom));
return (1 - gsq) / denom;
}
float anisotropyPointSpot(float costheta)
{
float g = 0.8;
float gsq = g*g;
float denom = 1 + gsq - 2.0 * g * costheta;
denom = denom * denom * denom;
denom = sqrt(max(0, denom));
return (1 - gsq) / denom;
}
float Attenuation(float distNorm)
{
return 1.0 / (1.0 + 25.0 * distNorm);
}
float DirectionalLight(float3 wpos)
{
float atten = 1.0f;
half cascadeIndex = ComputeCascadeIndex(wpos);
bool inside = dot(cascadeIndex, 1) < 4;
float4 coords = mul(_MainLightWorldToShadow[cascadeIndex], float4(wpos, 1.0));
ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
half4 shadowParams = GetMainLightShadowParams();
#if UNITY_VERSION >= 202220
float shadows = SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_LinearClampCompare), coords, shadowSamplingData, shadowParams, false).r;
#else
float shadows = SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), coords, shadowSamplingData, shadowParams, false).r;
#endif
atten = inside ? shadows : 1.0f;
// if(shadows > 0.0f)
// atten = 1.0f;
return atten;
}
#if !SHADER_API_GLES3
float3 PointLights(float3 pos)
{
float3 color = 0;
for (int i = 0; i < _PointLightsCount; i++)
{
float3 posToLight = _PointLights[i].pos - pos;
float distNorm = dot(posToLight, posToLight) * _PointLights[i].range;
float att = Attenuation(distNorm);
//#if ANISOTROPY
float3 cameraToPos = normalize(pos - _WorldSpaceCameraPos.xyz);
float costheta = dot(cameraToPos, normalize(posToLight));
att *= anisotropyPointSpot(costheta);
//#endif
color += _PointLights[i].color * att;
}
return color;
}
float3 SpotLights(float3 pos)
{
float3 color = 0;
for (int i = 0; i < _SpotLightsCount; i++)
{
float3 posToLight = _SpotLights[i].pos - pos;
float distNorm = dot(posToLight, posToLight) * _SpotLights[i].range;
float att = Attenuation(distNorm);
half3 lightVector = normalize(pos - _SpotLights[i].pos);
half cosAngle = dot(_SpotLights[i].lightDirection.xyz, lightVector);
half angleAttenuation = 1;
angleAttenuation = smoothstep(_SpotLights[i].lightCosHalfAngle, lerp(1, _SpotLights[i].lightCosHalfAngle, 0.8f), cosAngle);
angleAttenuation = pow(angleAttenuation, 2.0f);
att *= angleAttenuation;
#if ANISOTROPY
float3 cameraToPos = normalize(pos - _CameraPos.xyz);
float costheta = dot(cameraToPos, normalize(posToLight));
att *= anisotropyPointSpot(costheta);
#endif
color += _SpotLights[i].color * att;
}
return color;
}
#endif
//-----------------------------------------------------------------------------------------
// GetDensity
//-----------------------------------------------------------------------------------------
float GetDensity(float3 wpos, inout float density, float depth, float3 rayDir)
{
density = 1.0f;
// #ifdef NOISE
// float4 noise = tex3D(_NoiseTexture, frac(wpos * _NoiseData.x + float3(_Time.y * _WindDirection.x, 0, _Time.y * _WindDirection.y)));
// float noiseFbm = (noise.g * 0.625) + (noise.b * 0.25) + (noise.a * 0.125);
// noiseFbm = saturate(noiseFbm - _NoiseData.y);
// density *= saturate(noiseFbm);
// #endif
return density;
}
float2 squareUV(float2 uv)
{
float width = _ScreenParams.x;
float height =_ScreenParams.y;
float scale = 1000;
float x = uv.x * width;
float y = uv.y * height;
return float2 (x/scale, y/scale);
}
float4 RayMarch(float2 uv,float2 screenPos, float3 rayStart, float3 rayDir, float rayLength, float rayLengthLights, float linearDepth)
{
if (rayLength <= 0.01 || !all(isfinite(rayDir)))
return float4(0, 0, 0, 0);
float2 interleavedPos = fmod(floor(saturate(screenPos.xy)), 8.0);
interleavedPos = clamp(interleavedPos, 0.0, 7.999);
#if UNITY_SINGLE_PASS_STEREO
float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex];
interleavedPos = (interleavedPos - scaleOffset.zw) / scaleOffset.xy;
#endif
float4 ditherUV = saturate(float4(interleavedPos / 8.0 + float2(0.5 / 8.0, 0.5 / 8.0),0,0));
float offset = tex2Dlod(_DitherTexture, ditherUV).w; //+ _Randomness.xy
int stepCount = _Steps;
float stepSize = rayLength / stepCount;
float3 step = rayDir * stepSize;
float stepSizeLights = rayLengthLights / stepCount;
float3 stepLights = rayDir * stepSizeLights;
float3 currentPositionDithered = rayStart + step * offset;
float3 currentPositionLightsDithered = rayStart + stepLights * offset;
float3 currentPosition = rayStart + step;
float4 color = float4(0.0,0.0,0.0,0);
float cosAngle;
float extinction = 0;
float transmitance = 0;
float ambient = 0;
cosAngle = dot(_DirLightDir.xyz, -rayDir);
float ani = anisotropy(cosAngle);
float4 lightsColor = float4(0,0,0,0);
[loop]
for (int i = 0; i < stepCount; i++)
{
float density = GetDensity(currentPosition, density, linearDepth, rayDir);
float atten = DirectionalLight(currentPositionDithered) * 0.1;
//Cloud Shadows
//float cloudShadows = UNITY_SAMPLE_SCREENSPACE_TEXTURE(_CloudsTex,uv).b;
//atten *= (1-cloudShadows);
float scattering = _VolumetricLight.x * density;
extinction += _VolumetricLight.y * density;
transmitance += atten * scattering * exp(-extinction);
#if !SHADER_API_GLES3
lightsColor.rgb += PointLights(currentPositionLightsDithered) * stepSizeLights * density;
lightsColor.rgb += SpotLights(currentPositionLightsDithered) * stepSizeLights * density;
#endif
currentPosition += step;
currentPositionDithered += step;
currentPositionLightsDithered += stepLights;
}
//color.rgb = _DirLightColor.rgb * transmitance * ani;
color.a = transmitance * ani;
color.rgb += lightsColor.rgb * 0.1;
color = max(0, color);
return color;
}
float4 frag (v2f i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float2 uv = i.uv.xy;
float depth = SAMPLE_TEXTURE2D_X(_CameraDepthTexture, sampler_CameraDepthTexture, UnityStereoTransformScreenSpaceTex(uv)).r;
float linearDepth = Linear01Depth(depth,_ZBufferParams);
float4x4 proj, eyeToWorld;
if (unity_StereoEyeIndex == 0)
{
proj = _LeftViewFromScreen;
eyeToWorld = _LeftWorldFromView;
}
else
{
proj = _RightViewFromScreen;
eyeToWorld = _RightWorldFromView;
}
//bit of matrix math to take the screen space coord (u,v,depth) and transform to world space
float2 uvClip = i.uv * 2.0 - 1.0;
float clipDepth = depth; // Fix for OpenGl Core thanks to Lars Bertram
clipDepth = (UNITY_NEAR_CLIP_VALUE < 0) ? clipDepth * 2 - 1 : clipDepth;
float4 clipPos = float4(uvClip, clipDepth, 1.0);
float4 viewPos = mul(proj, clipPos); // inverse projection by clip position
viewPos /= viewPos.w; // perspective division
float3 wpos = mul(eyeToWorld, viewPos).xyz;
float3 rayStart = _WorldSpaceCameraPos;
float3 rayDir = wpos - _WorldSpaceCameraPos;
//rayDir *= linearDepth;
float rayLength = length(rayDir);
rayDir /= rayLength;
float rayLengthLights = min(rayLength, _MaxRayLengthLights);
rayLength = min(rayLength, _MaxRayLength);
float4 color = RayMarch(uv, i.position.xy, rayStart, rayDir, rayLength, rayLengthLights, linearDepth);
return color;
}
#else
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = v.vertex;
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float4 frag (v2f i) : SV_Target
{
float4 col = tex2D(_MainTex, i.uv);
// just invert the colors
col.rgb = 1 - col.rgb;
return col;
}
#endif
ENDHLSL
}
}
}