Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/LightRendering.h
2025-05-18 13:04:45 +08:00

350 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LightRendering.h: Light rendering declarations.
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "RHI.h"
#include "RHIResourceUtils.h"
#include "RenderResource.h"
#include "UniformBuffer.h"
#include "ShaderParameters.h"
#include "ShaderParameterUtils.h"
#include "Shader.h"
#include "GlobalShader.h"
#include "SceneRendering.h"
#include "Containers/DynamicRHIResourceArray.h"
#include "LightSceneInfo.h"
/** Uniform buffer for rendering deferred lights. */
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FDeferredLightUniformStruct,)
SHADER_PARAMETER(FVector4f,ShadowMapChannelMask)
SHADER_PARAMETER(FVector2f,DistanceFadeMAD)
SHADER_PARAMETER(float, ContactShadowLength)
SHADER_PARAMETER(float, ContactShadowCastingIntensity)
SHADER_PARAMETER(float, ContactShadowNonCastingIntensity)
SHADER_PARAMETER(float, VolumetricScatteringIntensity)
SHADER_PARAMETER(uint32,ShadowedBits)
SHADER_PARAMETER(uint32,LightingChannelMask)
SHADER_PARAMETER_STRUCT_INCLUDE(FLightShaderParameters, LightParameters)
END_GLOBAL_SHADER_PARAMETER_STRUCT()
extern uint32 GetShadowQuality();
extern float GetLightFadeFactor(const FSceneView& View, const FLightSceneProxy* Proxy);
extern FDeferredLightUniformStruct GetDeferredLightParameters(const FSceneView& View, const FLightSceneInfo& LightSceneInfo, bool bUseLightFunctionAtlas=false, uint32 LightFlags=0);
inline void SetDeferredLightParameters(
FRHIBatchedShaderParameters& BatchedParameters,
const TShaderUniformBufferParameter<FDeferredLightUniformStruct>& DeferredLightUniformBufferParameter,
const FLightSceneInfo* LightSceneInfo,
const FSceneView& View,
bool bUseLightFunctionAtlas)
{
SetUniformBufferParameterImmediate(BatchedParameters, DeferredLightUniformBufferParameter, GetDeferredLightParameters(View, *LightSceneInfo, bUseLightFunctionAtlas));
}
extern FDeferredLightUniformStruct GetSimpleDeferredLightParameters(
const FSceneView& View,
const FSimpleLightEntry& SimpleLight,
const FSimpleLightPerViewEntry &SimpleLightPerViewData);
inline void SetSimpleDeferredLightParameters(
FRHIBatchedShaderParameters& BatchedParameters,
const TShaderUniformBufferParameter<FDeferredLightUniformStruct>& DeferredLightUniformBufferParameter,
const FSimpleLightEntry& SimpleLight,
const FSimpleLightPerViewEntry &SimpleLightPerViewData,
const FSceneView& View)
{
FDeferredLightUniformStruct DeferredLightUniformsValue = GetSimpleDeferredLightParameters(View, SimpleLight, SimpleLightPerViewData);
SetUniformBufferParameterImmediate(BatchedParameters, DeferredLightUniformBufferParameter, DeferredLightUniformsValue);
}
/** Shader parameters needed to render a light function. */
class FLightFunctionSharedParameters
{
DECLARE_TYPE_LAYOUT(FLightFunctionSharedParameters, NonVirtual);
public:
void Bind(const FShaderParameterMap& ParameterMap);
static FVector4f GetLightFunctionSharedParameters(const FLightSceneInfo* LightSceneInfo, float ShadowFadeFraction);
void Set(FRHIBatchedShaderParameters& BatchedParameters, const FLightSceneInfo* LightSceneInfo, float ShadowFadeFraction) const
{
SetShaderValue(BatchedParameters, LightFunctionParameters, GetLightFunctionSharedParameters(LightSceneInfo, ShadowFadeFraction));
}
/** Serializer. */
friend FArchive& operator<<(FArchive& Ar,FLightFunctionSharedParameters& P)
{
Ar << P.LightFunctionParameters;
return Ar;
}
private:
LAYOUT_FIELD(FShaderParameter, LightFunctionParameters)
};
/** Utility functions for drawing a sphere */
namespace StencilingGeometry
{
/**
* Draws a sphere using RHIDrawIndexedPrimitive, useful as approximate bounding geometry for deferred passes.
* Note: The sphere will be of unit size unless transformed by the shader.
*/
extern void DrawSphere(FRHICommandList& RHICmdList);
/**
* Draws a sphere using RHIDrawIndexedPrimitive, useful as approximate bounding geometry for deferred passes.
* Compatible with instanced rendering.
* Note: The sphere will be of unit size unless transformed by the shader.
*/
extern void DrawSphere(FRHICommandList& RHICmdList, uint32 InstanceCount);
/** Draws exactly the same as above, but uses FVector rather than FVector4f vertex data. */
extern void DrawVectorSphere(FRHICommandList& RHICmdList);
/** Renders a cone with a spherical cap, used for rendering spot lights in deferred passes. */
extern void DrawCone(FRHICommandList& RHICmdList);
/**
* Vertex buffer for a sphere of unit size. Used for drawing a sphere as approximate bounding geometry for deferred passes.
*/
template<int32 NumSphereSides, int32 NumSphereRings, typename VectorType>
class TStencilSphereVertexBuffer : public FVertexBuffer
{
public:
static_assert(std::is_same_v<typename VectorType::FReal, float>, "Must be a float vector type");
int32 GetNumRings() const
{
return NumSphereRings;
}
/**
* Initialize the RHI for this rendering resource
*/
void InitRHI(FRHICommandListBase& RHICmdList) override
{
const int32 NumSides = NumSphereSides;
const int32 NumRings = NumSphereRings;
const int32 NumVerts = (NumSides + 1) * (NumRings + 1);
const float RadiansPerRingSegment = UE_PI / (float)NumRings;
float Radius = 1;
TArray<VectorType, TInlineAllocator<NumRings + 1> > ArcVerts;
ArcVerts.Empty(NumRings + 1);
// Calculate verts for one arc
for (int32 i = 0; i < NumRings + 1; i++)
{
const float Angle = i * RadiansPerRingSegment;
ArcVerts.Add(FVector3f(0.0f, FMath::Sin(Angle), FMath::Cos(Angle)));
}
TArray<VectorType> Verts;
Verts.Empty(NumVerts);
// Then rotate this arc NumSides + 1 times.
const FVector3f Center = FVector3f(0,0,0);
for (int32 s = 0; s < NumSides + 1; s++)
{
FRotator3f ArcRotator(0, 360.f * ((float)s / NumSides), 0);
FRotationMatrix44f ArcRot( ArcRotator );
for (int32 v = 0; v < NumRings + 1; v++)
{
const int32 VIx = (NumRings + 1) * s + v;
Verts.Add(Center + Radius * ArcRot.TransformPosition(ArcVerts[v]));
}
}
NumSphereVerts = Verts.Num();
// Create vertex buffer. Fill buffer with initial data upon creation
VertexBufferRHI = UE::RHIResourceUtils::CreateVertexBufferFromArray(RHICmdList, TEXT("TStencilSphereVertexBuffer"), EBufferUsageFlags::Static, MakeConstArrayView(Verts));
}
int32 GetVertexCount() const { return NumSphereVerts; }
/**
* Calculates the world transform for a sphere.
* @param OutTransform - The output world transform.
* @param Sphere - The sphere to generate the transform for.
* @param PreViewTranslation - The pre-view translation to apply to the transform.
* @param bConservativelyBoundSphere - when true, the sphere that is drawn will contain all positions in the analytical sphere,
* Otherwise the sphere vertices will lie on the analytical sphere and the positions on the faces will lie inside the sphere.
*/
void CalcTransform(FVector4f& OutPosAndScale, const FSphere& Sphere, const FVector& PreViewTranslation, bool bConservativelyBoundSphere = true)
{
float Radius = Sphere.W; // LWC_TODO: Precision loss
if (bConservativelyBoundSphere)
{
const int32 NumRings = NumSphereRings;
const float RadiansPerRingSegment = UE_PI / (float)NumRings;
// Boost the effective radius so that the edges of the sphere approximation lie on the sphere, instead of the vertices
Radius /= FMath::Cos(RadiansPerRingSegment);
}
const FVector3f Translate(Sphere.Center + PreViewTranslation);
OutPosAndScale = FVector4f(Translate, Radius);
}
private:
int32 NumSphereVerts;
};
/**
* Stenciling sphere index buffer
*/
template<int32 NumSphereSides, int32 NumSphereRings>
class TStencilSphereIndexBuffer : public FIndexBuffer
{
public:
/**
* Initialize the RHI for this rendering resource
*/
void InitRHI(FRHICommandListBase& RHICmdList) override
{
const int32 NumSides = NumSphereSides;
const int32 NumRings = NumSphereRings;
TArray<uint16> Indices;
Indices.Reserve(NumSides * NumRings * 6);
// Add triangles for all the vertices generated
for (int32 s = 0; s < NumSides; s++)
{
const int32 a0start = (s + 0) * (NumRings + 1);
const int32 a1start = (s + 1) * (NumRings + 1);
for (int32 r = 0; r < NumRings; r++)
{
Indices.Add(a0start + r + 0);
Indices.Add(a1start + r + 0);
Indices.Add(a0start + r + 1);
Indices.Add(a1start + r + 0);
Indices.Add(a1start + r + 1);
Indices.Add(a0start + r + 1);
}
}
NumIndices = Indices.Num();
// Create index buffer. Fill buffer with initial data upon creation
IndexBufferRHI = UE::RHIResourceUtils::CreateIndexBufferFromArray(RHICmdList, TEXT("TStencilSphereIndexBuffer"), EBufferUsageFlags::Static, MakeConstArrayView(Indices));
}
int32 GetIndexCount() const { return NumIndices; };
private:
int32 NumIndices;
};
extern TGlobalResource<TStencilSphereVertexBuffer<18, 12, FVector4f> > GStencilSphereVertexBuffer;
extern TGlobalResource<TStencilSphereVertexBuffer<18, 12, FVector3f> > GStencilSphereVectorBuffer;
extern TGlobalResource<TStencilSphereIndexBuffer<18, 12> > GStencilSphereIndexBuffer;
extern TGlobalResource<TStencilSphereVertexBuffer<4, 4, FVector4f> > GLowPolyStencilSphereVertexBuffer;
extern TGlobalResource<TStencilSphereIndexBuffer<4, 4> > GLowPolyStencilSphereIndexBuffer;
}; //End StencilingGeometry
/**
* Stencil geometry parameters used by multiple shaders.
*/
class FStencilingGeometryShaderParameters
{
DECLARE_TYPE_LAYOUT(FStencilingGeometryShaderParameters, NonVirtual);
public:
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER(FVector4f, StencilingGeometryPosAndScale)
SHADER_PARAMETER(FVector4f, StencilingConeParameters)
SHADER_PARAMETER(FMatrix44f, StencilingConeTransform)
END_SHADER_PARAMETER_STRUCT()
void Bind(const FShaderParameterMap& ParameterMap);
void Set(FRHIBatchedShaderParameters& BatchedParameters, const FVector4f& InStencilingGeometryPosAndScale) const;
void Set(FRHIBatchedShaderParameters& BatchedParameters, const FSceneView& View, const FLightSceneInfo* LightSceneInfo) const;
static FParameters GetParameters(const FVector4f& InStencilingGeometryPosAndScale);
static FParameters GetParameters(const FSceneView& View, const FLightSceneInfo* LightSceneInfo);
/** Serializer. */
friend FArchive& operator<<(FArchive& Ar,FStencilingGeometryShaderParameters& P)
{
Ar << P.StencilGeometryPosAndScale;
Ar << P.StencilConeParameters;
Ar << P.StencilConeTransform;
return Ar;
}
private:
LAYOUT_FIELD(FShaderParameter, StencilGeometryPosAndScale)
LAYOUT_FIELD(FShaderParameter, StencilConeParameters)
LAYOUT_FIELD(FShaderParameter, StencilConeTransform)
};
BEGIN_SHADER_PARAMETER_STRUCT(FDrawFullScreenRectangleParameters, )
SHADER_PARAMETER(FVector4f, PosScaleBias)
SHADER_PARAMETER(FVector4f, UVScaleBias)
SHADER_PARAMETER(FVector4f, InvTargetSizeAndTextureSize)
END_SHADER_PARAMETER_STRUCT()
/** A vertex shader for rendering the light in a deferred pass. */
class FDeferredLightVS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FDeferredLightVS,Global);
SHADER_USE_PARAMETER_STRUCT(FDeferredLightVS, FGlobalShader);
class FRadialLight : SHADER_PERMUTATION_BOOL("SHADER_RADIAL_LIGHT");
using FPermutationDomain = TShaderPermutationDomain<FRadialLight>;
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
SHADER_PARAMETER_STRUCT_INCLUDE(FDrawFullScreenRectangleParameters, FullScreenRect)
SHADER_PARAMETER_STRUCT_INCLUDE(FStencilingGeometryShaderParameters::FParameters, Geometry)
END_SHADER_PARAMETER_STRUCT()
public:
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters);
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment);
static FDrawFullScreenRectangleParameters GetFullScreenRectParameters(
float X, float Y,
float SizeX, float SizeY,
float U, float V,
float SizeU, float SizeV,
FIntPoint InTargetSize,
FIntPoint InTextureSize);
static FParameters GetParameters(const FViewInfo& View,
float X, float Y,
float SizeX, float SizeY,
float U, float V,
float SizeU, float SizeV,
FIntPoint TargetSize,
FIntPoint TextureSize,
bool bBindViewUniform = true);
static FParameters GetParameters(const FViewInfo& View, bool bBindViewUniform = true);
static FParameters GetParameters(const FViewInfo& View, const FSphere& LightBounds, bool bBindViewUniform = true);
static FParameters GetParameters(const FViewInfo& View, const FLightSceneInfo* LightSceneInfo, bool bBindViewUniform = true);
};
enum class FLightOcclusionType : uint8
{
Shadowmap,
Raytraced,
MegaLights, // Light handled through MegaLights raytracing
MegaLightsVSM, // Light projection handled through MegaLights using a VSM source data
};
FLightOcclusionType GetLightOcclusionType(const FLightSceneProxy& Proxy, const FSceneViewFamily& ViewFamily);
FLightOcclusionType GetLightOcclusionType(const FLightSceneInfoCompact& LightInfo, const FSceneViewFamily& ViewFamily);