You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3028958 on 2016/06/27 by Ben.Woodhouse Fix for perf issue with GetSingleFinalDataConst This was caused by the LPV integration/switch to blendables. Now we cache the flag for the directionalocclusion in the LPV class. This reduces calls to GetSingleFinalDataConst on the blendable data (potentially slow), and makes things a bit cleaner and consistent. Tested in QAGame editor (with LPV enabled in ConsoleSettings.ini) #jira UE-26179 Change 3029401 on 2016/06/27 by Rolando.Caloca DR - More vk logging Change 3029549 on 2016/06/27 by Uriel.Doyon Refactored "r.OnlyStreamInTextures" into "r.Streaming.FullyLoadUsedTextures", making it fully load every used textures, as an alternative to disabling texture streaming. New options "r.Streaming.UsePerTextureBias" that assign a bias between 0 and MipBias to each texture in order to fit in budget. Fixed crash when disabling texture streaming. Fixed issue when disabling texture streaming that would make current loaded texture low res. New logic to prevent retrying to cancel a streaming request more than once. Pending load request of one extra mip will not be cancelled anymore. Changed UTexture2D from float to double. Also using FApp::GetCurrentTime() instead of FPlatformTime::Seconds(). #jira UE-32197 #jira UE-31102 Change 3029837 on 2016/06/27 by David.Hill Fixed Shutter SM4 not working when using compute shader eye-adaptation #jira UE-32443 The default eye adaptation value was missing. Change 3030039 on 2016/06/27 by Uriel.Doyon Fix for crash when landscape materials are used in the Texture Streaming Build. #jira UE-32196 Change 3030081 on 2016/06/27 by Uriel.Doyon Updated MaterialTexCoordScalesPixelShader to use PackedEyeIndex, preventing crash when building the map with stereo rendering enabled. Change 3030401 on 2016/06/28 by Ben.Woodhouse Perf Monitor: Fix for perf warning due to cvar FindConsoleVariable being called too frequently. Tested in QAGame editor (DX11) #jira UE-31238 Change 3030607 on 2016/06/28 by Marc.Olano Random Number generators: fixed bug in TEA, added integer and float Blum-Blum-Shub. BBS is way cheaper for similar quality, suggest it for future use. Change 3030627 on 2016/06/28 by Ben.Woodhouse Fix for warning. CVar naming scope clash (doesn't appear to happen in vs2015). Change 3030809 on 2016/06/28 by Marc.Olano Noise shader function rename & perf improvement. Due to incorrect terminology in internet soruces, previous "Perlin" noise was not, in fact, Perlin noise. Now more accurately called "Value" noise. 6x perf improvement for value noise by changing random number function to BBS. Also updated instruction counts in UI tooltips. Change 3030850 on 2016/06/28 by Marc.Olano Rename & redirect noise material enums. At some point these got switched around and no longer accurately described the noise options the selected. Redirect, so all existing content will continue to work as-is. Updated UDN docs to match. Change 3030981 on 2016/06/28 by Rolando.Caloca DR - vk - More logging Change 3031056 on 2016/06/28 by Marc.Olano Introduce new pure-ALU gradient shader noise. Add noise samples to RenderTest map Change 3031398 on 2016/06/28 by Benjamin.Hyder updating TM-Shadermodels (correcting Mt Rushmore) Change 3031441 on 2016/06/28 by Marc.Olano Use only float version of BBS shader rand function for ES2 Change 3031463 on 2016/06/28 by John.Billon Fixed F4 changing the viewmode in Fortnite editor. The detailed lighting viewmode (detaillighting) named in DefaultInput.ini differed from the one in BaseInput.ini(lit_detaillighting). #Jira UE-32020 Change 3031512 on 2016/06/28 by Zabir.Hoque Relax clear flags for DX12 RHIs. Properly flush pending commands before residency is updated. Change 3031517 on 2016/06/28 by Rolando.Caloca DR - vk logging using r.Vulkan.DumpLayer Change 3032359 on 2016/06/29 by Allan.Bentham Fix mobile shadows crash. Change 3032431 on 2016/06/29 by Gil.Gribb Merging //UE4/Dev-Main@3032394 to Dev-Rendering (//UE4/Dev-Rendering) Change 3032757 on 2016/06/29 by Uriel.Doyon Fixed global mip bias being applied twice following integration with main. Change 3033121 on 2016/06/29 by Rolando.Caloca DR - vk - Logging Change 3033529 on 2016/06/29 by Daniel.Wright Null world guard on UReflectionCaptureComponent::ReadbackFromGPU Change 3033668 on 2016/06/29 by Uriel.Doyon Grouped texture streaming settings to simplify logic. New options "r.Streaming.UseAllMips" to ignores the different lod and cinematic bias #jira UE-32118 Change 3034403 on 2016/06/30 by Rolando.Caloca DR - Shorten dumped shader debug strings Change 3034475 on 2016/06/30 by Rolando.Caloca DR - Missing logging Change 3034722 on 2016/06/30 by Uriel.Doyon Improved StreamingAccuracy viewmodes with alpha test and translucent materials #jira UE-32656 Change 3034797 on 2016/06/30 by Rolando.Caloca DR - vk - 'fix' RHIClear but causes a CPU hang on AMD, so disabled again Change 3034799 on 2016/06/30 by Rolando.Caloca DR - vk - missed file Change 3034905 on 2016/06/30 by Rolando.Caloca DR - vk - Fix for render passes being reused with wrong dimensions Change 3035503 on 2016/07/01 by Simon.Tovey Async compute version of translucency lighting volume clear. Change 3035577 on 2016/07/01 by Marc.Olano Tiling noise. Adds tiling option for gradient, gradient texture, and value noise in the noise material node. Tiling is more expensive, but allows noise functions to be baked into a seamless repeating texture. Change 3035587 on 2016/07/01 by Ben.Woodhouse Fix for async SSAO bug (SSAO Async Compute results are used before the async job wait) #jira UE-32709 Change 3035618 on 2016/07/01 by Olaf.Piesche Asset fixes Change 3035692 on 2016/07/01 by Rolando.Caloca DR - vk - Deferred deletion queue Change 3035808 on 2016/07/01 by Rolando.Caloca DR - vk - Stat for deletion time, fixed some logging Change 3036012 on 2016/07/01 by John.Billon Alpha Coverage Preservation -Textures have a Alpha Preservation Vec4 property which dictates about much of that channel to preserve down the mip chain during mip generation. #Jira UE-31986 Change 3036041 on 2016/07/01 by Rolando.Caloca DR - vk - Fix for 32bit Change 3036433 on 2016/07/01 by Rolando.Caloca DR - More vk logging Change 3036935 on 2016/07/04 by Simon.Tovey Removing Data Objects Change 3036942 on 2016/07/04 by Ben.Woodhouse Fix for decal rendering resource leak The cause was that FD3D11BoundRenderTargets doesn't support setting RTs sparsely. So if one element is NULL, it won't release the ones after it. The sparse RT layout happened as a result of a change back in October, which meant that GBuffers for decals could be set sparsely, dependent on whether the decal wrote to the normalbuffer This change adds support for sparsely bound rendertargets in FD3D11BoundRenderTargets. #jira UE-32602 Change 3037563 on 2016/07/05 by Chris.Bunner HLOD self-shadowing in baked lighting fix. Change 3037640 on 2016/07/05 by Marcus.Wassmer Fix bug in USE_GPU_OVERWRITE_CHECKING Change 3037927 on 2016/07/05 by Rolando.Caloca DR - Fix touch pads not showing on Vulkan #jira UE-32062 Change 3038085 on 2016/07/05 by Chris.Bunner HLOD dynamic shadowing support. #jira UE-22627 Change 3038209 on 2016/07/05 by Rolando.Caloca DR - vk - Android compile fix Change 3038644 on 2016/07/05 by Uriel.Doyon Added LerpRange that allows to lerp between two rotators without taking the sortest path. Change 3038820 on 2016/07/05 by Uriel.Doyon Selecting streaming accuracy view modes will not automatically generate missing visualization data. Change 3039332 on 2016/07/06 by John.Billon -Made MaxGPUSkinBonesCvar a FAutoConsoleVariableRef and moved it to mesh utilitles from console manager to fix a thread initialization problem. #Jira UE-31710 Change 3039454 on 2016/07/06 by Simon.Tovey Moved all Niagara files from Engine and UnrealEd to remove dependancies and increase compile times. Niagara is now 99.999% decoupled from engine and editor so development should be much streamlined. Plus a few other edits to remove Curves/DataObjects that I missed in last CL. Change 3039517 on 2016/07/06 by Gil.Gribb Merging //UE4/Dev-Main@3039013 to Dev-Rendering (//UE4/Dev-Rendering) Change 3039587 on 2016/07/06 by Rolando.Caloca DR - vk logging, submit counter Change 3039603 on 2016/07/06 by Rolando.Caloca DR - Allow more samplers on GL4 #jira UE-32628 #jira UE-32744 Change 3039661 on 2016/07/06 by Daniel.Wright Fixed non-directional DFAO occlusion on specular 'r.AOSpecularOcclusionMode 0' Skylight occlusion tint now applies to specular Skylight occlusion tint on diffuse is now correctly affected by DiffuseColor Change 3039960 on 2016/07/06 by Daniel.Wright Forward renderer initial implementation * Point and spot lights are culled to a frustum space grid, base pass loops over culled lights. * Light culling uses a reverse linked list to avoid a per-cell limit, and the linked list is compacted to an array before the base pass. * New cvars to control light culling: r.Forward.MaxCulledLightsPerCell, r.Forward.LightGridSizeZ, r.Forward.LightGridPixelSize * A full Z Prepass is forced with forward shading. This allows deferred rendering before the base pass of shadow projection methods that only rely on depth. * Dynamic shadows are packed based on the assigned stationary light ShadowMapChannel, since stationary lights are already restricted to 4 overlapping. * GBuffer render targets are still allocated * Fixed several issues in parallax corrected base pass reflections - not blending out box shape, discontinuity in reflection vector, not blending with stationary skylight properly * Forward shading is now used for TLM_SurfacePerPixelLighting translucency in the deferred path * Notable missing features: shadowing of translucency, support for various translucency lighting modes, multiple blended reflection captures Change 3040050 on 2016/07/06 by Daniel.Wright Added r.Shadow.WholeSceneShadowCacheMb, which defaults to 150, to limit how much memory can be spent caching whole scene shadowmaps Change 3040160 on 2016/07/06 by Daniel.Wright Fixed tile artifacts in indirect capsule shadows from doing the scaled sphere vs tile bounding sphere intersection in the wrong space Change 3040163 on 2016/07/06 by Rolando.Caloca DR - vk - More logging Change 3040257 on 2016/07/06 by Daniel.Wright Skylights aren't captured until their level is made visible- fixes the case where skylights capture too early Change 3040316 on 2016/07/06 by Daniel.Wright PerObject shadows from point / spot lights do the light source pull back based on subject box size, not subject radius, since the box is used to find a valid < 90 degree projection. Fix from licensee Change 3040361 on 2016/07/06 by Daniel.Wright Fixed TexCreate_UAV being used on translucency volume textures in SM4 Change 3040402 on 2016/07/06 by Rolando.Caloca DR - vk - Make host mem accesses coherent Change 3040486 on 2016/07/06 by Daniel.Wright CIS fixes Change 3041028 on 2016/07/07 by Gil.Gribb Merging //UE4/Dev-Main@3040917 to Dev-Rendering (//UE4/Dev-Rendering) Change 3041235 on 2016/07/07 by Simon.Tovey Compile fix for FName conflict on UProperty (hopefully). Change 3041666 on 2016/07/07 by Daniel.Wright Fixed TLM_SurfacePerPixelLighting in SM4, falls back to lighting volume Change 3041731 on 2016/07/07 by Olaf.Piesche Adding Niagara to dynamically loaded module list; should fix UE-32915 Change 3042181 on 2016/07/07 by Daniel.Wright CIS fix [CL 3045471 by Gil Gribb in Main branch]
583 lines
19 KiB
Plaintext
583 lines
19 KiB
Plaintext
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
DeferredLightingCommon.usf: Common definitions for deferred lighting.
|
|
=============================================================================*/
|
|
|
|
#ifndef __DEFERRED_LIGHTING_COMMON__
|
|
#define __DEFERRED_LIGHTING_COMMON__
|
|
|
|
#include "DeferredShadingCommon.usf"
|
|
#include "DynamicLightingCommon.usf"
|
|
#include "BRDF.usf"
|
|
#include "MonteCarlo.usf"
|
|
#include "IESLightProfilesCommon.usf"
|
|
#include "ShadingModels.usf"
|
|
|
|
/**
|
|
* Data about a single light.
|
|
* Putting the light data in this struct allows the same lighting code to be used between standard deferred,
|
|
* Where many light properties are known at compile time, and tiled deferred, where all light properties have to be fetched from a buffer.
|
|
*/
|
|
struct FDeferredLightData
|
|
{
|
|
float4 LightPositionAndInvRadius;
|
|
float4 LightColorAndFalloffExponent;
|
|
float3 LightDirection;
|
|
float4 SpotAnglesAndSourceRadius;
|
|
float MinRoughness;
|
|
float ContactShadowLength;
|
|
float2 DistanceFadeMAD;
|
|
float4 ShadowMapChannelMask;
|
|
/** Whether to use inverse squared falloff. */
|
|
bool bInverseSquared;
|
|
/** Whether this is a light with radial attenuation, aka point or spot light. */
|
|
bool bRadialLight;
|
|
/** Whether this light needs spotlight attenuation. */
|
|
bool bSpotLight;
|
|
/** Whether the light should apply shadowing. */
|
|
uint ShadowedBits;
|
|
};
|
|
|
|
/** Data about a single light to be shaded with the simple shading model, designed for speed and limited feature set. */
|
|
struct FSimpleDeferredLightData
|
|
{
|
|
float4 LightPositionAndInvRadius;
|
|
float4 LightColorAndFalloffExponent;
|
|
/** Whether to use inverse squared falloff. */
|
|
bool bInverseSquared;
|
|
};
|
|
|
|
#ifdef THREADGROUP_SIZEX
|
|
#define REFERENCE_QUALITY 0
|
|
#else
|
|
#define REFERENCE_QUALITY 0
|
|
#endif
|
|
|
|
#undef LIGHT_SOURCE_SHAPE
|
|
#define LIGHT_SOURCE_SHAPE 1
|
|
|
|
#define LIGHT_SHAPE_SPHERE 1
|
|
#define LIGHT_SHAPE_RECT 2
|
|
|
|
static const uint LightSourceShape = LIGHT_SHAPE_SPHERE;
|
|
|
|
bool RayHitRect( float3 R, float3 RectCenter, float3 RectX, float3 RectY, float3 RectZ, float RectExtentX, float RectExtentY )
|
|
{
|
|
// Intersect ray with plane
|
|
float3 PointOnPlane = R * max( 0, dot( RectZ, RectCenter ) / dot( RectZ, R ) );
|
|
|
|
bool InExtentX = abs( dot( RectX, PointOnPlane - RectCenter ) ) <= RectExtentX;
|
|
bool InExtentY = abs( dot( RectY, PointOnPlane - RectCenter ) ) <= RectExtentY;
|
|
return InExtentX && InExtentY;
|
|
}
|
|
|
|
float3 SphereLightingMIS( FGBufferData GBuffer, FDeferredLightData LightData, float3 LobeRoughness, float3 ToLight, float3 V, float3 N, uint2 Random )
|
|
{
|
|
float3 Lighting = 0;
|
|
|
|
LobeRoughness = max( 0.08, LobeRoughness );
|
|
|
|
const float SourceRadius = max( 1, LightData.SpotAnglesAndSourceRadius.z );
|
|
|
|
const float DistanceSqr = dot( ToLight, ToLight );
|
|
const float3 ConeAxis = ToLight * rsqrt( DistanceSqr );
|
|
const float ConeCos = sqrt( 1 - Square( SourceRadius ) / DistanceSqr );
|
|
|
|
const float Area = PI * Square(SourceRadius);
|
|
const float SampleColor = 1.0 / Area;
|
|
|
|
const uint NumSets = 3;
|
|
const uint NumSamples[ NumSets ] =
|
|
{
|
|
0,
|
|
4,
|
|
4,
|
|
};
|
|
|
|
UNROLL
|
|
for( uint Set = 0; Set < NumSets; Set++ )
|
|
{
|
|
LOOP
|
|
for( uint i = 0; i < NumSamples[ Set ]; i++ )
|
|
{
|
|
float2 E = Hammersley( i, NumSamples[ Set ], Random );
|
|
//float2 E = CorrelatedMultiJitter2D( i, NumSamples[ Set ], Random.x * Random.y * (Set + 17) );
|
|
|
|
float3 L, H;
|
|
if( Set == 0 )
|
|
{
|
|
L = TangentToWorld( CosineSampleHemisphere( E ).xyz, N );
|
|
H = normalize(V + L);
|
|
}
|
|
else if( Set == 1 )
|
|
{
|
|
H = TangentToWorld( ImportanceSampleGGX( E, LobeRoughness[1] ).xyz, N );
|
|
L = 2 * dot( V, H ) * H - V;
|
|
}
|
|
else
|
|
{
|
|
L = TangentToWorld( UniformSampleCone( E, ConeCos ).xyz, ConeAxis );
|
|
H = normalize(V + L);
|
|
}
|
|
|
|
float NoL = saturate( dot(N, L) );
|
|
float NoH = saturate( dot(N, H) );
|
|
float VoH = saturate( dot(V, H) );
|
|
|
|
if( NoL > 0 && VoH > 0 )
|
|
{
|
|
BRANCH
|
|
if( Set != 2 && dot( L, ConeAxis ) < ConeCos )
|
|
{
|
|
// Ray misses sphere
|
|
continue;
|
|
}
|
|
|
|
float PDF[] =
|
|
{
|
|
NoL / PI,
|
|
D_GGX( LobeRoughness[1], NoH ) * NoH / (4 * VoH),
|
|
1.0 / ( 2 * PI * (1 - ConeCos) ),
|
|
};
|
|
|
|
// MIS balance heuristic
|
|
float InvWeight = 0;
|
|
UNROLL for( uint j = 0; j < NumSets; j++ )
|
|
{
|
|
InvWeight += PDF[j] * NumSamples[j];
|
|
}
|
|
float Weight = rcp( InvWeight );
|
|
|
|
float3 Shading = SurfaceShading( GBuffer, LobeRoughness, 1, L, V, N, 1, Random ) * NoL;
|
|
Shading += SubsurfaceShading( GBuffer, L, V, N, 1, Random );
|
|
|
|
Lighting += SampleColor * Shading * Weight;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Lighting;
|
|
}
|
|
|
|
// Find representative incoming light direction and energy modification
|
|
float3 AreaLightSpecular( FDeferredLightData LightData, inout float3 LobeRoughness, inout float3 ToLight, inout float3 L, float3 V, half3 N )
|
|
{
|
|
float3 LobeEnergy = 1;
|
|
|
|
LobeRoughness = max( LobeRoughness, LightData.MinRoughness );
|
|
float3 m = LobeRoughness * LobeRoughness;
|
|
|
|
const float SourceRadius = LightData.SpotAnglesAndSourceRadius.z;
|
|
const float SourceLength = LightData.SpotAnglesAndSourceRadius.w;
|
|
|
|
// TODO early out for point lights
|
|
|
|
float3 R = reflect( -V, N );
|
|
float InvDistToLight = rsqrt( dot( ToLight, ToLight ) );
|
|
|
|
// Point lobe in off-specular peak direction
|
|
float a = Square( LobeRoughness[1] );
|
|
R = lerp( N, R, (1 - a) * ( sqrt(1 - a) + a ) );
|
|
R = normalize( R );
|
|
|
|
BRANCH
|
|
if( SourceLength > 0 )
|
|
{
|
|
// Energy conservation
|
|
// asin(x) is angle to sphere, atan(x) is angle to disk, saturate(x) is free and in the middle
|
|
float LineAngle = saturate( SourceLength * InvDistToLight );
|
|
LobeEnergy *= m / saturate( m + 0.5 * LineAngle );
|
|
|
|
// Closest point on line segment to ray
|
|
float3 L01 = LightData.LightDirection * SourceLength;
|
|
float3 L0 = ToLight - 0.5 * L01;
|
|
float3 L1 = ToLight + 0.5 * L01;
|
|
|
|
#if 1
|
|
// Shortest distance
|
|
float a = Square( SourceLength );
|
|
float b = dot( R, L01 );
|
|
float t = saturate( dot( L0, b*R - L01 ) / (a - b*b) );
|
|
#else
|
|
// Smallest angle
|
|
float A = Square( SourceLength );
|
|
float B = 2 * dot( L0, L01 );
|
|
float C = dot( L0, L0 );
|
|
float D = dot( R, L0 );
|
|
float E = dot( R, L01 );
|
|
float t = saturate( (B*D - 2*C*E) / (B*E - 2*A*D) );
|
|
#endif
|
|
|
|
ToLight = L0 + t * L01;
|
|
}
|
|
|
|
BRANCH
|
|
if( SourceRadius > 0 )
|
|
{
|
|
// Energy conservation
|
|
// asin(x) is angle to sphere, atan(x) is angle to disk, saturate(x) is free and in the middle
|
|
float SphereAngle = saturate( SourceRadius * InvDistToLight );
|
|
LobeEnergy *= Square( m / saturate( m + 0.5 * SphereAngle ) );
|
|
|
|
// Closest point on sphere to ray
|
|
float3 ClosestPointOnRay = dot( ToLight, R ) * R;
|
|
float3 CenterToRay = ClosestPointOnRay - ToLight;
|
|
float3 ClosestPointOnSphere = ToLight + CenterToRay * saturate( SourceRadius * rsqrt( dot( CenterToRay, CenterToRay ) ) );
|
|
ToLight = ClosestPointOnSphere;
|
|
}
|
|
|
|
L = normalize( ToLight );
|
|
|
|
return LobeEnergy;
|
|
}
|
|
|
|
/** Returns 0 for positions closer than the fade near distance from the camera, and 1 for positions further than the fade far distance. */
|
|
float DistanceFromCameraFade(float SceneDepth, FDeferredLightData LightData, float3 WorldPosition, float3 CameraPosition)
|
|
{
|
|
// depth (non radial) based fading over distance
|
|
float Fade = saturate(SceneDepth * LightData.DistanceFadeMAD.x + LightData.DistanceFadeMAD.y);
|
|
return Fade * Fade;
|
|
}
|
|
|
|
void GetShadowTerms(FGBufferData GBuffer, FDeferredLightData LightData, float3 WorldPosition, float4 LightAttenuation, out float OpaqueShadowTerm, out float SSSShadowTerm)
|
|
{
|
|
// Remapping the light attenuation buffer (see ShadowRendering.cpp)
|
|
|
|
// LightAttenuation: Light function + per-object shadows in z, per-object SSS shadowing in w,
|
|
// Whole scene directional light shadows in x, whole scene directional light SSS shadows in y
|
|
// Get static shadowing from the appropriate GBuffer channel
|
|
float UsesStaticShadowMap = dot(LightData.ShadowMapChannelMask, float4(1, 1, 1, 1));
|
|
float StaticShadowing = lerp(1, dot(GBuffer.PrecomputedShadowFactors, LightData.ShadowMapChannelMask), UsesStaticShadowMap);
|
|
|
|
if (LightData.bRadialLight)
|
|
{
|
|
// Remapping the light attenuation buffer (see ShadowRendering.cpp)
|
|
|
|
OpaqueShadowTerm = LightAttenuation.z * StaticShadowing;
|
|
// SSS uses a separate shadowing term that allows light to penetrate the surface
|
|
//@todo - how to do static shadowing of SSS correctly?
|
|
SSSShadowTerm = LightAttenuation.w * StaticShadowing;
|
|
}
|
|
else
|
|
{
|
|
// Remapping the light attenuation buffer (see ShadowRendering.cpp)
|
|
// Also fix up the fade between dynamic and static shadows
|
|
// to work with plane splits rather than spheres.
|
|
|
|
float DynamicShadowFraction = DistanceFromCameraFade(GBuffer.Depth, LightData, WorldPosition, View.WorldCameraOrigin);
|
|
// For a directional light, fade between static shadowing and the whole scene dynamic shadowing based on distance + per object shadows
|
|
OpaqueShadowTerm = lerp(LightAttenuation.x, StaticShadowing, DynamicShadowFraction);
|
|
// Fade between SSS dynamic shadowing and static shadowing based on distance
|
|
SSSShadowTerm = min(lerp(LightAttenuation.y, StaticShadowing, DynamicShadowFraction), LightAttenuation.w);
|
|
|
|
// combine with light function
|
|
OpaqueShadowTerm *= LightAttenuation.z;
|
|
SSSShadowTerm *= LightAttenuation.z;
|
|
}
|
|
}
|
|
|
|
float ShadowRayCast(
|
|
float3 RayOriginTranslatedWorld, float3 RayDirection, float RayLength,
|
|
int NumSteps, float StepOffset
|
|
)
|
|
{
|
|
float4 RayStartClip = mul( float4( RayOriginTranslatedWorld, 1 ), View.TranslatedWorldToClip );
|
|
float4 RayDirClip = mul( float4( RayDirection * RayLength, 0 ), View.TranslatedWorldToClip );
|
|
float4 RayEndClip = RayStartClip + RayDirClip;
|
|
|
|
float3 RayStartScreen = RayStartClip.xyz / RayStartClip.w;
|
|
float3 RayEndScreen = RayEndClip.xyz / RayEndClip.w;
|
|
|
|
float3 RayStepScreen = RayEndScreen - RayStartScreen;
|
|
|
|
float3 RayStartUVz = float3( RayStartScreen.xy * View.ScreenPositionScaleBias.xy + View.ScreenPositionScaleBias.wz, RayStartScreen.z );
|
|
float3 RayStepUVz = float3( RayStepScreen.xy * View.ScreenPositionScaleBias.xy, RayStepScreen.z );
|
|
|
|
float4 RayDepthClip = RayStartClip + mul( float4( 0, 0, RayLength, 0 ), View.ViewToClip );
|
|
float3 RayDepthScreen = RayDepthClip.xyz / RayDepthClip.w;
|
|
|
|
const float Step = 1.0 / NumSteps;
|
|
|
|
// *2 to get less morie pattern in extreme cases, larger values make object appear not grounded in reflections
|
|
const float CompareTolerance = abs( RayDepthScreen.z - RayStartScreen.z ) * Step * 2;
|
|
|
|
float SampleTime = StepOffset * Step + Step;
|
|
|
|
float Coverage = 0;
|
|
|
|
UNROLL
|
|
for( int i = 0; i < NumSteps; i++ )
|
|
{
|
|
float3 SampleUVz = RayStartUVz + RayStepUVz * SampleTime;
|
|
float SampleDepth = SceneDepthTexture.SampleLevel( SceneDepthTextureSampler, SampleUVz.xy, 0 ).r;
|
|
|
|
float DepthDiff = SampleUVz.z - SampleDepth;
|
|
bool Hit = abs( DepthDiff + CompareTolerance ) < CompareTolerance;
|
|
|
|
Coverage += Hit ? 1.0 : 0.0;
|
|
|
|
SampleTime += Step;
|
|
}
|
|
|
|
float Shadow = Coverage > 0 ? 1 : 0;
|
|
|
|
// Off screen masking
|
|
float2 Vignette = saturate( abs( RayStartScreen.xy ) * 6 - 5 );
|
|
//Shadow *= saturate( 1.0 - dot( Vignette, Vignette ) );
|
|
|
|
return 1 - Shadow;
|
|
}
|
|
|
|
/** Calculates lighting for a given position, normal, etc with a fully featured lighting model designed for quality. */
|
|
float4 GetDynamicLighting(float3 WorldPosition, float3 CameraVector, FGBufferData GBuffer, float AmbientOcclusion, uint ShadingModelID, FDeferredLightData LightData, float4 LightAttenuation, uint2 Random)
|
|
{
|
|
FLightAccumulator LightAccumulator = (FLightAccumulator)0;
|
|
|
|
float3 V = -CameraVector;
|
|
float3 N = GBuffer.WorldNormal;
|
|
float3 ToLight = LightData.LightDirection;
|
|
float3 L = ToLight; // no need to normalize
|
|
float NoL = saturate( dot(N, L) );
|
|
float DistanceAttenuation = 1;
|
|
float LightRadiusMask = 1;
|
|
float SpotFalloff = 1;
|
|
|
|
if (LightData.bRadialLight)
|
|
{
|
|
ToLight = LightData.LightPositionAndInvRadius.xyz - WorldPosition;
|
|
|
|
float DistanceSqr = dot( ToLight, ToLight );
|
|
L = ToLight * rsqrt( DistanceSqr );
|
|
|
|
if (LightData.bInverseSquared)
|
|
{
|
|
const float SourceRadius = LightData.SpotAnglesAndSourceRadius.z;
|
|
const float SourceLength = LightData.SpotAnglesAndSourceRadius.w;
|
|
|
|
BRANCH
|
|
if( SourceLength > 0 )
|
|
{
|
|
// Line segment irradiance
|
|
float3 L01 = LightData.LightDirection * SourceLength;
|
|
float3 ToLight0 = ToLight - 0.5 * L01;
|
|
float3 ToLight1 = ToLight + 0.5 * L01;
|
|
|
|
float LengthSqr0 = dot( ToLight0, ToLight0 );
|
|
float LengthSqr1 = dot( ToLight1, ToLight1 );
|
|
float rLength0 = rsqrt( LengthSqr0 );
|
|
float rLength1 = rsqrt( LengthSqr1 );
|
|
float Length0 = LengthSqr0 * rLength0;
|
|
float Length1 = LengthSqr1 * rLength1;
|
|
|
|
DistanceAttenuation = rcp( ( Length0 * Length1 + dot( ToLight0, ToLight1 ) ) * 0.5 + 1 );
|
|
NoL = saturate( 0.5 * ( dot(N, ToLight0) * rLength0 + dot(N, ToLight1) * rLength1 ) );
|
|
}
|
|
else
|
|
{
|
|
DistanceAttenuation = rcp( DistanceSqr + 1 );
|
|
NoL = saturate( dot( N, L ) );
|
|
|
|
if( SourceRadius > 0 )
|
|
{
|
|
#if 1 //HORIZON
|
|
NoL = dot( N, L );
|
|
|
|
float SinAlphaSqr = saturate( Square( SourceRadius ) / DistanceSqr );
|
|
float SinAlpha = sqrt( SinAlphaSqr );
|
|
|
|
if( NoL < SinAlpha )
|
|
{
|
|
#if 0
|
|
// Accurate sphere irradiance
|
|
float CosBeta = NoL;
|
|
float SinBeta = sqrt( 1 - CosBeta * CosBeta );
|
|
float TanBeta = SinBeta / CosBeta;
|
|
|
|
float x = sqrt( 1 / SinAlphaSqr - 1 );
|
|
float y = -x / TanBeta;
|
|
float z = SinBeta * sqrt(1 - y*y);
|
|
|
|
DistanceAttenuation = SinAlphaSqr * ( NoL * acos(y) - x * z ) + atan( z / x );
|
|
DistanceAttenuation /= PI * Square( SourceRadius );
|
|
NoL = 1;
|
|
#else
|
|
// Hermite spline approximation
|
|
// Fairly accurate with SinAlpha < 0.8
|
|
// y=0 and dy/dx=0 at -SinAlpha
|
|
// y=SinAlpha and dy/dx=1 at SinAlpha
|
|
NoL = max( NoL, -SinAlpha );
|
|
NoL = Square( SinAlpha + NoL ) / ( 4 * SinAlpha );
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// TODO optimize
|
|
LightRadiusMask = Square( saturate( 1 - Square( DistanceSqr * Square(LightData.LightPositionAndInvRadius.w) ) ) );
|
|
}
|
|
else
|
|
{
|
|
DistanceAttenuation = 1;
|
|
NoL = saturate( dot( N, L ) );
|
|
|
|
LightRadiusMask = RadialAttenuation(ToLight * LightData.LightPositionAndInvRadius.w, LightData.LightColorAndFalloffExponent.w);
|
|
|
|
#if REFERENCE_QUALITY
|
|
// anti Area
|
|
LightRadiusMask *= DistanceSqr + 1;
|
|
#endif
|
|
}
|
|
|
|
if (LightData.bSpotLight)
|
|
{
|
|
SpotFalloff = SpotAttenuation(L, -LightData.LightDirection, LightData.SpotAnglesAndSourceRadius.xy);
|
|
}
|
|
}
|
|
|
|
LightAccumulator.EstimatedCost += 0.3f; // running the PixelShader at all has a cost
|
|
|
|
BRANCH
|
|
if (LightRadiusMask > 0 && SpotFalloff > 0)
|
|
{
|
|
float SurfaceShadow = 1;
|
|
float SubsurfaceShadow = 1;
|
|
|
|
BRANCH
|
|
if (LightData.ShadowedBits)
|
|
{
|
|
GetShadowTerms(GBuffer, LightData, WorldPosition, LightAttenuation, SurfaceShadow, SubsurfaceShadow);
|
|
|
|
// greatly reduces shadow mapping artifacts
|
|
// Commented out because it reduces character shading quality.
|
|
//SurfaceShadow *= saturate(dot(N, L) * 6 - 0.2);
|
|
|
|
#ifndef THREADGROUP_SIZEX
|
|
BRANCH
|
|
if( LightData.ShadowedBits > 1 && LightData.ContactShadowLength > 0 )
|
|
{
|
|
uint FrameRandom = View.StateFrameIndexMod8 * 1551;
|
|
|
|
float StepOffset = float( Random.x & 0xffff ) / (1<<16);
|
|
StepOffset -= 0.5;
|
|
|
|
float Shadow = ShadowRayCast( WorldPosition + View.PreViewTranslation, L, LightData.ContactShadowLength * GBuffer.Depth, 8, StepOffset );
|
|
|
|
SurfaceShadow *= Shadow;
|
|
//SubsurfaceShadow *= Shadow;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
SurfaceShadow = AmbientOcclusion;
|
|
}
|
|
|
|
#ifndef THREADGROUP_SIZEX
|
|
BRANCH
|
|
if( LightData.ShadowedBits < 2 && GBuffer.ShadingModelID == SHADINGMODELID_HAIR )
|
|
{
|
|
uint FrameRandom = View.StateFrameIndexMod8 * 1551;
|
|
|
|
float StepOffset = float( Random.x & 0xffff ) / (1<<16);
|
|
StepOffset -= 0.5;
|
|
|
|
SubsurfaceShadow = ShadowRayCast( WorldPosition + View.PreViewTranslation, L, 0.1 * GBuffer.Depth, 8, StepOffset );
|
|
}
|
|
#endif
|
|
|
|
float SurfaceAttenuation = (DistanceAttenuation * LightRadiusMask * SpotFalloff) * SurfaceShadow;
|
|
float SubsurfaceAttenuation = (DistanceAttenuation * LightRadiusMask * SpotFalloff) * SubsurfaceShadow;
|
|
|
|
LightAccumulator.EstimatedCost += 0.3f; // add the cost of getting the shadow terms
|
|
|
|
{
|
|
const float3 LightColor = LightData.LightColorAndFalloffExponent.rgb;
|
|
|
|
const float ClearCoatRoughness = GBuffer.CustomData.y;
|
|
|
|
float3 LobeRoughness = float3(ClearCoatRoughness, GBuffer.Roughness, 1);
|
|
|
|
#if REFERENCE_QUALITY
|
|
float LightMask = LightRadiusMask * SpotFalloff * SurfaceShadow;
|
|
LightAccumulator_Add( LightAccumulator, SphereLightingMIS( GBuffer, LightData, LobeRoughness, ToLight, V, N, Random ), 0, LightColor * LightMask );
|
|
#else
|
|
float3 LobeEnergy = AreaLightSpecular(LightData, LobeRoughness, ToLight, L, V, N);
|
|
|
|
// accumulate diffuse and specular
|
|
{
|
|
#if 1 // for testing if there is a perf impact
|
|
// correct screen space subsurface scattering
|
|
float3 SurfaceLightingDiff = SurfaceShading(GBuffer, LobeRoughness, LobeEnergy, L, V, N, float2(1, 0), Random);
|
|
float3 SurfaceLightingSpec = SurfaceShading(GBuffer, LobeRoughness, LobeEnergy, L, V, N, float2(0, 1), Random);
|
|
LightAccumulator_Add(LightAccumulator, SurfaceLightingDiff, SurfaceLightingSpec, LightColor * (NoL * SurfaceAttenuation));
|
|
//LightAccumulator_Add(LightAccumulator, SurfaceLightingDiff, SurfaceLightingSpec, LightColor * (SurfaceAttenuation));
|
|
#else
|
|
// wrong screen space subsurface scattering but potentially faster
|
|
float3 SurfaceLighting = SurfaceShading(GBuffer, LobeRoughness, LobeEnergy, L, V, N, float2(1, 1), Random);
|
|
LightAccumulator_Add(LightAccumulator, SurfaceLighting, 0, LightColor * (NoL * SurfaceAttenuation));
|
|
#endif
|
|
}
|
|
|
|
// accumulate subsurface
|
|
{
|
|
float3 SubsurfaceLighting = SubsurfaceShading(GBuffer, L, V, N, SubsurfaceShadow, Random);
|
|
|
|
LightAccumulator_Add(LightAccumulator, SubsurfaceLighting, 0, LightColor * SubsurfaceAttenuation);
|
|
|
|
LightAccumulator.EstimatedCost += 0.4f; // add the cost of the lighting computations (should sum up to 1 form one light)
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return LightAccumulator_GetResult(LightAccumulator);
|
|
}
|
|
|
|
/**
|
|
* Calculates lighting for a given position, normal, etc with a simple lighting model designed for speed.
|
|
* All lights rendered through this method are unshadowed point lights with no shadowing or light function or IES.
|
|
* A cheap specular is used instead of the more correct area specular, no fresnel.
|
|
*/
|
|
float3 GetSimpleDynamicLighting(float3 WorldPosition, float3 CameraVector, FScreenSpaceData ScreenSpaceData, FSimpleDeferredLightData LightData)
|
|
{
|
|
float3 V = -CameraVector;
|
|
float3 N = ScreenSpaceData.GBuffer.WorldNormal;
|
|
float3 ToLight = LightData.LightPositionAndInvRadius.xyz - WorldPosition;
|
|
float DistanceAttenuation = 1;
|
|
|
|
float DistanceSqr = dot( ToLight, ToLight );
|
|
float3 L = ToLight * rsqrt( DistanceSqr );
|
|
float NoL = saturate( dot( N, L ) );
|
|
|
|
if (LightData.bInverseSquared)
|
|
{
|
|
// Sphere falloff (technically just 1/d2 but this avoids inf)
|
|
DistanceAttenuation = 1 / ( DistanceSqr + 1 );
|
|
|
|
float LightRadiusMask = Square( saturate( 1 - Square( DistanceSqr * Square(LightData.LightPositionAndInvRadius.w) ) ) );
|
|
DistanceAttenuation *= LightRadiusMask;
|
|
}
|
|
else
|
|
{
|
|
DistanceAttenuation = RadialAttenuation(ToLight * LightData.LightPositionAndInvRadius.w, LightData.LightColorAndFalloffExponent.w);
|
|
}
|
|
|
|
float3 OutLighting = 0;
|
|
|
|
BRANCH
|
|
if (DistanceAttenuation > 0)
|
|
{
|
|
const float3 LightColor = LightData.LightColorAndFalloffExponent.rgb;
|
|
|
|
// Apply SSAO to the direct lighting since we're not going to have any other shadowing
|
|
float Attenuation = DistanceAttenuation * ScreenSpaceData.AmbientOcclusion;
|
|
|
|
OutLighting += LightColor * (NoL * Attenuation) * SimpleShading( ScreenSpaceData.GBuffer.DiffuseColor, ScreenSpaceData.GBuffer.SpecularColor, ScreenSpaceData.GBuffer.Roughness, L, V, N );
|
|
}
|
|
|
|
return OutLighting;
|
|
}
|
|
|
|
#endif |