// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
AtmosphericFogPixelShader.usf: Scene atmospheric fogging pixel shader.
This code contains embedded portions of free sample source code from
www-evasion.imag.fr Membres/Eric.Bruneton/PrecomputedAtmosphericScattering2.zip, Author: Eric Bruneton,
08/16/2011, Copyright (c) 2008 INRIA, All Rights Reserved, which have been altered from their original version.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
=============================================================================*/
#include "Common.ush"
#include "SceneTexturesCommon.ush"
#include "SHCommon.ush"
#include "AtmosphereCommon.ush"
#ifndef ATMOSPHERIC_NO_LIGHT_SHAFT
#define ATMOSPHERIC_NO_LIGHT_SHAFT0
#endif
#if !ATMOSPHERIC_NO_LIGHT_SHAFT
/** Result of the previous pass, rgb contains bloom color and a contains an occlusion mask. */
Texture2D OcclusionTexture;
SamplerState OcclusionTextureSampler;
static const float OcclusionMaskDarkness = 0.0;
#endif
void VSMain(
in float2 InPosition : ATTRIBUTE0,
out float2 OutTexCoord : TEXCOORD0,
out float4 OutScreenVector : TEXCOORD1,
out float4 OutPosition : SV_POSITION
)
{
// screenspace position from vb
OutPosition = float4(InPosition,0,1);
// texture coord from vb
OutTexCoord = InPosition * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
// deproject to world space
OutScreenVector = mul(float4(InPosition,1,0), View.ScreenToTranslatedWorld);
}
/** inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0) */
float3 GetInscatterColor2(float FogDepth, float3 X, float T, float3 V, float3 S, float Radius, float Mu, out float3 Attenuation, bool bIsSceneGeometry)
{
float3 Result = float3(0.f, 0.f, 0.f); // X in space and ray looking in space, initialize
Attenuation = float3(1.f, 1.f, 1.f);
float RadiusRadius = Radius;
float D = -Radius * Mu - sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusAtmosphere * RadiusAtmosphere);
if (D > 0.0)
{
// if X in space and ray intersects atmosphere
// move X to nearest intersection of ray with top atmosphere boundary
X += D * V;
T -= D;
Mu = (Radius * Mu + D) / RadiusAtmosphere;
Radius = RadiusAtmosphere;
}
float Epsilon = 0.005f;
float MieCoff=0.1;
if (Radius < RadiusGround + HeightOffset + Epsilon)
{
float Diff = (RadiusGround + HeightOffset + Epsilon) - Radius;
X -= Diff * V;
T -= Diff;
Radius = RadiusGround + HeightOffset + Epsilon;
Mu = dot(X, V) / Radius;
}
if (Radius <= RadiusAtmosphere && FogDepth > 0.f)
{
float3 X0 = X + T * V;
float R0 = length(X0);
// if ray intersects atmosphere
float Nu = dot(V, S);
float MuS = dot(X, S) / Radius;
float MuHorizon = -sqrt(1.0 - (RadiusGround / Radius) * (RadiusGround / Radius));
if (bIsSceneGeometry)
{
Mu = max(Mu, MuHorizon + Epsilon + 0.15);
}
else
{
Mu = max(Mu, MuHorizon + Epsilon);
}
float MuOriginal = Mu;
float BlendRatio = 0.0f;
if (bIsSceneGeometry)
{
BlendRatio = saturate(exp(-V.z) - 0.5);
if (BlendRatio < 1.f)
{
V.z = max(V.z, 0.15);
V = normalize(V);
float3 X1 = X + T * V;
float R1 = length(X1);
Mu = dot(X1, V) / R1;
}
}
float PhaseR = PhaseFunctionR(Nu);
float PhaseM = PhaseFunctionM(Nu);
float4 Inscatter = max(Texture4DSample(AtmosphereInscatterTexture, AtmosphereInscatterTextureSampler, Radius, Mu, MuS, Nu), 0);
if(D > 0.0 && MuS<0){
if(Radius >= RadiusAtmosphere){
//Inscatter = max(Inscatter, D * 0.1);//哈哈好亮。。
//Inscatter = max(Inscatter, RadiusRadius>RadiusAtmosphere*1.5?0.1:0.2);
Inscatter = max(Inscatter, lerp(0.2, 0.1, (RadiusRadius-RadiusAtmosphere)/RadiusAtmosphere));
//MieCoff=0;
}
//if(MuS<-0.85)
MieCoff=lerp(0.1, 0, -MuS);
}
#if ATMOSPHERIC_TEXTURE_SAMPLE_FIX
// avoids imprecision problems in Mie scattering when sun is below horizon
//Inscatter.w *= smoothstep(0.00, 0.02, MuS);
#endif
Result = max(Inscatter.rgb * PhaseR + MieCoff*GetMie(Inscatter) * PhaseM, 0.0);//max(Inscatter.rgb * PhaseR + GetMie(Inscatter) * PhaseM, 0.0);
//Result = float3(0,0,0);
}
return Result;
}
void AtmosphericPixelMain(
float2 TexCoord : TEXCOORD0,
float4 ScreenVector : TEXCOORD1,
out float4 OutColor : SV_Target0)
{
float Scale = 0.00001f * View.AtmosphericFogDistanceScale;
View.WorldCameraOrigin.z = (View.WorldCameraOrigin.z - View.AtmosphericFogGroundOffset) * View.AtmosphericFogAltitudeScale;
View.WorldCameraOrigin *= Scale;
//View.WorldCameraOrigin.z += RadiusGround + HeightOffset;
float Radius = length(View.WorldCameraOrigin);
float3 V = normalize(ScreenVector.xyz);
float Mu = dot(View.WorldCameraOrigin, V) / Radius;
float T = -Radius * Mu - sqrt(Radius * Radius * (Mu * Mu - 1.0) + RadiusGround * RadiusGround);
float DepthThreshold = 100.f * View.AtmosphericFogDistanceScale; // 100km limit
float SceneDepth=CalcSceneDepth(TexCoord);
//SceneDepth *= Scale;
float FogDepth = max(0.f, SceneDepth - View.AtmosphericFogStartDistance);
float ShadowFactor = 1.f; // shadow approximation
float DistanceRatio = min(FogDepth * 0.1f / View.AtmosphericFogStartDistance, 1.f);
bool bIsSceneGeometry = (SceneDepth < DepthThreshold); // Assume as scene geometry
if (bIsSceneGeometry)
{
ShadowFactor = DistanceRatio * View.AtmosphericFogPower;
T = max(SceneDepth + View.AtmosphericFogDistanceOffset, 1.f);
}
float3 Attenuation;
float3 InscatterColor = GetInscatterColor2(FogDepth, View.WorldCameraOrigin, T, V, View.AtmosphericFogSunDirection, Radius, Mu, Attenuation, bIsSceneGeometry); //S[L]-T(ViewPosition,xs)S[l]|xs
float3 SceneColor = float3(0, 0, 0);
#if BASEPASS_ATMOSPHERIC_FOG // Transluceny rendering just follows normal render flag
float3 GroundColor = 0.f;
BRANCH
if ((View.AtmosphericFogRenderMask & RENDERFLAG_DISABLE_GROUND_SCATTERING) == 0)
{
GroundColor = GetGroundColor(float4(SceneColor.xyz, 1.f), View.WorldCameraOrigin, T, V, View.AtmosphericFogSunDirection, Radius, Attenuation, bIsSceneGeometry); //R[L0]+R[L*]
}
#else
#if MATERIAL_ATMOSPHERIC_FOG || ATMOSPHERIC_NO_GROUND_SCATTERING // Material doesn't need this ground scattering for now
float3 GroundColor = 0.f;
#else
float3 GroundColor = GetGroundColor(float4(SceneColor.xyz, 1.f), View.WorldCameraOrigin, T, V, View.AtmosphericFogSunDirection, Radius, Attenuation, bIsSceneGeometry); //R[L0]+R[L*]
#endif
#endif
#if BASEPASS_ATMOSPHERIC_FOG // Transluceny rendering just follows normal render flag
float3 Sun = 0.f;
BRANCH
if ((View.AtmosphericFogRenderMask & RENDERFLAG_DISABLE_SUN_DISK) == 0)
{
Sun = GetSunColor(View.WorldCameraOrigin, T, V, View.AtmosphericFogSunDirection, Radius, Mu); //L0
}
#else
#if MATERIAL_ATMOSPHERIC_FOG || ATMOSPHERIC_NO_SUN_DISK // Material doesn't need to render the sun disk
float3 Sun = 0.f;
#else
float3 Sun = GetSunColor(View.WorldCameraOrigin, T, V, View.AtmosphericFogSunDirection, Radius, Mu); //L0
#endif
#endif
OutColor = GetAtmosphericFog(View.WorldCameraOrigin, ScreenVector.xyz, CalcSceneDepth(TexCoord), float3(0, 0, 0));
#if !ATMOSPHERIC_NO_LIGHT_SHAFT
float LightShaftMask = Texture2DSample(OcclusionTexture, OcclusionTextureSampler, TexCoord).x;
OutColor.rgb = OutColor.rgb * LightShaftMask;
//OutColor.rgb = float4(1,1,1,1);
#endif
#if USE_PREEXPOSURE
OutColor.rgb *= View.PreExposure;
#endif
float3 OriginalColor = Sun+InscatterColor+GroundColor;
OriginalColor = OriginalColor * max(1, min(lerp(0.2, 12, Radius/RadiusAtmosphere-1),11));
//OriginalColor = View.AtmosphericFogSunPower * ShadowFactor * View.AtmosphericFogSunColor.rgb * OriginalColor;
OutColor = float4(OriginalColor, 1);
}
虚幻4里面这个shader单个修改的话ctrl+shift+.编译起来超级快。随便玩好了。
大气雾应该就是画在整屏上的,但又不完全是,因为就算在shader中全返回纯色,也不会让屏幕变成纯色,而是场景里有东西的地方覆盖半透明的雾,类似蒙了一层纱一样。
2019年06月27日 01点06分
4