Files
UnrealEngineUWP/Engine/Shaders/Private/LightMapDensityShader.usf
Ben Ingram 14ea9b00e5 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

[CL 17787435 by Ben Ingram in ue5-main branch]
2021-10-12 13:29:45 -04:00

177 lines
6.2 KiB
Plaintext

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
LightMapDensityShader.hlsl: Shader for rendering lightmap density as a color
=============================================================================*/
#define NEEDS_LIGHTMAP_COORDINATE (HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP)
#include "Common.ush"
#include "/Engine/Generated/Material.ush"
#include "/Engine/Generated/VertexFactory.ush"
struct FLightMapDensityVSToPS
{
FVertexFactoryInterpolantsVSToPS FactoryInterpolants;
float4 WorldPosition : TEXCOORD6;
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
float3 PixelPositionExcludingWPO : TEXCOORD7;
#endif
float4 Position : SV_POSITION;
};
#define FLightMapDensityVSOutput FLightMapDensityVSToPS
/*=============================================================================
Vertex Shader
=============================================================================*/
#if VERTEXSHADER
void MainVertexShader(
FVertexFactoryInput Input,
out FLightMapDensityVSOutput Output
#if USE_GLOBAL_CLIP_PLANE
, out float OutGlobalClipPlaneDistance : SV_ClipDistance
#endif
)
{
ResolvedView = ResolveView();
FVertexFactoryIntermediates VFIntermediates = GetVertexFactoryIntermediates(Input);
float4 WorldPosition = VertexFactoryGetWorldPosition(Input, VFIntermediates);
float4 WorldPositionExcludingWPO = WorldPosition;
float3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, VFIntermediates);
FMaterialVertexParameters VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, WorldPosition.xyz, TangentToLocal);
WorldPosition.xyz += GetMaterialWorldPositionOffset(VertexParameters);
Output.WorldPosition = WorldPosition;
{
float4 RasterizedWorldPosition = VertexFactoryGetRasterizedWorldPosition(Input, VFIntermediates, Output.WorldPosition);
Output.Position = mul(RasterizedWorldPosition, ResolvedView.TranslatedWorldToClip);
}
#if USE_GLOBAL_CLIP_PLANE
OutGlobalClipPlaneDistance = dot(ResolvedView.GlobalClippingPlane, float4(WorldPosition.xyz, 1));
#endif
Output.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters);
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
Output.PixelPositionExcludingWPO = WorldPositionExcludingWPO.xyz;
#endif
}
#endif
/*=============================================================================
Pixel Shader
=============================================================================*/
float2 LightMapResolutionScale;
/**
* Tagging built vs. unbuilt lighting on objects.
* x = 1.0, y = 0.0 for built lighting
* x = 0.0, y = 1.0 for unbuilt lighting
* z = 1.0 if the object is selected
*/
float3 BuiltLightingAndSelectedFlags;
/**
* X = scalar to multiply density against...
* Y = scalar to multiply calculatated color against...
* So, to enable greyscale density mode - set X != 0, Y = 0
* Standard color mode - set X = 0, Y = 1
* Z = texture lightmap scalar
* Set to 1.0 if texture mapped to leave texture mapped colors alone.
* Set to 0.0 if vertex mapped
* W = vertex lightmap scalar
* Set to 0.0 if texture mapped
* Set to 1.0 if vertex mapped
*/
float4 LightMapDensityDisplayOptions;
/**
* The 'main' for the PixelShader
*/
void MainPixelShader(
FVertexFactoryInterpolantsVSToPS FactoryInterpolants,
float4 WorldPosition : TEXCOORD6,
#if USE_WORLD_POSITION_EXCLUDING_SHADER_OFFSETS
float3 PixelPositionExcludingWPO : TEXCOORD7,
#endif
in float4 SvPosition : SV_Position
OPTIONAL_IsFrontFace,
out float4 OutColor : SV_Target0
)
{
ResolvedView = ResolveView();
FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(FactoryInterpolants, SvPosition);
FPixelMaterialInputs PixelMaterialInputs;
CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, SvPosition, bIsFrontFace);
GetMaterialCoverageAndClipping(MaterialParameters, PixelMaterialInputs);
float2 LightMapUV,LightMapUV1;
#if HQ_TEXTURE_LIGHTMAP || LQ_TEXTURE_LIGHTMAP
uint LightmapDataIndex;
GetLightMapCoordinates(FactoryInterpolants,LightMapUV,LightMapUV1,LightmapDataIndex);
#else
LightMapUV = LightMapUV1 = float2(0.1,0.1);
#endif
// Area of parallelogram, in world space units.
float WorldSpaceArea = length( cross( ddx(WorldPosition.xyz), ddy(WorldPosition.xyz) ) );
WorldSpaceArea = max( WorldSpaceArea, 0.00000001f );
float MinDensity = LightmapDensityPass.LightMapDensity.y;
float IdealDensity = LightmapDensityPass.LightMapDensity.z;
float MaxDensity = LightmapDensityPass.LightMapDensity.w;
float Density = MinDensity;
float2 TexCoord = LightMapUV * (LightMapResolutionScale.xy * 2.0); // In texels
float2 A = ddx(TexCoord);
float2 B = ddy(TexCoord);
float2 C = A.xy * B.yx;
// Area of parallelogram, in texels.
float TexelArea = abs( C.x - C.y );
Density = TexelArea / WorldSpaceArea;
// Clamp the density to the max
Density = min( Density, MaxDensity );
float4 TintColor;
float4 TintGrayScale;
if ( Density > IdealDensity )
{
float Range = MaxDensity - IdealDensity;
Density -= IdealDensity;
TintColor = RETURN_COLOR( float4( Density/Range, (Range-Density)/Range, 0.0f, 1.0f ) );
}
else
{
float Range = IdealDensity - MinDensity;
Density -= MinDensity;
TintColor = RETURN_COLOR( float4( 0.0f, Density/Range, (Range-Density)/Range, 1.0f ) ) ;
}
float GrayScaleRange = MaxDensity - MinDensity;
TintGrayScale = RETURN_COLOR(float4(Density/GrayScaleRange,Density/GrayScaleRange,Density/GrayScaleRange,1.0f));
// Disable the color tinting if the option is set
TintColor *= LightMapDensityDisplayOptions.y;
// Enable 'grayscale' mode if desired
TintColor += (TintGrayScale * LightMapDensityDisplayOptions.x);
TintColor *= BuiltLightingAndSelectedFlags.x;
TintColor += BuiltLightingAndSelectedFlags.yyyy;
// Override the coloring if vertex mapped
TintColor *= LightMapDensityDisplayOptions.z;
TintColor += (LightmapDensityPass.VertexMappedColor * LightMapDensityDisplayOptions.w);
// Override the coloring if selected...
TintColor *= (1.0f - BuiltLightingAndSelectedFlags.z);
TintColor += (LightmapDensityPass.DensitySelectedColor * BuiltLightingAndSelectedFlags.z);
LightMapUV *= LightMapResolutionScale.xy;
OutColor = Texture2DSample(LightmapDensityPass.GridTexture, LightmapDensityPass.GridTextureSampler,LightMapUV) * TintColor;
}