Files
UnrealEngineUWP/Engine/Shaders/Private/LightFunctionCommon.ush
ben ingram 0bb0a923a0 Merging Dev-LWCRendering into Main, this includes initial work to support rendering with LWC-scale position
Basic approach is to add HLSL types FLWCScalar, FLWCMatrix, FLWCVector, etc.  Inside shaders, absolute world space position values should be represented as FLWCVector3.  Matrices that transform *into* absolute world space become FLWCMatrix.  Matrices that transform *from* world space become FLWCInverseMatrix.  Generally LWC values work by extending the regular 'float' value with an additional tile coordinate.  Final tile size will be a trade-off between scale/accuracy; I'm using 256k for now, but may need to be adjusted.  Value represented by a FLWCVector thus becomes V.Tile * TileSize + V.Offset.  Most operations can be performed directly on LWC values.  There are HLSL functions like LWCAdd, LWCSub, LWCMultiply, LWCDivide (operator overloading would be really nice here).  The goal is to stay with LWC values for as long as needed, then convert to regular float values when possible.  One thing that comes up a lot is working in translated (rather than absolute) world space.  WorldSpace + View.PrevPreViewTranslation = TranslatedWorldspace.  Except 'View.PrevPreViewTranslation' is now a FLWCVector3, and WorldSpace quantities should be as well.  So that becomes LWCAdd(WorldSpace, View.PrevPreViewTranslation) = TranslatedWorldspace.  Assuming that we're talking about a position that's "reasonably close" to the camera, it should be safe to convert the translated WS value to float.  The 'tile' coordinate of the 2 LWC values should cancel out when added together in this case.  I've done some work throughout the shader code to do this.  Materials are fully supporting LWC-values as well.  Projective texturing and vertex animation materials that I've tested work correctly even when positioned "far away" from the origin.

Lots of work remains to fully convert all of our shader code.  There's a function LWCHackToFloat(), which is a simple wrapper for LWCToFloat().  The idea of HackToFloat is to mark places that need further attention, where I'm simply converting absolute WS positions to float, to get shaders to compile.  Shaders converted in this way should continue to work for all existing content (without LWC-scale values), but they will break if positions get too large.

General overview of changed files:
LargeWorldCoordinates.ush - This defines the FLWC types and operations
GPUScene.cpp, SceneData.ush - Primitives add an extra 'float3' tile coordinate.  Instance data is unchanged, so instances need to stay within single-precision range of the primitive origin.  Could potentially split instances behind the scenes (I think) if we don't want this limitation
HLSLMaterialDerivativeAutogen.cpp, HLSLMaterialTranslator.cpp, Preshader.cpp - Translated materials to use LWC values
SceneView.cpp, SceneRelativeViewMatrices.cpp, ShaderCompiler.cpp, InstancedStereo.ush - View uniform buffer includes LWC values where appropriate
#jira UE-117101
#rb arne.schober, Michael.Galetzka

#ROBOMERGE-AUTHOR: ben.ingram
#ROBOMERGE-SOURCE: CL 17787435 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v881-17767770)

[CL 17787478 by ben ingram in ue5-release-engine-test branch]
2021-10-12 13:31:00 -04:00

63 lines
2.8 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LightFunctionCommon.usf: Utility functions for light functions.
=============================================================================*/
/** Tan of spotlight cone outer angle in x, ShadowFadeFraction in y, IsSpotLight in z, IsPointLight in w. */
float4 LightFunctionParameters;
float4x4 LightFunctionWorldToLight;
/**
* 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 GetLightFunctionColorTWS(float3 LightVector, float3 TranslatedWorldSpace)
{
// 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);
}
FMaterialPixelParameters MaterialParameters = MakeInitializedMaterialPixelParameters();
#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 = LWCSubtract(TranslatedWorldSpace, PrimaryView.PreViewTranslation);
FPixelMaterialInputs PixelMaterialInputs;
CalcPixelMaterialInputs(MaterialParameters, PixelMaterialInputs);
#if COMPUTESHADER
return GetMaterialEmissiveForCS(MaterialParameters);
#else
return GetMaterialEmissive(PixelMaterialInputs);
#endif
}
float3 GetLightFunctionColor(float3 LightVector, float3 AbsoluteWorldPosition)
{
return GetLightFunctionColorTWS(LightVector, AbsoluteWorldPosition + LWCHackToFloat(PrimaryView.PreViewTranslation));
}