Files
UnrealEngine/Engine/Shaders/Private/VisualizeVolumetricLightmap.usf
2025-05-18 13:04:45 +08:00

119 lines
4.9 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Common.ush"
#include "SHCommon.ush"
#include "VolumetricLightmapShared.ush"
#include "DeferredShadingCommon.ush"
#ifndef QUADS_PER_INSTANCE
#define QUADS_PER_INSTANCE 0
#endif
struct FVisualizeVolumetricLightmapVSToPS
{
nointerpolation float3 BrickUVs : TEXCOORD0;
nointerpolation float FadeToAmbient : TEXCOORD1;
nointerpolation float4 CellSphere : TEXCOORD2;
float3 VertexPosition : TEXCOORD3;
};
float VisualizationRadiusScale;
float VisualizationMinScreenFraction;
void VisualizeVolumetricLightmapVS(
uint VertexId : SV_VertexID,
uint InstanceId : SV_InstanceID,
out FVisualizeVolumetricLightmapVSToPS Output,
out float4 OutPosition : SV_POSITION
)
{
uint EffectiveInstanceId = InstanceId * QUADS_PER_INSTANCE + VertexId / 4;
uint3 NumHighestDensityCells = View.VolumetricLightmapIndirectionTextureSize * View.VolumetricLightmapBrickSize;
uint3 CellVector = uint3(
EffectiveInstanceId % NumHighestDensityCells.x,
(EffectiveInstanceId / NumHighestDensityCells.x) % NumHighestDensityCells.y,
EffectiveInstanceId / (NumHighestDensityCells.x * NumHighestDensityCells.y));
float3 IndirectionTextureTexelCoordinate = CellVector / View.VolumetricLightmapBrickSize;
float4 BrickOffsetAndSize = View.VolumetricLightmapIndirectionTexture.Load(int4(IndirectionTextureTexelCoordinate, 0));
float PaddedBrickSize = View.VolumetricLightmapBrickSize + 1;
float3 LocalCellPosition = frac(IndirectionTextureTexelCoordinate / BrickOffsetAndSize.w) * View.VolumetricLightmapBrickSize;
Output.BrickUVs = (BrickOffsetAndSize.xyz * PaddedBrickSize + LocalCellPosition + .5f) * View.VolumetricLightmapBrickTexelSize;
float3 GridLocalCellPosition = round(LocalCellPosition);
bool bValidCell = all(abs(LocalCellPosition - GridLocalCellPosition) < .01f);
Output.CellSphere.xyz = (CellVector / (float3)NumHighestDensityCells - View.VolumetricLightmapWorldToUVAdd) / View.VolumetricLightmapWorldToUVScale;
float DetailVoxelWorldSize = 1.0f / ((float)View.VolumetricLightmapIndirectionTextureSize.x * View.VolumetricLightmapWorldToUVScale.x);
// Set visualization sphere radius as a fraction of the corresponding brick's world space size
Output.CellSphere.w = BrickOffsetAndSize.w * DetailVoxelWorldSize * VisualizationRadiusScale;
{
float DistanceToCamera = length(Output.CellSphere.xyz - DFHackToFloat(PrimaryView.WorldViewOrigin));
float SizeOnScreen = Output.CellSphere.w * View.ViewToClip[0][0] / DistanceToCamera;
Output.FadeToAmbient = saturate(SizeOnScreen * 100 - .01f);
// Maintain a minimum size on screen to reduce aliasing
SizeOnScreen = max(SizeOnScreen, VisualizationMinScreenFraction * sqrt(BrickOffsetAndSize.w));
Output.CellSphere.w = SizeOnScreen * DistanceToCamera / View.ViewToClip[0][0];
}
float2 TexCoord = float2(
((VertexId >> 0) & 1) ? 1.0f : -1.0f,
((VertexId >> 1) & 1) ? 1.0f : -1.0f);
float2 RescaledTexCoord = TexCoord * Output.CellSphere.w * sqrt(2.0);
Output.VertexPosition = Output.CellSphere.xyz + RescaledTexCoord.x * View.ViewRight + RescaledTexCoord.y * View.ViewUp;
OutPosition = mul(float4(Output.VertexPosition, 1), DFHackToFloat(PrimaryView.WorldToClip));
if (!bValidCell)
{
// This cell is not resident, emit a degenerate triangle
OutPosition = 0;
}
}
#define WRITE_TO_SHADING_MODEL (FEATURE_LEVEL >= FEATURE_LEVEL_SM4 && !FORWARD_SHADING)
float3 DiffuseColor;
void VisualizeVolumetricLightmapPS(
FVisualizeVolumetricLightmapVSToPS Input,
out float4 OutColor : SV_Target0
#if WRITE_TO_SHADING_MODEL
,out float4 OutGBufferB : SV_Target1
#endif
)
{
float3 RayDirection = Input.VertexPosition - DFHackToFloat(PrimaryView.WorldViewOrigin);
float2 SphereIntersections = RayIntersectSphere(DFHackToFloat(PrimaryView.WorldViewOrigin), RayDirection, Input.CellSphere);
float3 IntersectionPosition = DFHackToFloat(PrimaryView.WorldViewOrigin) + SphereIntersections.x * RayDirection;
clip(SphereIntersections.x);
FThreeBandSHVectorRGB IrradianceSH = GetVolumetricLightmapSH3(Input.BrickUVs);
float3 WorldNormal = normalize(IntersectionPosition - Input.CellSphere.xyz);
FThreeBandSHVector DiffuseTransferSH = CalcDiffuseTransferSH3(WorldNormal, 1);
float3 SphereLighting = max(float3(0,0,0), DotSH3(IrradianceSH, DiffuseTransferSH)) / PI;
float3 AmbientLighting = float3(IrradianceSH.R.V0.x, IrradianceSH.G.V0.x, IrradianceSH.B.V0.x) / PI;
// Lerp to ambient lighting in the distance to reduce aliasing
float3 FinalLighting = lerp(AmbientLighting, SphereLighting, Input.FadeToAmbient);
FinalLighting *= View.PreExposure;
// Use a diffuse color that matches the rest of the scene for LightingOnly and DetailLighting view modes
float3 EffectiveDiffuseColor = DiffuseColor * View.DiffuseOverrideParameter.w + View.DiffuseOverrideParameter.xyz;
OutColor = float4(EffectiveDiffuseColor * FinalLighting, 0);
//OutColor = float4(WorldNormal, 0);
#if WRITE_TO_SHADING_MODEL
// Shading model unlit
SetGBufferForUnlit(OutGBufferB);
#endif
}