You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
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]
163 lines
5.8 KiB
Plaintext
163 lines
5.8 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/**
|
|
* VolumeLightingCommonSampling.usf
|
|
*/
|
|
|
|
/** Computes dynamic and static shadowing for a point anywhere in space. */
|
|
#ifdef VOLUME_SHADOW_SAMPLING_INPUT
|
|
|
|
#if VOLUME_SHADOW_SAMPLING_INPUT==0
|
|
|
|
// Sample from Light0Shadow
|
|
#define VSSPREFIX(X) Light0Shadow.X
|
|
#define VSSLIGHTPOSITION Light0Shadow.Position
|
|
#define VSSLIGHTINVRADIUS Light0Shadow.InvRadius
|
|
|
|
float ComputeLight0VolumeShadowing(
|
|
|
|
#elif VOLUME_SHADOW_SAMPLING_INPUT==1
|
|
|
|
// Sample from VolumeLightingCommon constants
|
|
#define VSSPREFIX(X) Light1Shadow.X
|
|
#define VSSLIGHTPOSITION Light1Shadow.Position
|
|
#define VSSLIGHTINVRADIUS Light1Shadow.InvRadius
|
|
|
|
float ComputeLight1VolumeShadowing(
|
|
|
|
#else
|
|
#error Unhandled value for VOLUME_SHADOW_SAMPLING_INPUT
|
|
#endif
|
|
|
|
#else
|
|
|
|
// Sample from data in
|
|
#define VSSPREFIX(X) X
|
|
#define VSSLIGHTPOSITION DeferredLightUniforms.Position
|
|
#define VSSLIGHTINVRADIUS DeferredLightUniforms.InvRadius
|
|
|
|
float ComputeVolumeShadowing(
|
|
|
|
#endif
|
|
float3 WorldPositionForLighting, bool bPointLight, bool bSpotLight, inout bool bShadowFactorValid)
|
|
{
|
|
float ShadowFactor = 1;
|
|
bShadowFactorValid = false;
|
|
|
|
BRANCH
|
|
if (VSSPREFIX(bStaticallyShadowed))
|
|
{
|
|
bool bUsePointLightShadowing = bPointLight;
|
|
|
|
BRANCH
|
|
if (bUsePointLightShadowing)
|
|
{
|
|
float3 LightVector = WorldPositionForLighting - VSSLIGHTPOSITION;
|
|
float DistanceToLight = length(LightVector);
|
|
float3 NormalizedLightVector = LightVector / DistanceToLight;
|
|
|
|
//@todo - use parametrization without slow inverse trig. Dual paraboloid?
|
|
float NormalizedTheta = atan2(NormalizedLightVector.y, NormalizedLightVector.x) / (2 * PI);
|
|
// atan2 returns in the range [-PI, PI], wrap the negative portion to [.5, 1]
|
|
float U = NormalizedTheta > 0 ? NormalizedTheta : 1 + NormalizedTheta;
|
|
float V = acos(NormalizedLightVector.z) / PI;
|
|
float2 UnwrappedUVs = float2(U, V);
|
|
|
|
float ShadowDepth = Texture2DSampleLevel(VSSPREFIX(StaticShadowDepthTexture), VSSPREFIX(StaticShadowDepthTextureSampler), UnwrappedUVs, 0).x;
|
|
ShadowFactor = DistanceToLight * VSSLIGHTINVRADIUS < ShadowDepth;
|
|
bShadowFactorValid = true;
|
|
}
|
|
else
|
|
{
|
|
// This path is used for directional lights and spot lights, which only require a single projection
|
|
// Transform the world position into shadowmap space
|
|
float4 HomogeneousShadowPosition = mul(float4(WorldPositionForLighting, 1), VSSPREFIX(WorldToStaticShadowMatrix));
|
|
float2 ShadowUVs = HomogeneousShadowPosition.xy / HomogeneousShadowPosition.w;
|
|
|
|
// Treat as unshadowed if the voxel is outside of the shadow map
|
|
if (all(ShadowUVs >= 0 && ShadowUVs <= 1))
|
|
{
|
|
FPCFSamplerSettings Settings;
|
|
Settings.ShadowDepthTexture = VSSPREFIX(StaticShadowDepthTexture);
|
|
Settings.ShadowDepthTextureSampler = VSSPREFIX(StaticShadowDepthTextureSampler);
|
|
Settings.ShadowBufferSize = VSSPREFIX(StaticShadowBufferSize);
|
|
Settings.SceneDepth = HomogeneousShadowPosition.z;
|
|
Settings.TransitionScale = 40;
|
|
Settings.bSubsurface = false;
|
|
// We can sample outside of the static shadowmap, which is centered around the scene. These 'infinite' depth values should not cause occlusion.
|
|
Settings.bTreatMaxDepthUnshadowed = true;
|
|
Settings.DensityMulConstant = 0;
|
|
Settings.ProjectionDepthBiasParameters = float2(0, 0);
|
|
|
|
ShadowFactor = Manual1x1PCF(ShadowUVs, Settings);
|
|
bShadowFactorValid = true;
|
|
|
|
/*
|
|
// Sample the shadowmap depth and determine if this voxel is shadowed
|
|
float ShadowDepth = Texture2DSampleLevel(StaticShadowDepthTexture, StaticShadowDepthTextureSampler, ShadowUVs, 0).x;
|
|
ShadowFactor = HomogeneousShadowPosition.z < ShadowDepth;
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DYNAMICALLY_SHADOWED && FEATURE_LEVEL >= FEATURE_LEVEL_SM4
|
|
bool bUseCubemapShadowing = bPointLight;
|
|
float DynamicShadowFactor = 1;
|
|
|
|
if (bUseCubemapShadowing)
|
|
{
|
|
bShadowFactorValid = true;
|
|
const float DepthBias = 0.03f * 512 * VSSPREFIX(InvShadowmapResolution);
|
|
const float SlopeDepthBias = 0;
|
|
const float MaxSlopeDepthBias = 0;
|
|
|
|
DynamicShadowFactor = CubemapHardwarePCF(
|
|
VSSPREFIX(ShadowDepthCubeTexture), VSSPREFIX(ShadowDepthCubeTextureSampler), VSSPREFIX(ShadowViewProjectionMatrices), VSSPREFIX(InvShadowmapResolution),
|
|
WorldPositionForLighting, VSSLIGHTPOSITION, VSSLIGHTINVRADIUS, DepthBias, SlopeDepthBias, MaxSlopeDepthBias);
|
|
}
|
|
else
|
|
{
|
|
// Transform the world position into shadowmap space
|
|
// NOTE: Shadow space is reverse Z, but shadowmap is stored in "linear Z"
|
|
float4 HomogeneousShadowPosition = mul(float4(WorldPositionForLighting, 1), VSSPREFIX(WorldToShadowMatrix));
|
|
float2 ShadowUVs = HomogeneousShadowPosition.xy / HomogeneousShadowPosition.w;
|
|
float SceneDepth = 1.0f - HomogeneousShadowPosition.z;
|
|
|
|
// Treat as unshadowed if the voxel is outside of the shadow map
|
|
if (all(ShadowUVs >= VSSPREFIX(ShadowmapMinMax).xy) && all(ShadowUVs <= VSSPREFIX(ShadowmapMinMax).zw))
|
|
{
|
|
bShadowFactorValid = true;
|
|
// Sample the shadowmap depth and determine if this voxel is shadowed
|
|
float ShadowDepth = Texture2DSampleLevel(VSSPREFIX(ShadowDepthTexture), VSSPREFIX(ShadowDepthTextureSampler), ShadowUVs, 0).x;
|
|
DynamicShadowFactor = SceneDepth < ShadowDepth - VSSPREFIX(DepthBiasParameters).x;
|
|
|
|
#ifdef TREAT_MAXDEPTH_UNSHADOWED
|
|
DynamicShadowFactor = saturate(DynamicShadowFactor + (ShadowDepth == 1.0f));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// fade shadows in the distance
|
|
if (!bPointLight && !bSpotLight)
|
|
{
|
|
float Depth = dot(WorldPositionForLighting - LWCHackToFloat(PrimaryView.WorldCameraOrigin), View.ViewForward);
|
|
float DistanceFade = saturate(Depth * VSSPREFIX(ShadowInjectParams).z + VSSPREFIX(ShadowInjectParams).w);
|
|
DynamicShadowFactor = lerp(DynamicShadowFactor, 1.0f, DistanceFade * DistanceFade);
|
|
}
|
|
|
|
// Combine static shadowing and dynamic shadowing, important for stationary directional lights with CSM
|
|
ShadowFactor = min(ShadowFactor, DynamicShadowFactor);
|
|
|
|
#endif
|
|
|
|
return ShadowFactor;
|
|
}
|
|
|
|
|
|
|
|
#undef VSSPREFIX
|
|
#undef VSSLIGHTPOSITION
|
|
#undef VSSLIGHTINVRADIUS
|
|
|