https://zhuanlan.zhihu.com/p/76627240
指数密度高度雾总共分为4个板块,完成了其中的两个板块
https://blog.csdn.net/netyeaxi/article/details/87437880
控制台设置
SceneRendering.cpp
FSceneRenderer::PostVisibilityFrameSetup
InitFogConstants();
Common.ush
// also see ConvertToDeviceZ()
// @param DeviceZ value that is stored in the depth buffer (Z/W)
// @return SceneDepth (linear in world units, W)
float ConvertFromDeviceZ(float DeviceZ)
{
// Supports ortho and perspective, see CreateInvDeviceZToWorldZTransform()
return DeviceZ * View.InvDeviceZToWorldZTransform[0] + View.InvDeviceZToWorldZTransform[1] + 1.0f / (DeviceZ * View.InvDeviceZToWorldZTransform[2] - View.InvDeviceZToWorldZTransform[3]);
}
shader中关于View相关的代码在:SceneView.cpp
L2424
ViewUniformShaderParameters.ScreenToTranslatedWorld = FMatrix(
FPlane(1, 0, 0, 0),
FPlane(0, 1, 0, 0),
FPlane(0, 0, ProjectionMatrixUnadjustedForRHI.M[2][2], 1),
FPlane(0, 0, ProjectionMatrixUnadjustedForRHI.M[3][2], 0))
* InViewMatrices.GetInvTranslatedViewProjectionMatrix();
L2251
// to bring NDC (-1..1, 1..-1) into 0..1 UV for BufferSize textures
const FVector4 ScreenPositionScaleBias(
EffectiveViewRect.Width() * InvBufferSizeX / +2.0f,
EffectiveViewRect.Height() * InvBufferSizeY / (-2.0f * GProjectionSignY),
(EffectiveViewRect.Height() / 2.0f + EffectiveViewRect.Min.Y) * InvBufferSizeY,
(EffectiveViewRect.Width() / 2.0f + EffectiveViewRect.Min.X) * InvBufferSizeX);
RenderUtils.cpp
QuadVertex
virtual void InitRHI() override
{
// create a static vertex buffer
FRHIResourceCreateInfo CreateInfo;
VertexBufferRHI = RHICreateVertexBuffer(sizeof(FVector2D) * 4, BUF_Static, CreateInfo);
void* VoidPtr = RHILockVertexBuffer(VertexBufferRHI, 0, sizeof(FVector2D) * 4, RLM_WriteOnly);
static const FVector2D Vertices[4] =
{
FVector2D(-1,-1),
FVector2D(-1,+1),
FVector2D(+1,-1),
FVector2D(+1,+1),
};
FMemory::Memcpy(VoidPtr, Vertices, sizeof(FVector2D) * 4);
RHIUnlockVertexBuffer(VertexBufferRHI);
}
// FogStruct.ExponentialFogParameters: FogDensity * exp2(-FogHeightFalloff * (CameraWorldPosition.z - FogHeight)) in x, FogHeightFalloff in y, MaxWorldObserverHeight in z, StartDistance in w.
// FogStruct.ExponentialFogParameters2: FogDensitySecond * exp2(-FogHeightFalloffSecond * (CameraWorldPosition.z - FogHeightSecond)) in x, FogHeightFalloffSecond in y, FogDensitySecond in z, FogHeightSecond in w
// FogStruct.ExponentialFogParameters3: FogDensity in x, FogHeight in y, whether to use cubemap fog color in z, FogCutoffDistance in w.
//ExponentialFogParameters
y和雾高度衰减有关
z=65536+HeiFog的z
w=
y=雾高度
w=
w=1-雾最大不透明度
引擎版
复制版
shader
参数设置
// FogStruct.ExponentialFogParameters: FogDensity * exp2(-FogHeightFalloff * (CameraWorldPosition.z - FogHeight)) in x, FogHeightFalloff in y, MaxWorldObserverHeight in z, StartDistance in w.
// FogStruct.ExponentialFogParameters2: FogDensitySecond * exp2(-FogHeightFalloffSecond * (CameraWorldPosition.z - FogHeightSecond)) in x, FogHeightFalloffSecond in y, FogDensitySecond in z, FogHeightSecond in w
// FogStruct.ExponentialFogParameters3: FogDensity in x, FogHeight in y, whether to use cubemap fog color in z, FogCutoffDistance in w.
static const float3 MyFogColor = float3(0.528, 0.646, 1.0);
static const float FogHeightFalloff = 0.001;
//Why not 0 or 1 or 2 .when set FogHeightFalloff value to 2 in editor it set 0.002 actually??Why
//it becomes constance when value=0
static const float GlobalDensity = 0.0003;
//this value is used to control the global fog density
//using a special starting distance to limit the inscattering to the distance
static const float DirectionalInscatteringStartDistance=10312;
static const float3 DirectionalInscatteringColor = float3(0.0, 2.594,0.615);
static const float3 InscatterinLightDirection = float3(0.506, 0.863, 0.00);
static const float DirectionalInscatteringStrenthFactor = 8.0;
雾密度计算+积分计算
float CalculateLineIntegralShared(float RayDirectionZ)
{
//积分拟合函数
//RayDirectionZ 人眼与物体的相对高度
//雾效影响程度受到 物体高度的影响。越高的物体,到达人眼雾效消失的越严重,越低的物体,到达人眼以后,雾效会加强。
float Falloff = max(-127.0f, FogHeightFalloff * RayDirectionZ); // if it's lower than -127.0, then exp2() goes crazy in OpenGL's GLSL.
float LineIntegral = (1.0f - exp2(-Falloff)) / Falloff;
float LineIntegralTaylor = log(2.0) - (0.5 * Pow2(log(2.0))) * Falloff; // Taylor expansion around 0
//float FogDensity = GlobalDensity * exp2(-FogHeightFalloff * (CameraWorldPosition.z - FogHeight));
//we set fogheight to 0
//雾密度呈指数变化。
//摄像机与雾的相对高度越大,这个密度值越小,且最小为0;相对高度越小,雾密度越大,最高为正无穷。
//当摄像机的高度比雾高度小时,雾的密度始终大于1,且变化剧烈;反之,雾密度始终小于1, 且随着高度的增加,逐渐衰减为0
//GlobalDensity ,高度雾全局密度,通过这个参数来控制整体的密度,人工干预修正曲线
//FogHeightFalloff的引入,是为了缩小高度变化的程度,当衰减值为0时,变化程度缩小最大化,所有高度只有同一个密度值,当那个衰减值为2时,加强了高度对密度的影响程度。
float FogDensity = GlobalDensity * exp2(-FogHeightFalloff * (View.WorldCameraOrigin.z-0.0));
//abs(Falloff) > FLT_EPSILON2 avoid dvide zero
//return RayOriginTerms * (abs(Falloff) > FLT_EPSILON2 ? LineIntegral : LineIntegralTaylor);
//RayOriginTerms=FogDensity * exp2(-FogHeightFalloff * (CameraWorldPosition.z - FogHeight)) which is FogStruct.ExponentialFogParameters.x
return FogDensity * (abs(Falloff) > FLT_EPSILON2 ? LineIntegral : LineIntegralTaylor);
}
计算指数高度雾+DirectionalLightInscattering
half4 GetExponentialHeightFog(float3 WorldPositionRelativeToCamera, float ExcludeDistance)
{
float3 CameraToReceiver = WorldPositionRelativeToCamera;
//const float3 WorldObserverOrigin = View.WorldCameraOrigin.xyz;
float CameraToReceiverLengthSqr = dot(CameraToReceiver, CameraToReceiver);
float CameraToReceiverLengthInv = rsqrt(CameraToReceiverLengthSqr);
float CameraToReceiverLength = CameraToReceiverLengthSqr * CameraToReceiverLengthInv;
half3 CameraToReceiverNormalized = CameraToReceiver * CameraToReceiverLengthInv;
float RayLength = CameraToReceiverLength;
float RayDirectionZ = CameraToReceiver.z;
float ExponentialHeightLineIntegralShared = CalculateLineIntegralShared(RayDirectionZ);
//RayLength 加上距离的影响
float ExponentialHeightLineIntegral = ExponentialHeightLineIntegralShared * RayLength;
half MinFogOpacity = 0.0;
//设置最小不透明度为0.0 观察低处的影响
half ExpFogFactor = max(saturate(exp2(-ExponentialHeightLineIntegral)), 0.5);
//Shader type 2:DirectionalLightInscattering--------------------------------------------------------------
half3 DirectionalLightInscattering = DirectionalInscatteringColor * pow(saturate(dot(CameraToReceiverNormalized, InscatterinLightDirection)), DirectionalInscatteringStrenthFactor);
//距离影响因子
float DirExponentialHeightLineIntegral = ExponentialHeightLineIntegralShared * max(RayLength - DirectionalInscatteringStartDistance, 0.0f);
// Calculate the amount of light that made it through the fog using the transmission equation
half DirectionalInscatteringFogFactor = saturate(exp2(-DirExponentialHeightLineIntegral));
// Final inscattering from the light
half3 DirectionalInscattering = DirectionalLightInscattering * (1 - DirectionalInscatteringFogFactor);
//-----------------------------------------------------------------------------------------------------------
half3 FogColor = (MyFogColor.xyz) * (1 - ExpFogFactor) + DirectionalInscattering;
//return half4(0.0, 0.0, 0.0, 1.0);
return half4(FogColor, ExpFogFactor);
}
void MainPS(
in float2 UV: TEXCOORD0,
in float3 ScreenVector : TEXCOORD1,
in float4 Position : SV_POSITION,
out float4 OutColor : SV_Target0
)
{
float DeviceZ = Texture2DSampleLevel(SceneTexturesStruct.SceneDepthTexture, SceneTexturesStruct_SceneDepthTextureSampler, UV, 0).r;
// @param DeviceZ value that is stored in the depth buffer (Z/W)
// @return SceneDepth (linear in world units, W)
float SceneDepth = ConvertFromDeviceZ(DeviceZ); // Fetch the depth buffer Z / W value, solve for W
bool bIsRendered = (DeviceZ != 0.0);
float3 WorldPositionRelativeToCamera = ScreenVector.xyz * SceneDepth;//scale xyz ??
float4 HeightFogInscatteringAndOpacity = CalculateHeightFog(WorldPositionRelativeToCamera);
float LightShaftMask = Texture2DSample(OcclusionTexture, OcclusionSampler, UV).x;
HeightFogInscatteringAndOpacity.xyz *= LightShaftMask;
if (!bIsRendered)
{
HeightFogInscatteringAndOpacity.rgb = 0;
HeightFogInscatteringAndOpacity.a = 1;
}
OutColor = float4(HeightFogInscatteringAndOpacity.xyz, HeightFogInscatteringAndOpacity.w);
//recompileshaders changed
}