You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
361 lines
11 KiB
Plaintext
361 lines
11 KiB
Plaintext
|
4 years ago
|
Shader "Enviro/Pro/EnviroFogHDRP"
|
||
|
|
{
|
||
|
|
HLSLINCLUDE
|
||
|
|
|
||
|
|
#pragma target 4.5
|
||
|
|
#pragma only_renderers d3d11 ps4 xboxone vulkan metal switch
|
||
|
|
|
||
|
|
#pragma multi_compile __ ENVIROHDRP
|
||
|
|
#if defined (ENVIROHDRP)
|
||
|
|
|
||
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
||
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
||
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
||
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
|
||
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"
|
||
|
|
#include "../../../../Core/Resources/Shaders/Core/EnviroFogCore.hlsl"
|
||
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/AtmosphericScattering/AtmosphericScattering.hlsl"
|
||
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Sky/SkyUtils.hlsl"
|
||
|
|
|
||
|
|
struct Attributes
|
||
|
|
{
|
||
|
|
uint vertexID : SV_VertexID;
|
||
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||
|
|
};
|
||
|
|
|
||
|
|
struct Varyings
|
||
|
|
{
|
||
|
|
float4 positionCS : SV_POSITION;
|
||
|
|
float2 texcoord : TEXCOORD0;
|
||
|
|
float3 sky : TEXCOORD1;
|
||
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
||
|
|
};
|
||
|
|
|
||
|
|
Varyings Vert(Attributes input)
|
||
|
|
{
|
||
|
|
Varyings output;
|
||
|
|
UNITY_SETUP_INSTANCE_ID(input);
|
||
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
||
|
|
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
|
||
|
|
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
|
||
|
|
output.sky.x = saturate(_SunDir.y + 0.25);
|
||
|
|
output.sky.y = saturate(clamp(1.0 - _SunDir.y, 0.0, 0.5));
|
||
|
|
return output;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEXTURE2D_X(_MainTex);
|
||
|
|
TEXTURE3D(_FogNoiseTexture);
|
||
|
|
float4x4 _LeftWorldFromView;
|
||
|
|
float4x4 _RightWorldFromView;
|
||
|
|
float4x4 _LeftViewFromScreen;
|
||
|
|
float4x4 _RightViewFromScreen;
|
||
|
|
float _EnviroSkyIntensity;
|
||
|
|
float _DitheringIntensity;
|
||
|
|
|
||
|
|
|
||
|
|
float Remap(float org_val, float org_min, float org_max, float new_min, float new_max)
|
||
|
|
{
|
||
|
|
return new_min + saturate(((org_val - org_min) / (org_max - org_min))*(new_max - new_min));
|
||
|
|
}
|
||
|
|
|
||
|
|
float3 ScreenSpaceDither(float2 vScreenPos, float3 clr)
|
||
|
|
{
|
||
|
|
float d = dot(float2(131.0, 312.0), vScreenPos.xy + _Time.y);
|
||
|
|
float3 vDither = float3(d, d, d);
|
||
|
|
vDither.rgb = frac(vDither.rgb / float3(103.0, 71.0, 97.0)) - float3(0.5, 0.5, 0.5);
|
||
|
|
return (vDither.rgb / 15.0) * _DitheringIntensity * Luminance(clr);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Linear height fog function
|
||
|
|
float ComputeHalfSpaceWithNoise(float3 wsDir)
|
||
|
|
{
|
||
|
|
float3 wpos = _WorldSpaceCameraPos + wsDir;
|
||
|
|
float FH = _HeightParams.x;
|
||
|
|
float3 C = _WorldSpaceCameraPos;
|
||
|
|
float3 V = wsDir;
|
||
|
|
float3 P = wpos;
|
||
|
|
float3 aV = (_HeightParams.w * _EnviroSkyFog.w) * V;
|
||
|
|
float noise = LOAD_TEXTURE3D(_FogNoiseTexture, frac(wpos * _FogNoiseData.x + float3(_Time.y * _FogNoiseVelocity.x, 0, _Time.y * _FogNoiseVelocity.y)));
|
||
|
|
noise = saturate(noise - _FogNoiseData.z) * _FogNoiseData.y;
|
||
|
|
aV *= noise;
|
||
|
|
float FdotC = _HeightParams.y;
|
||
|
|
float k = _HeightParams.z;
|
||
|
|
float FdotP = P.y - FH;
|
||
|
|
float FdotV = wsDir.y;
|
||
|
|
float c1 = k * (FdotP + FdotC);
|
||
|
|
float c2 = (1 - 2 * k) * FdotP;
|
||
|
|
float g = min(c2, 0.0);
|
||
|
|
g = -length(aV) * (c1 - g * g / abs(FdotV + 1.0e-5f));
|
||
|
|
return g;
|
||
|
|
}
|
||
|
|
|
||
|
|
float4 FullFogPass(Varyings input) : SV_Target
|
||
|
|
{
|
||
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
||
|
|
|
||
|
|
uint2 positionSS = input.texcoord * _ScreenSize.xy;
|
||
|
|
float rawDepth = LoadCameraDepth(input.positionCS.xy);
|
||
|
|
float dpth = Linear01Depth(rawDepth, _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 = input.texcoord * 2.0 - 1.0;
|
||
|
|
float clipDepth = rawDepth; // 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
|
||
|
|
float4 wsPos = float4(mul(eyeToWorld, viewPos).xyz, 1);
|
||
|
|
float4 wsDir = wsPos - float4(_WorldSpaceCameraPos, 0);
|
||
|
|
float3 viewDir = normalize(wsDir);
|
||
|
|
|
||
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
half fogFac = 0;
|
||
|
|
float4 finalFog = 0;
|
||
|
|
float g = _DistanceParams.x;
|
||
|
|
half gHeight = 0;
|
||
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
//Scene
|
||
|
|
if (dpth < 0.99999)
|
||
|
|
{
|
||
|
|
// Calculate Distance Fog
|
||
|
|
if (_EnviroParams.y > 0)
|
||
|
|
{
|
||
|
|
g += ComputeDistance(wsDir, dpth);
|
||
|
|
g *= _distanceFogIntensity;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_EnviroParams.z > 0)
|
||
|
|
{
|
||
|
|
gHeight = ComputeHalfSpaceWithNoise(wsDir)* (1 - dpth);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add Height Fog
|
||
|
|
g += gHeight;
|
||
|
|
|
||
|
|
// Compute fog amount
|
||
|
|
fogFac = ComputeFogFactorEnviro(max(0.0, g));
|
||
|
|
fogFac = lerp(_maximumFogDensity, 1.0f, fogFac);
|
||
|
|
|
||
|
|
finalFog = ComputeScatteringScene(viewDir, input.sky.xy) * _EnviroSkyIntensity * GetCurrentExposureMultiplier();
|
||
|
|
}
|
||
|
|
else //SKY
|
||
|
|
{
|
||
|
|
if (_EnviroParams.z > 0 && _SceneFogMode.w == 1)
|
||
|
|
{
|
||
|
|
gHeight = ComputeHalfSpace(wsDir);
|
||
|
|
}
|
||
|
|
|
||
|
|
half fogFacSky = ComputeFogFactorEnviro(max(0.0, gHeight));
|
||
|
|
float f = saturate(_EnviroSkyFog.x * (viewDir.y + _EnviroSkyFog.z));
|
||
|
|
f = pow(f, _EnviroSkyFog.y);
|
||
|
|
|
||
|
|
fogFac = (clamp(f, 0, 1));
|
||
|
|
|
||
|
|
if (fogFac > fogFacSky)
|
||
|
|
fogFac = fogFacSky;
|
||
|
|
|
||
|
|
|
||
|
|
float skyLerp = Remap(_WorldSpaceCameraPos.y, 0, 11000, 0, 1);
|
||
|
|
fogFac = lerp(fogFac, 1, skyLerp);
|
||
|
|
|
||
|
|
float4 skyFog = ComputeScatteringScene(viewDir, input.sky.xy);
|
||
|
|
finalFog = skyFog * _EnviroSkyIntensity * GetCurrentExposureMultiplier();
|
||
|
|
}
|
||
|
|
|
||
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
/// Composing
|
||
|
|
float4 source = LOAD_TEXTURE2D_X(_MainTex, positionSS);
|
||
|
|
|
||
|
|
//HDRP Fog
|
||
|
|
float3 V = GetSkyViewDirWS(positionSS);
|
||
|
|
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, rawDepth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V);
|
||
|
|
posInput.positionWS = GetCurrentViewPosition() - V * _MaxFogDistance;
|
||
|
|
float3 color, opacity;
|
||
|
|
EvaluateAtmosphericScattering(posInput, V, color, opacity);
|
||
|
|
finalFog.rgb = color + (1 - opacity) * finalFog.rgb;
|
||
|
|
//
|
||
|
|
|
||
|
|
//Dithering
|
||
|
|
finalFog.rgb = finalFog.rgb + ScreenSpaceDither(input.positionCS.xy, finalFog.rgb);
|
||
|
|
|
||
|
|
float4 final = lerp(finalFog, source, fogFac);
|
||
|
|
|
||
|
|
return final;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
float4 SkyOnlyPass(Varyings input) : SV_Target
|
||
|
|
{
|
||
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
||
|
|
|
||
|
|
uint2 positionSS = input.texcoord * _ScreenSize.xy;
|
||
|
|
float rawDepth = LoadCameraDepth(input.positionCS.xy);
|
||
|
|
float dpth = Linear01Depth(rawDepth, _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 = input.texcoord * 2.0 - 1.0;
|
||
|
|
float clipDepth = rawDepth; // 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
|
||
|
|
float4 wsPos = float4(mul(eyeToWorld, viewPos).xyz, 1);
|
||
|
|
float4 wsDir = wsPos - float4(_WorldSpaceCameraPos, 0);
|
||
|
|
float3 viewDir = normalize(wsDir);
|
||
|
|
|
||
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
half fogFac = 1;
|
||
|
|
float4 finalFog = 0;
|
||
|
|
float g = _DistanceParams.x;
|
||
|
|
half gHeight = 0;
|
||
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
//Scene
|
||
|
|
if (dpth > 0.99999)
|
||
|
|
{
|
||
|
|
if (_EnviroParams.z > 0 && _SceneFogMode.w == 1)
|
||
|
|
{
|
||
|
|
gHeight = ComputeHalfSpace(wsDir);
|
||
|
|
}
|
||
|
|
|
||
|
|
half fogFacSky = ComputeFogFactorEnviro(max(0.0, gHeight));
|
||
|
|
float f = saturate(_EnviroSkyFog.x * (viewDir.y + _EnviroSkyFog.z));
|
||
|
|
f = pow(f, _EnviroSkyFog.y);
|
||
|
|
|
||
|
|
fogFac = (clamp(f, 0, 1));
|
||
|
|
|
||
|
|
if (fogFac > fogFacSky)
|
||
|
|
fogFac = fogFacSky;
|
||
|
|
|
||
|
|
|
||
|
|
float skyLerp = Remap(_WorldSpaceCameraPos.y, 0, 11000, 0, 1);
|
||
|
|
fogFac = lerp(fogFac, 1, skyLerp);
|
||
|
|
|
||
|
|
float4 skyFog = ComputeScatteringScene(viewDir, input.sky.xy);
|
||
|
|
finalFog = skyFog * _EnviroSkyIntensity * GetCurrentExposureMultiplier();
|
||
|
|
|
||
|
|
//HDRP Fog
|
||
|
|
float3 V = GetSkyViewDirWS(positionSS);
|
||
|
|
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, rawDepth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V);
|
||
|
|
posInput.positionWS = GetCurrentViewPosition() - V * _MaxFogDistance;
|
||
|
|
float3 color, opacity;
|
||
|
|
EvaluateAtmosphericScattering(posInput, V, color, opacity);
|
||
|
|
finalFog.rgb = color + (1 - opacity) * finalFog.rgb;
|
||
|
|
//
|
||
|
|
}
|
||
|
|
|
||
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
|
||
|
|
//Dithering
|
||
|
|
finalFog.rgb = finalFog.rgb + ScreenSpaceDither(input.positionCS.xy, finalFog.rgb);
|
||
|
|
|
||
|
|
/// Composing
|
||
|
|
float4 source = LOAD_TEXTURE2D_X(_MainTex, positionSS);
|
||
|
|
|
||
|
|
return lerp(finalFog, source, fogFac);
|
||
|
|
}
|
||
|
|
|
||
|
|
#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 FullFogPass (v2f i) : SV_Target
|
||
|
|
{
|
||
|
|
float4 col = tex2D(_MainTex, i.uv);
|
||
|
|
// just invert the colors
|
||
|
|
col.rgb = 1 - col.rgb;
|
||
|
|
return col;
|
||
|
|
}
|
||
|
|
|
||
|
|
float4 SkyOnlyPass (v2f i) : SV_Target
|
||
|
|
{
|
||
|
|
float4 col = tex2D(_MainTex, i.uv);
|
||
|
|
// just invert the colors
|
||
|
|
col.rgb = 1 - col.rgb;
|
||
|
|
return col;
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
ENDHLSL
|
||
|
|
|
||
|
|
SubShader
|
||
|
|
{
|
||
|
|
Tags{ "RenderPipeline" = "HDRenderPipeline" }
|
||
|
|
Pass
|
||
|
|
{
|
||
|
|
Name "EnviroFog Full Pass"
|
||
|
|
|
||
|
|
ZWrite Off
|
||
|
|
ZTest Always
|
||
|
|
Blend Off
|
||
|
|
Cull Off
|
||
|
|
|
||
|
|
HLSLPROGRAM
|
||
|
|
#pragma fragment FullFogPass
|
||
|
|
#pragma vertex Vert
|
||
|
|
ENDHLSL
|
||
|
|
}
|
||
|
|
|
||
|
|
Pass
|
||
|
|
{
|
||
|
|
Name "EnviroFog SkyOnly Pass"
|
||
|
|
|
||
|
|
ZWrite Off
|
||
|
|
ZTest Always
|
||
|
|
Blend Off
|
||
|
|
Cull Off
|
||
|
|
|
||
|
|
HLSLPROGRAM
|
||
|
|
#pragma fragment SkyOnlyPass
|
||
|
|
#pragma vertex Vert
|
||
|
|
ENDHLSL
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Fallback Off
|
||
|
|
}
|