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

112 lines
4.3 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LightFunctionCommon.usf: Utility functions for light functions.
=============================================================================*/
#include "/Engine/Private/Substrate/Substrate.ush"
#ifndef LIGHT_FUNCTION_ATLAS
#define LIGHT_FUNCTION_ATLAS 0
#endif
// This ifdef is to allow shaders(notably the ratracing miss shader implementing light functions) to override where these parameters come from.
#ifndef LightFunctionParameters
/** Tan of spotlight cone outer angle in x, ShadowFadeFraction in y, IsSpotLight in z, IsPointLight in w. */
float4 LightFunctionParameters;
float4x4 LightFunctionTranslatedWorldToLight;
#endif
/**
* Calculates the light function color with the given light vector.
* LightVector is the vector from the light to the position being shaded, in the light's coordinate space.
*/
float3 GetLightFunctionColor(float3 LightVector, float3 TranslatedWorldSpace, in out FMaterialPixelParameters MaterialParameters
#if LIGHT_FUNCTION_ATLAS
, float2 UVs
#endif
)
{
#if LIGHT_FUNCTION_ATLAS
// This path is used when rendering a light function into a 2D Atlas
float2 LightFunctionUVs = UVs;
#else // LIGHT_FUNCTION_ATLAS
// Swizzle so that LightVector.xy are perpendicular to the light direction and LightVector.z is distance along the light direction
LightVector.xyz = LightVector.zyx;
// By default, map textures using the vectors perpendicular to the light direction
float2 LightFunctionUVs = LightVector.xy;
if (LightFunctionParameters.z > 0)
{
// For spotlights, setup UVs that go from 1 at one side of the spotlight cone to 0 at the other side, at any distance from the light
// This minimizes artist setup when they just want to use the spotlight like a projector
LightFunctionUVs = LightVector.xy / (LightVector.z * LightFunctionParameters.x) * .5f + .5f;
}
else if (LightFunctionParameters.w > 0)
{
float3 UnitLightVector = normalize(LightVector);
// Setup 2d UVs for a pointlight that map the texture using spherical coordinates, which is how max handles a 2d texture projector on a point light
// Artists should use a cubemap indexed by a light vector to get better quality
LightFunctionUVs = float2((atan2(UnitLightVector.y, UnitLightVector.x) + PI) / (2 * PI), acos(UnitLightVector.z) / PI);
}
#endif // LIGHT_FUNCTION_ATLAS
#if NUM_MATERIAL_TEXCOORDS
for(int CoordinateIndex = 0;CoordinateIndex < NUM_MATERIAL_TEXCOORDS;CoordinateIndex++)
{
MaterialParameters.TexCoords[CoordinateIndex] = LightFunctionUVs;
}
#endif
MaterialParameters.VertexColor = 1;
MaterialParameters.CameraVector = LightVector.xyz;
MaterialParameters.ReflectionVector = LightVector.xyz;
MaterialParameters.LightVector = LightVector.xyz;
MaterialParameters.AbsoluteWorldPosition = DFFastSubtract(TranslatedWorldSpace, PrimaryView.PreViewTranslation);
MaterialParameters.WorldPosition_CamRelative = MaterialParameters.WorldPosition_NoOffsets_CamRelative = TranslatedWorldSpace;
MaterialParameters.ScreenPosition = mul(float4(TranslatedWorldSpace, 1.0f), PrimaryView.TranslatedWorldToClip);
MaterialParameters.LWCData = MakeMaterialLWCData(MaterialParameters);
FPixelMaterialInputs PixelMaterialInputs;
CalcPixelMaterialInputs(MaterialParameters, PixelMaterialInputs);
#if SUBSTRATE_ENABLED
// Light function node forces a single unlit BSDF. We get the raw data from the Substrate light function node from the raw BSDF on the tree.
FSubstratePixelHeader SubstratePixelHeader = MaterialParameters.GetFrontSubstrateHeader();
FSubstrateBSDF UnlitBSDF = SubstratePixelHeader.SubstrateTree.BSDFs[0];
UnlitBSDF.SubstrateSanitizeBSDF(); // required wehen not calling SubstrateUpdateTreeUnlit
return SubstrateGetBSDFEmissive(UnlitBSDF);
#else // SUBSTRATE_ENABLED
#if COMPUTESHADER
return GetMaterialEmissiveForCS(MaterialParameters);
#else
return GetMaterialEmissive(PixelMaterialInputs);
#endif
#endif // SUBSTRATE_ENABLED
}
float3 GetLightFunctionColor(float3 LightVector, float3 TranslatedWorldSpace
#if LIGHT_FUNCTION_ATLAS
, float2 UVs
#endif
)
{
FMaterialPixelParameters MaterialParameters = MakeInitializedMaterialPixelParameters();
return GetLightFunctionColor(LightVector, TranslatedWorldSpace, MaterialParameters
#if LIGHT_FUNCTION_ATLAS
, UVs
#endif
);
}