You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Light function materials are rendered as additional draws with additive blending to the prepass/postprocess targets. For the prepass codepath (that requires a depth prepass) the directional render target is updated in the main pass, only the color target is updated per light function. Light functions of non-directional lights are currently not supported. #rb Florin.Pascu, Dmitriy.Dyomin, Charles.deRousiers [CL 27764934 by florian penzkofer in ue5-main branch]
241 lines
7.1 KiB
Plaintext
241 lines
7.1 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#define SUPPORT_CONTACT_SHADOWS 0
|
|
|
|
#if !COMPUTE_SHADER
|
|
#include "Common.ush"
|
|
#include "SceneTextureParameters.ush"
|
|
#include "DeferredLightingCommon.ush"
|
|
#endif
|
|
|
|
#if LIGHT_FUNCTION
|
|
#include "/Engine/Generated/Material.ush"
|
|
#include "LightDataUniforms.ush"
|
|
#include "LightFunctionCommon.ush"
|
|
#else
|
|
#include "LightGridCommon.ush"
|
|
#endif
|
|
|
|
#if COMPUTE_SHADER
|
|
|
|
uint2 GroupSize;
|
|
RWBuffer<int> RWTileInfo;
|
|
[numthreads(THREADGROUP_SIZEX, 1, 1)]
|
|
void MainCS(
|
|
uint3 GroupId : SV_GroupID,
|
|
uint3 DispatchThreadId : SV_DispatchThreadID,
|
|
uint3 GroupThreadId : SV_GroupThreadID)
|
|
{
|
|
if(DispatchThreadId.x > (GroupSize.x * GroupSize.y))
|
|
{
|
|
return;
|
|
}
|
|
|
|
const uint GridX = DispatchThreadId.x % GroupSize.x;
|
|
const uint GridY = DispatchThreadId.x / GroupSize.x;
|
|
const uint EyeIndex = 0;
|
|
const FLightGridData GridData = GetLightGridData(EyeIndex);
|
|
uint LocalNumLights = 0;
|
|
LOOP
|
|
for (int SliceIt = 0; SliceIt < GridData.CulledGridSize.z; SliceIt++)
|
|
{
|
|
const uint GridIndex = ComputeLightGridCellIndex(uint3(GridX, GridY, SliceIt), EyeIndex);
|
|
const FCulledLightsGridData CulledLightsGrid = GetCulledLightsGrid(GridIndex, EyeIndex);
|
|
|
|
LocalNumLights = CulledLightsGrid.NumLocalLights;
|
|
|
|
if(LocalNumLights > 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(LocalNumLights > 0)
|
|
{
|
|
RWTileInfo[2 * DispatchThreadId.x] = GridX;
|
|
RWTileInfo[2 * DispatchThreadId.x + 1] = GridY;
|
|
}
|
|
else
|
|
{
|
|
RWTileInfo[2 * DispatchThreadId.x] = -1;
|
|
RWTileInfo[2 * DispatchThreadId.x + 1] = -1;
|
|
}
|
|
}
|
|
|
|
#else // COMPUTE_SHADER
|
|
|
|
#if !LIGHT_FUNCTION
|
|
|
|
int LightGridPixelSize;
|
|
Buffer<int> TileInfo;
|
|
void MainVS(
|
|
float2 TexCoord : ATTRIBUTE0,
|
|
uint VertexId : SV_VertexID,
|
|
uint InstanceId : SV_InstanceID,
|
|
out float4 OutPosition : SV_POSITION)
|
|
{
|
|
float YPos = TileInfo[2 * InstanceId + 1] + TexCoord.y;
|
|
float XPos = TileInfo[2 * InstanceId] + TexCoord.x;
|
|
|
|
float2 ScreenUV = float2(XPos, YPos) * LightGridPixelSize * View.BufferSizeAndInvSize.zw;
|
|
float2 ScreenPosition = (ScreenUV.xy - View.ScreenPositionScaleBias.wz) / View.ScreenPositionScaleBias.xy;
|
|
OutPosition = float4(ScreenPosition, 0, 1);
|
|
|
|
if(TileInfo[2 * InstanceId] < 0)
|
|
{
|
|
OutPosition.xy = 0;
|
|
}
|
|
}
|
|
|
|
void Main(float4 SvPosition : SV_POSITION
|
|
, out float3 OutColorA : SV_Target0
|
|
#if POST_PROCESS_LOCAL_LIGHTS == 0
|
|
, out float4 OutColorB : SV_Target1
|
|
#endif
|
|
)
|
|
{
|
|
const uint2 PixelPos = SvPosition.xy;
|
|
const float2 ScreenPosition = SvPositionToScreenPosition(SvPosition).xy;
|
|
const uint EyeIndex = 0;
|
|
|
|
float2 ScreenUV = ScreenPosition * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz;
|
|
float SceneDepth = CalcSceneDepth(ScreenUV);
|
|
|
|
float3 TranslatedWorldPosition = mul(float4(ScreenPosition * SceneDepth, SceneDepth, 1), PrimaryView.ScreenToTranslatedWorld).xyz;
|
|
float3 CameraVector = normalize(TranslatedWorldPosition);
|
|
|
|
uint GridIndex = ComputeLightGridCellIndex(uint2(PixelPos.x, PixelPos.y), SceneDepth);
|
|
const FCulledLightsGridData CulledLightGridData = GetCulledLightsGrid(GridIndex, EyeIndex);
|
|
|
|
uint NumLocalLights = min(CulledLightGridData.NumLocalLights, GetMaxLightsPerCell(EyeIndex));
|
|
|
|
float3 Color = uint3(0.f, 0.f , 0.f);
|
|
float3 SavedL = float3(0,0,0);
|
|
float TotalWeight = 0;
|
|
|
|
LOOP
|
|
for (uint LocalLightListIndex = 0; LocalLightListIndex < NumLocalLights; LocalLightListIndex++)
|
|
{
|
|
const FLocalLightData LocalLight = GetLocalLightData(CulledLightGridData.DataStartIndex + LocalLightListIndex, EyeIndex);
|
|
|
|
// extra-early out since we know light grid is sloppy and all lights in list are radial (have a range)
|
|
// appears useless
|
|
float InvLightRadiusSq = LocalLight.LightPositionAndInvRadius.w * LocalLight.LightPositionAndInvRadius.w;
|
|
float DistLight = length2(TranslatedWorldPosition - LocalLight.LightPositionAndInvRadius.xyz) * InvLightRadiusSq;
|
|
|
|
if (DistLight > 1.0f)
|
|
{
|
|
continue;
|
|
}
|
|
FDeferredLightData LightData = ConvertToDeferredLight_Mobile(LocalLight);
|
|
|
|
float3 L = LightData.Direction; // Already normalized
|
|
float3 ToLight = L;
|
|
float3 MaskedLightColor = LightData.Color;
|
|
float LightMask = 1;
|
|
if (LightData.bRadialLight)
|
|
{
|
|
LightMask = GetLocalLightAttenuation( TranslatedWorldPosition, LightData, ToLight, L );
|
|
MaskedLightColor *= LightMask;
|
|
}
|
|
|
|
float WeightLight = 1 - DistLight;
|
|
|
|
if( LightMask > 0)
|
|
{
|
|
TotalWeight += WeightLight;
|
|
// For lights with light functions we only only use the compute the direction (OutColorB)
|
|
// The Color is added in additional draws using MainLightFunction()
|
|
if (!UnpackHasLightFunction(LocalLight))
|
|
{
|
|
Color += MaskedLightColor;
|
|
}
|
|
|
|
SavedL += L * WeightLight;
|
|
}
|
|
}
|
|
|
|
#if POST_PROCESS_LOCAL_LIGHTS == 0
|
|
if (TotalWeight > 0)
|
|
{
|
|
SavedL = (SavedL / TotalWeight);
|
|
OutColorA = float3(Color.x, Color.y, Color.z);
|
|
OutColorB = 0.5f * float4(SavedL.x, SavedL.y, SavedL.z, 0) + float4(0.5f, 0.5f, 0.5f, 0.5f);
|
|
}
|
|
else
|
|
{
|
|
OutColorA = float3(0, 0, 0);
|
|
OutColorB = float4(0.5,0.5,0.5, 0.5);
|
|
}
|
|
#else
|
|
if (TotalWeight > 0)
|
|
{
|
|
SavedL = (SavedL / TotalWeight);
|
|
float3 N = normalize(cross(ddx(TranslatedWorldPosition.xyz), ddy(TranslatedWorldPosition.xyz)));
|
|
float3 L = SavedL; // Already normalized
|
|
float NoL = max(0, dot(N, L));
|
|
float3 Diffuse = (1 / PI) * NoL * Color;
|
|
OutColorA = 1 + Diffuse;
|
|
}
|
|
else
|
|
{
|
|
OutColorA = float3(1, 1, 1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
#else // !LIGHT_FUNCTION
|
|
|
|
|
|
float4x4 SvPositionToLight;
|
|
/** Fade distance in x, disabled brightness in y */
|
|
float2 LightFunctionParameters2;
|
|
|
|
void MainLightFunction(
|
|
float4 InScreenPosition : TEXCOORD0,
|
|
float4 SvPosition : SV_POSITION,
|
|
out float3 OutColorA : SV_Target0
|
|
)
|
|
{
|
|
float2 ScreenUV = SvPositionToBufferUV(SvPosition);
|
|
SvPosition.z = LookupDeviceZ(ScreenUV);
|
|
float3 TranslatedWorldPosition = SvPositionToTranslatedWorld(SvPosition);
|
|
float ViewDistance = length(GetPrimaryView().TranslatedWorldCameraOrigin - TranslatedWorldPosition);
|
|
float GreyScale;
|
|
{
|
|
float4 Hom = mul(float4(SvPosition.xyz, 1), SvPositionToLight);
|
|
float3 LightVector = Hom.xyz / Hom.w;
|
|
float3 Color = GetLightFunctionColor(LightVector, TranslatedWorldPosition);
|
|
GreyScale = dot(Color, .3333f);
|
|
}
|
|
float DistanceFadeAlpha = saturate((LightFunctionParameters2.x - ViewDistance) / (LightFunctionParameters2.x * .2f));
|
|
GreyScale = lerp(LightFunctionParameters2.y, GreyScale, DistanceFadeAlpha);
|
|
GreyScale = lerp(LightFunctionParameters2.y, GreyScale, LightFunctionParameters.y);
|
|
float EncodedLightAttenuation = EncodeLightAttenuation(GreyScale);
|
|
|
|
FDeferredLightData LightData = InitDeferredLightFromUniforms();
|
|
float3 L = LightData.Direction; // Already normalized
|
|
float3 ToLight = LightData.TranslatedWorldPosition - TranslatedWorldPosition;
|
|
float LightMask = 1;
|
|
// At the moment directional lights are not supported
|
|
// if (LightData.bRadialLight)
|
|
{
|
|
LightMask = GetLocalLightAttenuation( TranslatedWorldPosition, LightData, ToLight, L );
|
|
}
|
|
|
|
float3 Color = LightData.Color * LightMask * EncodedLightAttenuation;
|
|
|
|
#if POST_PROCESS_LOCAL_LIGHTS == 0
|
|
OutColorA = Color;
|
|
#else
|
|
float3 N = normalize(cross(ddx(TranslatedWorldPosition.xyz), ddy(TranslatedWorldPosition.xyz)));
|
|
float NoL = max(0, dot(N, L));
|
|
float3 Diffuse = (1 / PI) * NoL * Color;
|
|
OutColorA = Diffuse;
|
|
#endif
|
|
}
|
|
#endif // !LIGHT_FUNCTION
|
|
|
|
#endif // COMPUTE_SHADER
|