You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* reduced order of SH (faster but a bit more blurry) * DirectionalOcclusion (disabled by default, can be enabled in PostProcessSettings, affects SkyLight and ReflectionEnvironments but not AmbientCube) * Material BlockGI feature * Spotlight support * Uses AsyncCompute on XboxOne as optimization (order is not optimized yet) [CL 2553823 by Martin Mittring in Main branch]
149 lines
4.5 KiB
Plaintext
149 lines
4.5 KiB
Plaintext
//-----------------------------------------------------------------------------
|
|
// File: LPVDirectLightInject.usf
|
|
//
|
|
// Summary: Compute shaders for injecting light directly into an LPV
|
|
// without using an RSM
|
|
//
|
|
// Created: 2013-03-01
|
|
//
|
|
// Author: mailto:benwood@microsoft.com
|
|
//
|
|
// Copyright (C) Microsoft. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Compile time parameters:
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#include "Common.usf"
|
|
#include "LpvWriteVplCommon.usf"
|
|
#include "LPVGeometryVolumeCommon.usf"
|
|
#include "DeferredLightingCommon.usf"
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
#define DIRECT_LIGHT_INJECTION_STRENGTH 200.0f
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
float ComputeAttenuation( float3 WorldPosition )
|
|
{
|
|
float3 ToLight = LpvInject.LightPosition - WorldPosition;
|
|
float DistanceSqr = dot( ToLight, ToLight );
|
|
float3 L = ToLight * rsqrt( DistanceSqr );
|
|
float Attenuation = 1.0f;
|
|
|
|
if (LpvInject.bLightInverseSquaredAttenuation > 0.0f )
|
|
{
|
|
// @TODO: From DeferredLightingCommon.usf GetDynamicLighting() - could refactor to avoid duplication
|
|
BRANCH
|
|
if( LpvInject.LightSourceLength > 0 )
|
|
{
|
|
// Line segment irradiance
|
|
float3 L01 = LpvInject.LightDirection * LpvInject.LightSourceLength;
|
|
float3 L0 = ToLight - 0.5 * L01;
|
|
float3 L1 = ToLight + 0.5 * L01;
|
|
Attenuation = rcp( ( length( L0 ) * length( L1 ) + dot( L0, L1 ) ) * 0.5 + 1 );
|
|
}
|
|
else
|
|
{
|
|
// Sphere irradiance (technically just 1/d^2 but this avoids inf)
|
|
Attenuation = 1 / ( DistanceSqr + 1 );
|
|
}
|
|
Attenuation *= Square( saturate( 1 - Square( DistanceSqr * Square(1.0f/LpvInject.LightRadius) ) ) );
|
|
}
|
|
else
|
|
{
|
|
Attenuation = RadialAttenuation( ToLight/LpvInject.LightRadius, LpvInject.LightFalloffExponent );
|
|
}
|
|
|
|
#if SPOT_ATTENUATION
|
|
Attenuation *= SpotAttenuation(L, -LpvInject.LightDirection, LpvInject.LightSpotAngles);
|
|
#endif
|
|
|
|
return Attenuation;
|
|
}
|
|
|
|
[numthreads(4,4,4)]
|
|
void CSLightInject_ListGenCS(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID )
|
|
{
|
|
int index = GetGridAddress( DTid );
|
|
|
|
// TODO: optimise this. Don't read/write unless we need to. Requires read/write access to UAV, which requires
|
|
// aliasing for the textures...
|
|
LPVCell cell = ReadLpvCell( index );
|
|
|
|
float3 GridPosition = float3( DTid );
|
|
|
|
float3 LightPos = LpvInject.LightPosition;
|
|
|
|
float3 WorldPosition = GridToWorld( GridPosition+0.5 );
|
|
float3 LightVector = float3( LightPos-WorldPosition );
|
|
|
|
float len = length( LightVector );
|
|
if ( len < LpvInject.LightRadius )
|
|
{
|
|
int gvOffset = 0;
|
|
|
|
// Gv is at a half cell offset to the LPV. Offset GV Lookup based on Light direction to avoid bias artifacts
|
|
const int xStride = 1;
|
|
const int yStride = 32;
|
|
const int zStride = 32*32;
|
|
if ( LightVector.x < 0 ) gvOffset += xStride;
|
|
if ( LightVector.y < 0 ) gvOffset += yStride;
|
|
if ( LightVector.z < 0 ) gvOffset += zStride;
|
|
|
|
int gvIndex = index + gvOffset;
|
|
GeometryVolumeEntry gvCell = ReadGvCell( gvIndex );
|
|
|
|
if ( gvCell.SH[0] > 0.1f )
|
|
{
|
|
float3 LightDirection = LightVector/len;
|
|
|
|
// TODO: Not ideal for thin walls! Use SH directly rather than approximating the normal?
|
|
float3 normal = -GvGetDominantDirectionApprox( gvCell );
|
|
|
|
float nDotL = saturate( dot( normal, LightDirection ) );
|
|
|
|
if ( nDotL > 0.0f )
|
|
{
|
|
float distance = len;
|
|
float shadowValue = 1.0f;
|
|
#if SHADOW_CASTING
|
|
//TODO: Could use shadow map to avoid artifacts with shadow casters outside the LPV volume
|
|
if ( distance > 100.0f )
|
|
{
|
|
float3 inc = LightVector / 16.0f;
|
|
|
|
float3 pos = WorldPosition + inc*2;
|
|
|
|
for ( int i=0; i<15; i++ )
|
|
{
|
|
int traceGvIndex = GetGridIndex( pos ) + gvOffset;
|
|
GeometryVolumeEntry sCell = ReadGvCell( traceGvIndex );
|
|
|
|
float s = 1-SHLookupGeometryVolume( sCell, -LightDirection );
|
|
|
|
shadowValue = min( shadowValue, s );
|
|
pos+=inc;
|
|
}
|
|
shadowValue = saturate( shadowValue );
|
|
}
|
|
#endif
|
|
|
|
float3 flux = LpvInject.LightColor * gvCell.color * DIRECT_LIGHT_INJECTION_STRENGTH;
|
|
|
|
float Attenuation = ComputeAttenuation( WorldPosition );
|
|
Attenuation *= nDotL*shadowValue;
|
|
flux *= Attenuation;
|
|
|
|
WorldPosition += normal * LpvWrite.VplInjectionBias;
|
|
|
|
float solidAngle = 3.14;
|
|
AccumulateLighting( flux, -normal, solidAngle, cell );
|
|
}
|
|
}
|
|
}
|
|
WriteLpvCell( cell, index );
|
|
}
|