You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
485 lines
12 KiB
Plaintext
485 lines
12 KiB
Plaintext
//-----------------------------------------------------------------------------
|
|
// File: LPVFinalPass.usf
|
|
//
|
|
// Summary: (SHADER HEADER) LPV Final pass functionality
|
|
//
|
|
// Created: 2013-03-01
|
|
//
|
|
// Author: mailto:benwood@microsoft.com
|
|
//
|
|
// Copyright (C) Microsoft. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Copyright 2013 Lionhead Studios
|
|
// mailto:benwood@microsoft.com
|
|
|
|
/*------------------------------------------------------------------------------
|
|
Compile time parameters:
|
|
------------------------------------------------------------------------------*/
|
|
|
|
#ifndef LPV_FINAL_PASS_USF
|
|
#define LPV_FINAL_PASS_USF
|
|
|
|
#include "LPVCommon.usf"
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
#define REFLECTION_RAY_LENGTH_DEFAULT 2.0
|
|
|
|
#define SHOW_GRID 0
|
|
#define DEBUG_WEIGHTS 0
|
|
|
|
// Indirect strength
|
|
#define INDIRECT_LEVEL ( 0.00375 * REFINE_LIGHTING_MULTIPLIER )
|
|
#define INDIRECT_SPECULAR_LEVEL 1.0
|
|
#define INDIRECT_DIFFUSE_LEVEL 0.333
|
|
|
|
#define INDIRECT_DIFFUSE 1
|
|
#define INDIRECT_SPECULAR 1
|
|
|
|
// Filtering modes
|
|
#define FILTER_NEAREST 0
|
|
#define FILTER_TETRA 1 // Interpolate using tetrahedrons (4 points instead of 8)
|
|
#define FILTER_TRILINEAR 2
|
|
#define FILTER_HARDWARE_TRILINEAR 3 // Use hardware volume texture filtering
|
|
|
|
// Filtering settings
|
|
#if LPV_VOLUME_TEXTURE
|
|
#define DIFFUSE_FILTER FILTER_HARDWARE_TRILINEAR
|
|
#define SPECULAR_FILTER FILTER_HARDWARE_TRILINEAR
|
|
#else
|
|
#ifndef DIFFUSE_FILTER
|
|
#define DIFFUSE_FILTER FILTER_TRILINEAR
|
|
#endif
|
|
|
|
#ifndef SPECULAR_FILTER
|
|
#define SPECULAR_FILTER FILTER_TRILINEAR
|
|
#endif
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
void GetGridIndicesAndWeightsTetra( float3 gridPos, out int indices[4], out float weights[4] )
|
|
{
|
|
// gridPos.y+=0.43;
|
|
const float3 gridOffset[8] =
|
|
{
|
|
float3( -0.5f, -0.5f, -0.5f ), // c1
|
|
float3( -0.5f, -0.5f, 0.5f ),
|
|
float3( -0.5f, 0.5f, -0.5f ),
|
|
float3( -0.5f, 0.5f, 0.5f ), // c0
|
|
float3( 0.5f, -0.5f, -0.5f ),
|
|
float3( 0.5f, -0.5f, 0.5f ), // c3
|
|
float3( 0.5f, 0.5f, -0.5f ), // c2
|
|
float3( 0.5f, 0.5f, 0.5f ),
|
|
};
|
|
|
|
int cubeIndices[8];
|
|
// Get cube indices
|
|
[unroll]
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
int3 ui = int3( gridPos + gridOffset[i] );
|
|
ui %= 32;
|
|
cubeIndices[i] = GetGridAddress( ui );//ui.z*32*32 + ui.y*32 + ui.x;
|
|
}
|
|
|
|
|
|
// Get the position in cube space
|
|
// Where cube is space is nearest 2x2x2 cells, with origin at 0,0,0
|
|
int3 cubeOriginI = int3( gridPos-float3(0.5f,0.5f,0.5f) );
|
|
|
|
float3 cubeOrigin = float3(cubeOriginI)+0.5;
|
|
float3 cubePos = ( gridPos - cubeOrigin );
|
|
|
|
int3 align = int3( LpvRead.mLpvGridOffset ) % 2;
|
|
|
|
|
|
float3 flip2 = ( (cubeOriginI + align ) % 2 ) * -2 + 1;
|
|
|
|
// Classification
|
|
uint tetra = 4;
|
|
const float3 tips[4] =
|
|
{
|
|
float3( 0,1,0 ),
|
|
float3( 0,0,1 ),
|
|
float3( 1,0,0 ),
|
|
float3( 1,1,1 ),
|
|
};
|
|
|
|
float3 weights3 = 0;
|
|
if ( flip2.x < 0 ) cubePos.x = 1-cubePos.x;
|
|
if ( flip2.y < 0 ) cubePos.y = 1-cubePos.y;
|
|
if ( flip2.z < 0 ) cubePos.z = 1-cubePos.z;
|
|
|
|
[unroll]
|
|
for ( uint i=0; i<4; i++ )
|
|
{
|
|
float3 tip = tips[i];
|
|
float3 d = abs(cubePos-tip);
|
|
float mDist = d.x+d.y+d.z;
|
|
if ( mDist <= 1.0f ) tetra=i;
|
|
}
|
|
|
|
if ( tetra<4 )
|
|
{
|
|
float3 r4 = tips[tetra];
|
|
float3 diagMat = 1.0f - r4 * 2.0f;
|
|
float3 rMinusR4 = cubePos - r4;
|
|
weights3 = rMinusR4*diagMat;
|
|
|
|
// compute the 4 tetra vert positions
|
|
if ( flip2.x< 0 ) r4.x=1-r4.x;
|
|
if ( flip2.y< 0 ) r4.y=1-r4.y;
|
|
if ( flip2.z< 0 ) r4.z=1-r4.z;
|
|
int3 r4i = int3(r4);
|
|
int3 p[4];
|
|
p[0] = int3(1-r4i.x,r4i.y,r4i.z);
|
|
p[1] = int3(r4i.x,1-r4i.y,r4i.z);
|
|
p[2] = int3(r4i.x,r4i.y,1-r4i.z);
|
|
p[3] = r4i;
|
|
|
|
[unroll]
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
int3 ui = ( cubeOriginI + p[i] ) % 32;
|
|
indices[i] = GetGridAddress( ui );//ui.z*32*32 + ui.y*32 + ui.x;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float3 centreR4 = float3( 1, 0, 1 );
|
|
|
|
// Inverse of tetrahedron matrix for the centre tetrahedron
|
|
const float3 centreM1 = float3( -0.5, 0.5, 0.5 );
|
|
const float3 centreM2 = float3( -0.5,-0.5,-0.5 );
|
|
const float3 centreM3 = float3( 0.5, 0.5,-0.5 );
|
|
|
|
float3 rMinusR4 = cubePos - centreR4;
|
|
weights3.x = dot( centreM1, rMinusR4 );
|
|
weights3.y = dot( centreM2, rMinusR4 );
|
|
weights3.z = dot( centreM3, rMinusR4 );
|
|
|
|
// compute the 4 tetra vert positions
|
|
//int3 r4i = int3(centreR4);
|
|
int3 r1i = int3(0,1,1);
|
|
|
|
if ( flip2.x< 0 ) r1i.x=1-r1i.x;
|
|
if ( flip2.y< 0 ) r1i.y=1-r1i.y;
|
|
if ( flip2.z< 0 ) r1i.z=1-r1i.z;
|
|
|
|
int3 p[4];
|
|
p[0] = r1i;
|
|
p[1] = int3(r1i.x,1-r1i.y,1-r1i.z);
|
|
p[2] = int3(1-r1i.x,r1i.y,1-r1i.z);
|
|
p[3] = int3(1-r1i.x,1-r1i.y,r1i.z);
|
|
|
|
[unroll]
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
int3 ui = ( cubeOriginI + p[i] ) % 32;
|
|
indices[i] = GetGridAddress( ui );//ui.z*32*32 + ui.y*32 + ui.x;
|
|
}
|
|
}
|
|
|
|
weights[0] = weights3.x;
|
|
weights[1] = weights3.y;
|
|
weights[2] = weights3.z;
|
|
weights[3] = 1.0f-(weights3.x+weights3.y+weights3.z);
|
|
|
|
#if DEBUG_WEIGHTS
|
|
float3 colour = 0;
|
|
float3 colours[9] =
|
|
{
|
|
float3(1,0,0), // float3( -0.5f, -0.5f, -0.5f ), // c1
|
|
float3(0,1,0), // float3( -0.5f, -0.5f, 0.5f ),
|
|
float3(0,0,1), // float3( -0.5f, 0.5f, -0.5f ),
|
|
float3(1,1,0), // float3( -0.5f, 0.5f, 0.5f ), // c0
|
|
float3(0,2,2), // float3( 0.5f, -0.5f, -0.5f ),
|
|
float3(1,0,1), // float3( 0.5f, -0.5f, 0.5f ), // c3
|
|
float3(0,0,0), // float3( 0.5f, 0.5f, -0.5f ), // c2
|
|
float3(8,0.5,0.5), // float3( 0.5f, 0.5f, 0.5f ),
|
|
float3(10,0,0), // Invalid (very bright red!)
|
|
};
|
|
|
|
for ( int i=0;i<8; i++ )
|
|
{
|
|
LPVCell cell = ReadLpvCell( cubeIndices[i] );
|
|
colours[i] = cell.coeffs[0];
|
|
|
|
//int3 ui = int3( gridPos + gridOffset[i] );
|
|
//colours[i] = ( ( float3(ui) * 10 ) % 32 ) / 32;
|
|
|
|
int idx = cubeIndices[i];
|
|
|
|
int ix = idx % 32;
|
|
int iy = ( idx / 32 ) % 32;
|
|
int iz = ( idx / (32*32) ) % 32;
|
|
|
|
colours[i] = 0;
|
|
if ( ix == 16 && iy == 15 && iz == 16 ) colours[i] = float3(1,0,0);
|
|
|
|
int3 cp = int3(gridPos);//cubeOrigin-0.5;
|
|
if ( cp.x == 16 && cp.y == 15 && cp.z == 16 ) colours[i].b+=1;
|
|
}
|
|
|
|
for ( int i=0; i<4; i++ )
|
|
{
|
|
// Find the cube index
|
|
int cubeIndex = 8;
|
|
for ( int j=0; j<8; j++ )
|
|
{
|
|
if ( indices[i] == cubeIndices[j] )
|
|
{
|
|
cubeIndex = j;
|
|
break;
|
|
}
|
|
}
|
|
colour += colours[ cubeIndex ] * weights[i];
|
|
}
|
|
colour/=4.0;
|
|
|
|
//cubePos = 1-cubePos;
|
|
if ( flip2.x < 0 ) cubePos.x = 1-cubePos.x;
|
|
if ( flip2.y < 0 ) cubePos.y = 1-cubePos.y;
|
|
if ( flip2.z < 0 ) cubePos.z = 1-cubePos.z;
|
|
if ( cubePos.x < 0.0125 || cubePos.y < 0.0125 || cubePos.z < 0.0125 )
|
|
{
|
|
colour = 0.5;
|
|
}
|
|
|
|
//colour = ( ( cubeOrigin * 10 ) % 32 ) / 32;
|
|
weights[0] = colour.x;
|
|
weights[1] = colour.y;
|
|
weights[2] = colour.z;
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
void GetGridIndicesAndWeights( float3 gridPos, out int indices[8], out float weights[8] )
|
|
{
|
|
const float3 gridOffset[8] =
|
|
{
|
|
float3( -0.5f, -0.5f, -0.5f ),
|
|
float3( -0.5f, -0.5f, 0.5f ),
|
|
float3( -0.5f, 0.5f, -0.5f ),
|
|
float3( -0.5f, 0.5f, 0.5f ),
|
|
float3( 0.5f, -0.5f, -0.5f ),
|
|
float3( 0.5f, -0.5f, 0.5f ),
|
|
float3( 0.5f, 0.5f, -0.5f ),
|
|
float3( 0.5f, 0.5f, 0.5f ),
|
|
};
|
|
|
|
// Get indices
|
|
[unroll]
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
int3 ui = int3( gridPos+gridOffset[i] );
|
|
float maxExtent = MaxGridExtent( ui );
|
|
if ( maxExtent > 15.5 )
|
|
indices[i] = -1;
|
|
else
|
|
indices[i] = GetGridAddress( ui );//ui.z*32*32 + ui.y*32 + ui.x;
|
|
}
|
|
|
|
// Get weights
|
|
float3 baseTexelPos = floor( gridPos-0.5 ) + 0.5;
|
|
float3 texPos = gridPos-baseTexelPos; // Pos relative to bottom-left texel centre
|
|
|
|
float3 minVal = 1.0f-texPos;
|
|
float3 maxVal = texPos;
|
|
weights[0] = minVal.x * minVal.y * minVal.z;
|
|
weights[1] = minVal.x * minVal.y * maxVal.z;
|
|
weights[2] = minVal.x * maxVal.y * minVal.z;
|
|
weights[3] = minVal.x * maxVal.y * maxVal.z;
|
|
weights[4] = maxVal.x * minVal.y * minVal.z;
|
|
weights[5] = maxVal.x * minVal.y * maxVal.z;
|
|
weights[6] = maxVal.x * maxVal.y * minVal.z;
|
|
weights[7] = maxVal.x * maxVal.y * maxVal.z;
|
|
|
|
#if 0
|
|
[unroll]
|
|
for ( int i=0; i<8; i++ )
|
|
{
|
|
weights[i] *= weights[i];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
float3 DebugGridColour( float3 gridPos, float3 originalColour )
|
|
{
|
|
float3 cubePos = frac( gridPos + 0.5 );
|
|
float3 colour = saturate( ( 0.015 - cubePos ) * 10000 );
|
|
|
|
float3 cubePos2 = frac( gridPos );
|
|
float3 colour2 = saturate( ( 0.01 - cubePos2 ) * 10000 );
|
|
colour2 = ( colour2 * 0.05) + dot( colour2, colour2 ).xxx * 0.1;
|
|
|
|
colour += colour2;
|
|
|
|
|
|
if ( dot( colour,colour ) > 0.0 )
|
|
{
|
|
return colour * 8 + originalColour * 0.5;
|
|
}
|
|
return originalColour;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
LPVCell LPVGetCellNearest( float3 worldPos )
|
|
{
|
|
int gridIndex = GetGridIndex( worldPos );
|
|
return ReadLpvCell( gridIndex );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
LPVCell LPVGetCellTetra( float3 worldPos )
|
|
{
|
|
float3 colour = 0;
|
|
|
|
float3 gridPos = WorldToGrid( worldPos );
|
|
|
|
const int n = 4;
|
|
int indices[4];
|
|
float weights[4];
|
|
GetGridIndicesAndWeightsTetra( gridPos, indices, weights );
|
|
|
|
#if DEBUG_WEIGHTS
|
|
return float3(weights[0],weights[1],weights[2]);
|
|
#endif
|
|
LPVCell accumCell;
|
|
ClearCell( accumCell );
|
|
|
|
[unroll]
|
|
for ( int i=0; i<n; i++ )
|
|
{
|
|
// Decompress the cell and apply the weight
|
|
LPVCell cell = ReadLpvCell( indices[i] );
|
|
MultiplyCell( cell, weights[i] );
|
|
AddCell( accumCell, cell );
|
|
}
|
|
|
|
return accumCell;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
LPVCell LPVGetCellTrilinear( float3 worldPos )
|
|
{
|
|
float3 colour = 0;
|
|
|
|
float3 gridPos = WorldToGrid( worldPos );
|
|
|
|
const int n = 8;
|
|
int indices[8];
|
|
float weights[8];
|
|
GetGridIndicesAndWeights( gridPos, indices, weights );
|
|
|
|
#if DEBUG_WEIGHTS
|
|
return float3(weights[0],weights[1],weights[2]);
|
|
#endif
|
|
|
|
LPVCell accumCell;
|
|
ClearCell( accumCell );
|
|
|
|
[unroll]
|
|
for ( int i=0; i<n; i++ )
|
|
{
|
|
// Decompress the cell and apply the weight
|
|
LPVCell cell = ReadLpvCell( indices[i] );
|
|
|
|
MultiplyCell( cell, weights[i] );
|
|
AddCell( accumCell, cell );
|
|
}
|
|
|
|
return accumCell;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
#if LPV_VOLUME_TEXTURE
|
|
LPVCell LPVGetCellHardwareTrilinear( float3 worldPos )
|
|
{
|
|
float3 colour = 0;
|
|
|
|
float3 gridPos = WorldToGrid( worldPos );
|
|
|
|
return ReadLpvCellVolumeTextureFiltered( gridPos );
|
|
}
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
LPVCell LPVGetCell( float3 worldPos )
|
|
{
|
|
#if ( DIFFUSE_FILTER == FILTER_TETRA )
|
|
return LPVGetCellTetra( worldPos );
|
|
#elif ( DIFFUSE_FILTER == FILTER_NEAREST )
|
|
return LPVGetCellNearest( worldPos );
|
|
#elif ( DIFFUSE_FILTER == FILTER_TRILINEAR )
|
|
return LPVGetCellTrilinear( worldPos );
|
|
#elif ( DIFFUSE_FILTER == FILTER_HARDWARE_TRILINEAR )
|
|
return LPVGetCellHardwareTrilinear( worldPos );
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
|
|
float3 LPVSpecular( float3 worldPos, float3 reflectionVec, float rOffsetLength )
|
|
{
|
|
#if !INDIRECT_SPECULAR
|
|
return 0;
|
|
#endif
|
|
|
|
LPVCell Cell = LPVGetCell( worldPos + reflectionVec * rOffsetLength * LpvRead.LpvScale );
|
|
|
|
float3 Colour = LPVCellLookup( Cell, reflectionVec ) * INDIRECT_LEVEL * INDIRECT_SPECULAR_LEVEL;
|
|
|
|
#if SHOW_GRID
|
|
Colour = DebugGridColour( WorldToGrid( worldPos ), colour );
|
|
#endif
|
|
|
|
return Colour;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
float3 LPVSpecular( float3 worldPos, float3 reflectionVec )
|
|
{
|
|
return LPVSpecular( worldPos, reflectionVec, REFLECTION_RAY_LENGTH_DEFAULT );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
float3 LPVLookup( float3 worldPos, float3 normal )
|
|
{
|
|
#if !INDIRECT_DIFFUSE
|
|
return 0;
|
|
#endif
|
|
|
|
LPVCell Cell = LPVGetCell( worldPos );
|
|
|
|
float3 Colour = LPVCellLookup( Cell, normal ) * INDIRECT_LEVEL * INDIRECT_DIFFUSE_LEVEL;
|
|
|
|
return Colour;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
void LPVGetDiffuseAndSpecular( float3 worldPos, float3 normal, float3 reflectionVec, out float3 diffuseOut, out float3 specularOut )
|
|
{
|
|
// TODO: could implement optimised ref lookup by using SH from diffuse for reflection
|
|
|
|
diffuseOut = LPVLookup( worldPos, normal ) ;
|
|
specularOut = LPVSpecular( worldPos, reflectionVec ) ;
|
|
}
|
|
|
|
#endif
|