Files
UnrealEngineUWP/Engine/Shaders/LPVWriteVplCommon.usf
Daniel Wright 1464dcf2c3 Distance field AO using a surface cache
* Provides mid-range stable AO for dynamic rigid meshes
* Movable sky lights are now supported, and distance field AO is used for shadowing Movable sky lighting from dynamic scenes
* Static meshes are preprocessed into signed distance field volumes at mesh build time when the r.AllowMeshDistanceFieldRepresentations project setting is enabled
* Non-uniform scaling does not work with this method (mirroring is fine), animating through world position offset also causes artifacts as the two representations diverge
* Occlusion is computed along cones to reduce over-shadowing, object distance fields are operated on directly (no hierarchy) to obtain enough resolution to prevent leaking, visibility traces are done with cone stepping to allow better parallelization, and shading is done adaptively in space and time using the surface cache.

[CL 2093556 by Daniel Wright in Main branch]
2014-06-03 15:53:13 -04:00

87 lines
2.8 KiB
Plaintext

//-----------------------------------------------------------------------------
// File: LPVWriteVPLCommmon.usf
//
// Summary: Common functionality for LPV vpl list write
//
// Created: 2013-03-01
//
// Author: mailto:benwood@microsoft.com
//
// Copyright (C) Microsoft. All rights reserved.
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
#include "LPVWriteCommon.usf"
//-------------------------------------------------------------------------------------------------
RWStructuredBuffer<VplListEntry> RWGvListBuffer; // 0
RWByteAddressBuffer RWGvListHeadBuffer; // 1
RWStructuredBuffer<VplListEntry> RWVplListBuffer; // 2
RWByteAddressBuffer RWVplListHeadBuffer; // 3
//-------------------------------------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------------------------------------
int AddToVplList( float3 worldPos, float3 flux, float3 direction, const bool emissiveInjection )
{
int gridIndex = GetGridIndex( worldPos );
[branch]
if ( gridIndex >= 0 )
{
// Allocate a new list entry
uint newHeadIndex = RWVplListBuffer.IncrementCounter();
uint oldHeadIndex;
RWVplListHeadBuffer.InterlockedExchange( gridIndex*4, newHeadIndex, oldHeadIndex );
if ( emissiveInjection )
{
// Weight according to projected texel size 1 / N dot L
float nDotL = abs( dot( LpvWrite.GeometryVolumeCaptureLightDirection.xyz, direction ) );
nDotL = max( nDotL, 0.25f ); // Clamp to prevent divBy0 and and general weirdness due to undersampling
flux *= 1.0f / nDotL;
}
// Fill in the new list node
Vpl vpl;
vpl.normal = direction;
vpl.flux = flux;
VplListEntry listNode = PackVpl( vpl );
listNode.nextIndex = oldHeadIndex;
RWVplListBuffer[ newHeadIndex ] = listNode;
}
return gridIndex;
}
//-------------------------------------------------------------------------------------------------
int AddToGvList( float3 worldPos, float3 flux, float3 direction )
{
// Gv is offset by half
float3 offset = ( LpvWrite.LpvScale * 0.5f ).xxx;
int gridIndex = GetGridIndex( worldPos + offset );
[branch]
if ( gridIndex >= 0 )
{
// Allocate a new list entry
uint newHeadIndex = RWGvListBuffer.IncrementCounter();
uint oldHeadIndex;
RWGvListHeadBuffer.InterlockedExchange( gridIndex*4, newHeadIndex, oldHeadIndex );
// Fill in the new list node
Vpl vpl;
vpl.normal = direction;
vpl.flux = flux;
VplListEntry listNode = PackVpl( vpl );
listNode.nextIndex = oldHeadIndex;
RWGvListBuffer[ newHeadIndex ] = listNode;
}
return gridIndex;
}
//-------------------------------------------------------------------------------------------------