Evgenii Golubev
8 年前
当前提交
f85c5fe4
共有 30 个文件被更改,包括 1943 次插入 和 662 次删除
-
2Assets/ScriptableRenderLoop/HDRenderLoop/Editor/HDRenderLoopInspector.cs
-
2Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.asset.meta
-
327Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs
-
2Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/LightDefinition.cs
-
2Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.cs
-
10Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/lightlistbuild.compute
-
413Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs
-
21Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs.hlsl
-
8Assets/ScriptableRenderLoop/HDRenderLoop/Material/LayeredLit/LayeredLit.shader
-
16Assets/ScriptableRenderLoop/HDRenderLoop/Sky/Resources/SkyHDRI.shader
-
4Assets/ScriptableRenderLoop/RenderPasses/ShadowRenderPass.cs
-
10Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl
-
8Assets/ScriptableRenderLoop/fptl/FptlLighting.cs
-
208Assets/TestScenes/HDTest/GlobalIlluminationTest.unity
-
259Assets/TestScenes/HDTest/Material/HDRenderLoopMaterials/Gray.mat
-
12Assets/TestScenes/HDTest/Material/HDRenderLoopMaterials/Layered/Layered.mat
-
2Assets/TestScenes/HDTest/Material/HDRenderLoopMaterials/Layered/Layered.mat.meta
-
90Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/ClusteredUtils.hlsl
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/ClusteredUtils.hlsl.meta
-
267Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/lightlistbuild-bigtile.compute
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/lightlistbuild-bigtile.compute.meta
-
553Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/lightlistbuild-clustered.compute
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/lightlistbuild-clustered.compute.meta
-
30Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/ShaderBase.hlsl
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/ShaderBase.hlsl.meta
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Shaders.meta
-
185Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyRenderer.cs
-
12Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyRenderer.cs.meta
-
105Assets/ScriptableRenderLoop/HDRenderLoop/Utilities.cs
-
12Assets/ScriptableRenderLoop/HDRenderLoop/Utilities.cs.meta
|
|||
fileFormatVersion: 2 |
|||
guid: 2400b74f5ce370c4481e5dc417d03703 |
|||
timeCreated: 1479395301 |
|||
timeCreated: 1479691644 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
userData: |
|
|||
fileFormatVersion: 2 |
|||
guid: 6e7fa39a7d1b15c4184c9f51d86eba22 |
|||
timeCreated: 1479298680 |
|||
timeCreated: 1479379836 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
userData: '{"GUIDArray":["01fa3be727161d249a81ad7065c15459","3acf8f156d29e494e8cd196462d1a17c","62b3c923bc540b94a803550e9927936a","c569253e641dc934db7c3595b31890da"]}' |
|
|||
#ifndef __CLUSTEREDUTILS_H__ |
|||
#define __CLUSTEREDUTILS_H__ |
|||
|
|||
#ifndef FLT_EPSILON |
|||
#define FLT_EPSILON 1.192092896e-07f |
|||
#endif |
|||
|
|||
float GetScaleFromBase(float base) |
|||
{ |
|||
const float C = (float)(1 << g_iLog2NumClusters); |
|||
const float geomSeries = (1.0 - pow(base, C)) / (1 - base); // geometric series: sum_k=0^{C-1} base^k |
|||
return geomSeries / (g_fFarPlane - g_fNearPlane); |
|||
} |
|||
|
|||
int SnapToClusterIdxFlex(float z_in, float suggestedBase, bool logBasePerTile) |
|||
{ |
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float z = z_in; |
|||
#else |
|||
float z = -z_in; |
|||
#endif |
|||
|
|||
float userscale = g_fClustScale; |
|||
if (logBasePerTile) |
|||
userscale = GetScaleFromBase(suggestedBase); |
|||
|
|||
// using the inverse of the geometric series |
|||
const float dist = max(0, z - g_fNearPlane); |
|||
return (int)clamp(log2(dist * userscale * (suggestedBase - 1.0f) + 1) / log2(suggestedBase), 0.0, (float)((1 << g_iLog2NumClusters) - 1)); |
|||
} |
|||
|
|||
int SnapToClusterIdx(float z_in, float suggestedBase) |
|||
{ |
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
bool logBasePerTile = true; // resolved compile time |
|||
#else |
|||
bool logBasePerTile = false; |
|||
#endif |
|||
|
|||
return SnapToClusterIdxFlex(z_in, suggestedBase, logBasePerTile); |
|||
} |
|||
|
|||
float ClusterIdxToZFlex(int k, float suggestedBase, bool logBasePerTile) |
|||
{ |
|||
float res; |
|||
|
|||
float userscale = g_fClustScale; |
|||
if (logBasePerTile) |
|||
userscale = GetScaleFromBase(suggestedBase); |
|||
|
|||
float dist = (pow(suggestedBase, (float)k) - 1.0) / (userscale * (suggestedBase - 1.0f)); |
|||
res = dist + g_fNearPlane; |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
return res; |
|||
#else |
|||
return -res; |
|||
#endif |
|||
} |
|||
|
|||
float ClusterIdxToZ(int k, float suggestedBase) |
|||
{ |
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
bool logBasePerTile = true; // resolved compile time |
|||
#else |
|||
bool logBasePerTile = false; |
|||
#endif |
|||
|
|||
return ClusterIdxToZFlex(k, suggestedBase, logBasePerTile); |
|||
} |
|||
|
|||
// generate a log-base value such that half of the clusters are consumed from near plane to max. opaque depth of tile. |
|||
float SuggestLogBase50(float tileFarPlane) |
|||
{ |
|||
const float C = (float)(1 << g_iLog2NumClusters); |
|||
float normDist = clamp((tileFarPlane - g_fNearPlane) / (g_fFarPlane - g_fNearPlane), FLT_EPSILON, 1.0); |
|||
float suggested_base = pow((1.0 + sqrt(max(0.0, 1.0 - 4.0 * normDist * (1.0 - normDist)))) / (2.0 * normDist), 2.0 / C); // |
|||
return max(g_fClustBase, suggested_base); |
|||
} |
|||
|
|||
// generate a log-base value such that (approximately) a quarter of the clusters are consumed from near plane to max. opaque depth of tile. |
|||
float SuggestLogBase25(float tileFarPlane) |
|||
{ |
|||
const float C = (float)(1 << g_iLog2NumClusters); |
|||
float normDist = clamp((tileFarPlane - g_fNearPlane) / (g_fFarPlane - g_fNearPlane), FLT_EPSILON, 1.0); |
|||
float suggested_base = pow((1 / 2.3) * max(0.0, (0.8 / normDist) - 1), 4.0 / (C * 2)); // approximate inverse of d*x^4 + (-x) + (1-d) = 0 - d is normalized distance |
|||
return max(g_fClustBase, suggested_base); |
|||
} |
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 54f8006db9236c148af831b7fcaadc0c |
|||
timeCreated: 1479691314 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#pragma kernel BigTileLightListGen |
|||
|
|||
#include "../TilePass.cs.hlsl" |
|||
#include "../LightingConvexHullUtils.hlsl" |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
#include "../SortingComputeUtils.hlsl" |
|||
#endif |
|||
|
|||
#define EXACT_EDGE_TESTS |
|||
#define PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
|
|||
#define MAX_NR_BIGTILE_LIGHTS (MAX_NR_BIGTILE_LIGHTS_PLUSONE-1) |
|||
|
|||
|
|||
uniform int g_iNrVisibLights; |
|||
uniform uint2 g_viDimensions; |
|||
uniform float4x4 g_mInvScrProjection; |
|||
uniform float4x4 g_mScrProjection; |
|||
uniform float g_fNearPlane; |
|||
uniform float g_fFarPlane; |
|||
|
|||
StructuredBuffer<float3> g_vBoundsBuffer : register( t1 ); |
|||
StructuredBuffer<SFiniteLightData> g_vLightData : register( t2 ); |
|||
StructuredBuffer<SFiniteLightBound> g_data : register( t3 ); |
|||
|
|||
|
|||
#define NR_THREADS 64 |
|||
|
|||
// output buffer |
|||
RWBuffer<uint> g_vLightList : register( u0 ); |
|||
|
|||
|
|||
// 2kB (room for roughly 30 wavefronts) |
|||
groupshared unsigned int lightsListLDS[MAX_NR_BIGTILE_LIGHTS_PLUSONE]; |
|||
groupshared uint lightOffs; |
|||
|
|||
|
|||
float GetLinearDepth(float zDptBufSpace) // 0 is near 1 is far |
|||
{ |
|||
float3 vP = float3(0.0f,0.0f,zDptBufSpace); |
|||
float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
return v4Pres.z / v4Pres.w; |
|||
} |
|||
|
|||
|
|||
float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth) |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fCx = g_mScrProjection[0].z; |
|||
float fSy = g_mScrProjection[1].y; |
|||
float fCy = g_mScrProjection[1].z; |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
return fLinDepth*float3( ((v2ScrPos.x-fCx)/fSx), ((v2ScrPos.y-fCy)/fSy), 1.0 ); |
|||
#else |
|||
return fLinDepth*float3( -((v2ScrPos.x+fCx)/fSx), -((v2ScrPos.y+fCy)/fSy), 1.0 ); |
|||
#endif |
|||
} |
|||
|
|||
float GetOnePixDiagWorldDistAtDepthOne() |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fSy = g_mScrProjection[1].y; |
|||
|
|||
return length( float2(1.0/fSx,1.0/fSy) ); |
|||
} |
|||
|
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
void SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate); |
|||
#endif |
|||
|
|||
#ifdef EXACT_EDGE_TESTS |
|||
void CullByExactEdgeTests(uint threadID, int iNrCoarseLights, uint2 viTilLL, uint2 viTilUR); |
|||
#endif |
|||
|
|||
|
|||
|
|||
|
|||
[numthreads(NR_THREADS, 1, 1)] |
|||
void BigTileLightListGen(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) |
|||
{ |
|||
uint2 tileIDX = u3GroupID.xy; |
|||
uint t=threadID; |
|||
|
|||
uint iWidth = g_viDimensions.x; |
|||
uint iHeight = g_viDimensions.y; |
|||
uint nrBigTilesX = (iWidth+63)/64; |
|||
uint nrBigTilesY = (iHeight+63)/64; |
|||
|
|||
if(t==0) lightOffs = 0; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
|
|||
uint2 viTilLL = 64*tileIDX; |
|||
uint2 viTilUR = min( viTilLL+uint2(64,64), uint2(iWidth, iHeight) ); // not width and height minus 1 since viTilUR represents the end of the tile corner. |
|||
|
|||
float2 vTileLL = float2(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight); |
|||
float2 vTileUR = float2(viTilUR.x/(float) iWidth, viTilUR.y/(float) iHeight); |
|||
|
|||
// build coarse list using AABB |
|||
for(int l=(int) t; l<(int) g_iNrVisibLights; l += NR_THREADS) |
|||
{ |
|||
const float2 vMi = g_vBoundsBuffer[l].xy; |
|||
const float2 vMa = g_vBoundsBuffer[l+g_iNrVisibLights].xy; |
|||
|
|||
if( all(vMa>vTileLL) && all(vMi<vTileUR)) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffs, uInc, uIndex); |
|||
if(uIndex<MAX_NR_BIGTILE_LIGHTS) lightsListLDS[uIndex] = l; // add to light list |
|||
} |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
int iNrCoarseLights = min(lightOffs,MAX_NR_BIGTILE_LIGHTS); |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
SphericalIntersectionTests( t, iNrCoarseLights, float2(min(viTilLL.xy+uint2(64/2,64/2), uint2(iWidth-1, iHeight-1))) ); |
|||
#endif |
|||
|
|||
#ifdef EXACT_EDGE_TESTS |
|||
CullByExactEdgeTests(t, iNrCoarseLights, viTilLL.xy, viTilUR.xy); |
|||
#endif |
|||
|
|||
|
|||
// sort lights |
|||
SORTLIST(lightsListLDS, iNrCoarseLights, MAX_NR_BIGTILE_LIGHTS_PLUSONE, t, NR_THREADS); |
|||
|
|||
lightOffs = 0; |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
for(int i=t; i<iNrCoarseLights; i+=NR_THREADS) if(lightsListLDS[i]<g_iNrVisibLights) InterlockedAdd(lightOffs, 1); |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
iNrCoarseLights = lightOffs; |
|||
|
|||
int offs = tileIDX.y*nrBigTilesX + tileIDX.x; |
|||
|
|||
for(int i=t; i<(iNrCoarseLights+1); i+=NR_THREADS) |
|||
g_vLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*offs + i] = t==0 ? iNrCoarseLights : lightsListLDS[i-1]; |
|||
} |
|||
|
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
void SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate) |
|||
{ |
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, 1.0); |
|||
#else |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, -1.0); |
|||
#endif |
|||
|
|||
float onePixDiagDist = GetOnePixDiagWorldDistAtDepthOne(); |
|||
float halfTileSizeAtZDistOne = 32*onePixDiagDist; // scale by half a tile |
|||
|
|||
for(int l=threadID; l<iNrCoarseLights; l+=NR_THREADS) |
|||
{ |
|||
SFiniteLightBound lgtDat = g_data[lightsListLDS[l]]; |
|||
|
|||
if( !DoesSphereOverlapTile(V, halfTileSizeAtZDistOne, lgtDat.center.xyz, lgtDat.radius) ) |
|||
lightsListLDS[l]=0xffffffff; |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
} |
|||
#endif |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
#ifdef EXACT_EDGE_TESTS |
|||
float3 GetTileVertex(uint2 viTilLL, uint2 viTilUR, int i, float fTileFarPlane) |
|||
{ |
|||
float x = (i&1)==0 ? viTilLL.x : viTilUR.x; |
|||
float y = (i&2)==0 ? viTilLL.y : viTilUR.y; |
|||
float z = (i&4)==0 ? g_fNearPlane : fTileFarPlane; |
|||
#if !USE_LEFTHAND_CAMERASPACE |
|||
z = -z; |
|||
#endif |
|||
return GetViewPosFromLinDepth( float2(x, y), z); |
|||
} |
|||
|
|||
void GetFrustEdge(out float3 vP0, out float3 vE0, const int e0, uint2 viTilLL, uint2 viTilUR, float fTileFarPlane) |
|||
{ |
|||
int iSection = e0>>2; // section 0 is side edges, section 1 is near edges and section 2 is far edges |
|||
int iSwizzle = e0&0x3; |
|||
|
|||
int i=iSwizzle + (2*(iSection&0x2)); // offset by 4 at section 2 |
|||
vP0 = GetTileVertex(uint2(viTilLL.x, viTilUR.y), uint2(viTilUR.x, viTilLL.y), i, fTileFarPlane); |
|||
vE0 = iSection==0 ? vP0 : (((iSwizzle&0x2)==0 ? 1.0f : (-1.0f))*((iSwizzle&0x1)==(iSwizzle>>1) ? float3(1,0,0) : float3(0,1,0))); |
|||
} |
|||
|
|||
void CullByExactEdgeTests(uint threadID, int iNrCoarseLights, uint2 viTilLL, uint2 viTilUR) |
|||
{ |
|||
const bool bOnlyNeedFrustumSideEdges = true; |
|||
const int nrFrustEdges = bOnlyNeedFrustumSideEdges ? 4 : 8; // max 8 since we never need to test 4 far edges of frustum since they are identical vectors to near edges and plane is placed at vP0 on light hull. |
|||
|
|||
const int totNrEdgePairs = 12*nrFrustEdges; |
|||
for(int l=0; l<iNrCoarseLights; l++) |
|||
{ |
|||
const int idxCoarse = lightsListLDS[l]; |
|||
[branch]if(idxCoarse<(uint) g_iNrVisibLights && g_vLightData[idxCoarse].lightType!=SPHERE_LIGHT) // don't bother doing edge tests for sphere lights since these have camera aligned bboxes. |
|||
{ |
|||
SFiniteLightBound lgtDat = g_data[idxCoarse]; |
|||
|
|||
const float3 boxX = lgtDat.boxAxisX.xyz; |
|||
const float3 boxY = lgtDat.boxAxisY.xyz; |
|||
const float3 boxZ = -lgtDat.boxAxisZ.xyz; // flip axis (so it points away from the light direction for a spot-light) |
|||
const float3 center = lgtDat.center.xyz; |
|||
const float2 scaleXY = lgtDat.scaleXY; |
|||
|
|||
for(int i=threadID; i<totNrEdgePairs; i+=NR_THREADS) |
|||
{ |
|||
int e0 = (int) (((uint)i)/((uint) nrFrustEdges)); // should become a shift right |
|||
int e1 = i - e0*nrFrustEdges; |
|||
|
|||
int idx_cur=0, idx_twin=0; |
|||
float3 vP0, vE0; |
|||
GetHullEdge(idx_cur, idx_twin, vP0, vE0, e0, boxX, boxY, boxZ, center, scaleXY); |
|||
|
|||
|
|||
float3 vP1, vE1; |
|||
GetFrustEdge(vP1, vE1, e1, viTilLL, viTilUR, g_fFarPlane); |
|||
|
|||
// potential separation plane |
|||
float3 vN = cross(vE0, vE1); |
|||
|
|||
int positive=0, negative=0; |
|||
for(int k=1; k<8; k++) // only need to test 7 verts (technically just 6). |
|||
{ |
|||
int j = (idx_cur+k)&0x7; |
|||
float3 vPh = GetHullVertex(boxX, boxY, boxZ, center, scaleXY, j); |
|||
float fSignDist = idx_twin==j ? 0.0 : dot(vN, vPh-vP0); |
|||
if(fSignDist>0) ++positive; else if(fSignDist<0) ++negative; |
|||
} |
|||
int resh = (positive>0 && negative>0) ? 0 : (positive>0 ? 1 : (negative>0 ? (-1) : 0)); |
|||
|
|||
positive=0; negative=0; |
|||
for(int j=0; j<8; j++) |
|||
{ |
|||
float3 vPf = GetTileVertex(viTilLL, viTilUR, j, g_fFarPlane); |
|||
float fSignDist = dot(vN, vPf-vP0); |
|||
if(fSignDist>0) ++positive; else if(fSignDist<0) ++negative; |
|||
} |
|||
int resf = (positive>0 && negative>0) ? 0 : (positive>0 ? 1 : (negative>0 ? (-1) : 0)); |
|||
|
|||
bool bFoundSepPlane = (resh*resf)<0; |
|||
if(bFoundSepPlane) lightsListLDS[l]=0xffffffff; |
|||
} |
|||
} |
|||
} |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
} |
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 5ee1f9d6e09abe045b2f5e0b784b9072 |
|||
timeCreated: 1479689024 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 4 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#pragma kernel TileLightListGen_NoDepthRT LIGHTLISTGEN=TileLightListGen_NoDepthRT |
|||
#pragma kernel TileLightListGen_DepthRT LIGHTLISTGEN=TileLightListGen_DepthRT ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
#pragma kernel TileLightListGen_DepthRT_MSAA LIGHTLISTGEN=TileLightListGen_DepthRT_MSAA ENABLE_DEPTH_TEXTURE_BACKPLANE MSAA_ENABLED |
|||
#pragma kernel TileLightListGen_NoDepthRT_SrcBigTile LIGHTLISTGEN=TileLightListGen_NoDepthRT_SrcBigTile USE_TWO_PASS_TILED_LIGHTING |
|||
#pragma kernel TileLightListGen_DepthRT_SrcBigTile LIGHTLISTGEN=TileLightListGen_DepthRT_SrcBigTile ENABLE_DEPTH_TEXTURE_BACKPLANE USE_TWO_PASS_TILED_LIGHTING |
|||
#pragma kernel TileLightListGen_DepthRT_MSAA_SrcBigTile LIGHTLISTGEN=TileLightListGen_DepthRT_MSAA_SrcBigTile ENABLE_DEPTH_TEXTURE_BACKPLANE MSAA_ENABLED USE_TWO_PASS_TILED_LIGHTING |
|||
#pragma kernel ClearAtomic |
|||
|
|||
#include "../ShaderBase.hlsl" |
|||
#include "../TilePass.cs.hlsl" |
|||
#include "../LightingConvexHullUtils.hlsl" |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
#include "../SortingComputeUtils.hlsl" |
|||
#endif |
|||
|
|||
|
|||
//#define EXACT_EDGE_TESTS |
|||
#define PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
#define CONV_HULL_TEST_ENABLED |
|||
|
|||
uniform int g_iNrVisibLights; |
|||
uniform float4x4 g_mInvScrProjection; |
|||
uniform float4x4 g_mScrProjection; |
|||
|
|||
uniform float g_fClustScale; |
|||
uniform float g_fClustBase; |
|||
uniform float g_fNearPlane; |
|||
uniform float g_fFarPlane; |
|||
uniform int g_iLog2NumClusters; // numClusters = (1<<g_iLog2NumClusters) |
|||
|
|||
#include "../ClusteredUtils.hlsl" |
|||
|
|||
|
|||
#ifdef MSAA_ENABLED |
|||
Texture2DMS<float> g_depth_tex : register( t0 ); |
|||
#else |
|||
Texture2D g_depth_tex : register( t0 ); |
|||
#endif |
|||
StructuredBuffer<float3> g_vBoundsBuffer : register( t1 ); |
|||
StructuredBuffer<SFiniteLightData> g_vLightData : register( t2 ); |
|||
StructuredBuffer<SFiniteLightBound> g_data : register( t3 ); |
|||
|
|||
#ifdef USE_TWO_PASS_TILED_LIGHTING |
|||
Buffer<uint> g_vBigTileLightList : register( t4 ); |
|||
#endif |
|||
|
|||
|
|||
#define NR_THREADS 64 |
|||
|
|||
// output buffer |
|||
RWBuffer<uint> g_vLayeredLightList : register( u0 ); |
|||
RWBuffer<uint> g_LayeredOffset : register( u1 ); |
|||
RWBuffer<uint> g_LayeredSingleIdxBuffer : register( u2 ); |
|||
|
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
RWBuffer<float> g_logBaseBuffer : register( u3 ); |
|||
#endif |
|||
|
|||
|
|||
#define MAX_NR_COARSE_ENTRIES 128 |
|||
|
|||
groupshared unsigned int coarseList[MAX_NR_COARSE_ENTRIES]; |
|||
groupshared unsigned int clusterIdxs[MAX_NR_COARSE_ENTRIES/2]; |
|||
groupshared float4 lightPlanes[4*6]; |
|||
|
|||
groupshared uint lightOffs; |
|||
|
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
groupshared int ldsZMax; |
|||
#endif |
|||
|
|||
#ifdef EXACT_EDGE_TESTS |
|||
groupshared uint ldsIsLightInvisible; |
|||
groupshared uint lightOffs2; |
|||
#endif |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
groupshared uint lightOffsSph; |
|||
#endif |
|||
|
|||
|
|||
float GetLinearDepth(float zDptBufSpace) // 0 is near 1 is far |
|||
{ |
|||
float3 vP = float3(0.0f,0.0f,zDptBufSpace); |
|||
float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
return v4Pres.z / v4Pres.w; |
|||
} |
|||
|
|||
|
|||
float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth) |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fCx = g_mScrProjection[0].z; |
|||
float fSy = g_mScrProjection[1].y; |
|||
float fCy = g_mScrProjection[1].z; |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
return fLinDepth*float3( ((v2ScrPos.x-fCx)/fSx), ((v2ScrPos.y-fCy)/fSy), 1.0 ); |
|||
#else |
|||
return fLinDepth*float3( -((v2ScrPos.x+fCx)/fSx), -((v2ScrPos.y+fCy)/fSy), 1.0 ); |
|||
#endif |
|||
} |
|||
|
|||
float GetOnePixDiagWorldDistAtDepthOne() |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fSy = g_mScrProjection[1].y; |
|||
|
|||
return length( float2(1.0/fSx,1.0/fSy) ); |
|||
} |
|||
|
|||
#ifdef EXACT_EDGE_TESTS |
|||
int CullByExactEdgeTests(uint threadID, int iNrCoarseLights, uint2 viTilLL, uint2 viTilUR, float fTileFarPlane); |
|||
#endif |
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate); |
|||
#endif |
|||
|
|||
|
|||
// returns 1 for intersection and 0 for none |
|||
|
|||
float4 FetchPlane(int l, int p); |
|||
|
|||
|
|||
bool CheckIntersection(int l, int k, uint2 viTilLL, uint2 viTilUR, float suggestedBase) |
|||
{ |
|||
unsigned int val = (clusterIdxs[l>>1]>>(16*(l&1)))&0xffff; |
|||
bool bIsHit = ((val>>0)&0xff)<=((uint) k) && ((uint) k)<=((val>>8)&0xff); |
|||
if(bIsHit) |
|||
{ |
|||
#ifdef CONV_HULL_TEST_ENABLED |
|||
float depthAtNearZ = ClusterIdxToZ(k, suggestedBase); |
|||
float depthAtFarZ = ClusterIdxToZ(k+1, suggestedBase); |
|||
|
|||
for(int p=0; p<6; p++) |
|||
{ |
|||
float4 plane = lightPlanes[6*(l&3)+p]; |
|||
|
|||
bool bAllInvisib = true; |
|||
|
|||
for(int i=0; i<8; i++) |
|||
{ |
|||
float x = (i&1)==0 ? viTilLL.x : viTilUR.x; |
|||
float y = (i&2)==0 ? viTilLL.y : viTilUR.y; |
|||
float z = (i&4)==0 ? depthAtNearZ : depthAtFarZ; |
|||
float3 vP = GetViewPosFromLinDepth( float2(x, y), z); |
|||
|
|||
bAllInvisib = bAllInvisib && dot(plane, float4(vP,1.0))>0; |
|||
} |
|||
|
|||
if(bAllInvisib) bIsHit = false; |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
return bIsHit; |
|||
} |
|||
|
|||
bool CheckIntersectionBasic(int l, int k) |
|||
{ |
|||
unsigned int val = (clusterIdxs[l>>1]>>(16*(l&1)))&0xffff; |
|||
return ((val>>0)&0xff)<=((uint) k) && ((uint) k)<=((val>>8)&0xff); |
|||
} |
|||
|
|||
|
|||
[numthreads(NR_THREADS, 1, 1)] |
|||
void LIGHTLISTGEN(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) |
|||
{ |
|||
uint2 tileIDX = u3GroupID.xy; |
|||
uint t=threadID; |
|||
|
|||
uint iWidth; |
|||
uint iHeight; |
|||
#ifdef MSAA_ENABLED |
|||
uint iNumSamplesMSAA; |
|||
g_depth_tex.GetDimensions(iWidth, iHeight, iNumSamplesMSAA); |
|||
#else |
|||
g_depth_tex.GetDimensions(iWidth, iHeight); |
|||
#endif |
|||
uint nrTilesX = (iWidth+15)/16; |
|||
uint nrTilesY = (iHeight+15)/16; |
|||
|
|||
uint2 viTilLL = 16*tileIDX; |
|||
uint2 viTilUR = min( viTilLL+uint2(16,16), uint2(iWidth, iHeight) ); // not width and height minus 1 since viTilUR represents the end of the tile corner. |
|||
|
|||
if(t==0) |
|||
{ |
|||
lightOffs = 0; |
|||
|
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
ldsZMax = 0; |
|||
#endif |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
float dpt_ma=1.0; |
|||
|
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
// establish min and max depth first |
|||
dpt_ma=0.0; |
|||
|
|||
for(int idx=t; idx<256; idx+=NR_THREADS) |
|||
{ |
|||
uint2 uPixCrd = min( uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1) ); |
|||
#ifdef MSAA_ENABLED |
|||
for(int i=0; i<iNumSamplesMSAA; i++) |
|||
{ |
|||
const float fDpth = FetchDepthMSAA(g_depth_tex, uPixCrd, i); |
|||
#else |
|||
const float fDpth = FetchDepth(g_depth_tex, uPixCrd); |
|||
#endif |
|||
if(fDpth<VIEWPORT_SCALE_Z) // if not skydome |
|||
{ |
|||
dpt_ma = max(fDpth, dpt_ma); |
|||
} |
|||
#ifdef MSAA_ENABLED |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
InterlockedMax(ldsZMax, asuint(dpt_ma) ); |
|||
|
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
dpt_ma = asfloat(ldsZMax); |
|||
#endif |
|||
|
|||
float3 vTileLL = float3(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight, 0.0); |
|||
float3 vTileUR = float3(viTilUR.x/(float) iWidth, viTilUR.y/(float) iHeight, 1.0); |
|||
|
|||
|
|||
// build coarse list using AABB |
|||
#ifdef USE_TWO_PASS_TILED_LIGHTING |
|||
int NrBigTilesX = (nrTilesX+3)>>2; |
|||
const int bigTileIdx = (tileIDX.y>>2)*NrBigTilesX + (tileIDX.x>>2); // map the idx to 64x64 tiles |
|||
int nrBigTileLights = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+0]; |
|||
for(int l0=(int) t; l0<(int) nrBigTileLights; l0 += NR_THREADS) |
|||
{ |
|||
int l = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+l0+1]; |
|||
#else |
|||
for(int l=(int) t; l<(int) g_iNrVisibLights; l += NR_THREADS) |
|||
{ |
|||
#endif |
|||
const float3 vMi = g_vBoundsBuffer[l]; |
|||
const float3 vMa = g_vBoundsBuffer[l+g_iNrVisibLights]; |
|||
|
|||
if( all(vMa.xy>vTileLL.xy) && all(vMi.xy<vTileUR.xy)) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffs, uInc, uIndex); |
|||
if(uIndex<MAX_NR_COARSE_ENTRIES) coarseList[uIndex] = l; // add to light list |
|||
} |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
int iNrCoarseLights = min(lightOffs,MAX_NR_COARSE_ENTRIES); |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
iNrCoarseLights = SphericalIntersectionTests( t, iNrCoarseLights, float2(min(viTilLL.xy+uint2(16/2,16/2), uint2(iWidth-1, iHeight-1))) ); |
|||
#endif |
|||
|
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float fTileFarPlane = GetLinearDepth(dpt_ma); |
|||
#else |
|||
float fTileFarPlane = -GetLinearDepth(dpt_ma); |
|||
#endif |
|||
float suggestedBase = SuggestLogBase50(fTileFarPlane); |
|||
#else |
|||
float fTileFarPlane = g_fFarPlane; |
|||
float suggestedBase = g_fClustBase; |
|||
#endif |
|||
|
|||
|
|||
#ifdef EXACT_EDGE_TESTS |
|||
iNrCoarseLights = CullByExactEdgeTests(t, iNrCoarseLights, viTilLL.xy, viTilUR.xy, fTileFarPlane); |
|||
#endif |
|||
|
|||
// sort lights (gives a more efficient execution in both deferred and tiled forward lighting). |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
SORTLIST(coarseList, iNrCoarseLights, MAX_NR_COARSE_ENTRIES, t, NR_THREADS); |
|||
#endif |
|||
|
|||
//////////// cell specific code |
|||
{ |
|||
for(int l=(int) t; l<((iNrCoarseLights+1)>>1); l += NR_THREADS) |
|||
{ |
|||
const int l0 = coarseList[2*l+0], l1 = coarseList[min(2*l+1,iNrCoarseLights)]; |
|||
const unsigned int clustIdxMi0 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l0].z), suggestedBase)); |
|||
const unsigned int clustIdxMa0 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l0+g_iNrVisibLights].z), suggestedBase)); |
|||
const unsigned int clustIdxMi1 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l1].z), suggestedBase)); |
|||
const unsigned int clustIdxMa1 = (const unsigned int) min(255,SnapToClusterIdx(GetLinearDepth(g_vBoundsBuffer[l1+g_iNrVisibLights].z), suggestedBase)); |
|||
|
|||
clusterIdxs[l] = (clustIdxMa1<<24) | (clustIdxMi1<<16) | (clustIdxMa0<<8) | (clustIdxMi0<<0); |
|||
} |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
int nrClusters = (1<<g_iLog2NumClusters); |
|||
|
|||
|
|||
|
|||
////////////////////////////////////////////////////////// |
|||
|
|||
uint start = 0; |
|||
int i=(int) t; |
|||
int iSpaceAvail = 0; |
|||
int iSum = 0; |
|||
if(i<nrClusters) |
|||
{ |
|||
for(int l=0; l<iNrCoarseLights; l++) |
|||
{ |
|||
iSum += (CheckIntersectionBasic(l, i) ? 1 : 0); |
|||
} |
|||
|
|||
iSpaceAvail = min(iSum,MAX_NR_COARSE_ENTRIES); // combined storage for both direct lights and reflection |
|||
InterlockedAdd(g_LayeredSingleIdxBuffer[0], (uint) iSpaceAvail, start); // alloc list memory |
|||
} |
|||
|
|||
int modelListCount[NR_LIGHT_MODELS]={0,0}; // direct light count and reflection lights |
|||
uint offs = start; |
|||
for(int ll=0; ll<iNrCoarseLights; ll+=4) |
|||
{ |
|||
int p = i>>2; |
|||
int m = i&3; |
|||
if(i<24) lightPlanes[6*m+p] = FetchPlane(min(iNrCoarseLights-1,ll+m), p); |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
for(int l=ll; l<min(iNrCoarseLights,(ll+4)); l++) |
|||
{ |
|||
if(offs<(start+iSpaceAvail) && i<nrClusters && CheckIntersection(l, i, viTilLL.xy, viTilUR.xy, suggestedBase) ) |
|||
{ |
|||
uint lightModel = g_vLightData[ coarseList[l] ].lightModel; |
|||
++modelListCount[ lightModel==REFLECTION_LIGHT ? 1 : 0]; |
|||
g_vLayeredLightList[offs++] = coarseList[l]; // reflection lights will be last since we sorted |
|||
} |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
} |
|||
|
|||
uint localOffs=0; |
|||
offs = i*nrTilesX*nrTilesY + tileIDX.y*nrTilesX + tileIDX.x; |
|||
for(int m=0; m<NR_LIGHT_MODELS; m++) |
|||
{ |
|||
int numLights = min(modelListCount[m],31); // only allow 5 bits |
|||
if(i<nrClusters) |
|||
{ |
|||
g_LayeredOffset[offs] = (start+localOffs) | (((uint) numLights)<<27); |
|||
offs += (nrClusters*nrTilesX*nrTilesY); |
|||
localOffs += modelListCount[m]; // use unclamped count for localOffs |
|||
} |
|||
} |
|||
|
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
g_logBaseBuffer[tileIDX.y*nrTilesX + tileIDX.x] = suggestedBase; |
|||
#endif |
|||
} |
|||
|
|||
|
|||
float4 FetchPlane(int l, int p) |
|||
{ |
|||
SFiniteLightBound lgtDat = g_data[coarseList[l]]; |
|||
|
|||
const float3 boxX = lgtDat.boxAxisX.xyz; |
|||
const float3 boxY = lgtDat.boxAxisY.xyz; |
|||
const float3 boxZ = -lgtDat.boxAxisZ.xyz; // flip axis (so it points away from the light direction for a spot-light) |
|||
const float3 center = lgtDat.center.xyz; |
|||
const float radius = lgtDat.radius; |
|||
const float2 scaleXY = lgtDat.scaleXY; |
|||
|
|||
return GetPlaneEq(boxX, boxY, boxZ, center, scaleXY, p); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate) |
|||
{ |
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, 1.0); |
|||
#else |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, -1.0); |
|||
#endif |
|||
|
|||
float onePixDiagDist = GetOnePixDiagWorldDistAtDepthOne(); |
|||
float halfTileSizeAtZDistOne = 8*onePixDiagDist; // scale by half a tile |
|||
|
|||
for(int l=threadID; l<iNrCoarseLights; l+=NR_THREADS) |
|||
{ |
|||
SFiniteLightBound lgtDat = g_data[coarseList[l]]; |
|||
|
|||
if( !DoesSphereOverlapTile(V, halfTileSizeAtZDistOne, lgtDat.center.xyz, lgtDat.radius) ) |
|||
coarseList[l]=0xffffffff; |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
// to greedy to double buffer coarseList lds on this so serializing removal of gaps. |
|||
if(threadID==0) |
|||
{ |
|||
int offs = 0; |
|||
for(int l=0; l<iNrCoarseLights; l++) |
|||
{ if(coarseList[l]!=0xffffffff) coarseList[offs++] = coarseList[l]; } |
|||
lightOffsSph = offs; |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
return lightOffsSph; |
|||
} |
|||
#endif |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
#ifdef EXACT_EDGE_TESTS |
|||
|
|||
float3 GetTileVertex(uint2 viTilLL, uint2 viTilUR, int i, float fTileFarPlane) |
|||
{ |
|||
float x = (i&1)==0 ? viTilLL.x : viTilUR.x; |
|||
float y = (i&2)==0 ? viTilLL.y : viTilUR.y; |
|||
float z = (i&4)==0 ? g_fNearPlane : fTileFarPlane; |
|||
#if !USE_LEFTHAND_CAMERASPACE |
|||
z = -z; |
|||
#endif |
|||
return GetViewPosFromLinDepth( float2(x, y), z); |
|||
} |
|||
|
|||
void GetFrustEdge(out float3 vP0, out float3 vE0, const int e0, uint2 viTilLL, uint2 viTilUR, float fTileFarPlane) |
|||
{ |
|||
int iSection = e0>>2; // section 0 is side edges, section 1 is near edges and section 2 is far edges |
|||
int iSwizzle = e0&0x3; |
|||
|
|||
int i=iSwizzle + (2*(iSection&0x2)); // offset by 4 at section 2 |
|||
vP0 = GetTileVertex(uint2(viTilLL.x, viTilUR.y), uint2(viTilUR.x, viTilLL.y), i, fTileFarPlane); |
|||
vE0 = iSection==0 ? vP0 : (((iSwizzle&0x2)==0 ? 1.0f : (-1.0f))*((iSwizzle&0x1)==(iSwizzle>>1) ? float3(1,0,0) : float3(0,1,0))); |
|||
} |
|||
|
|||
int CullByExactEdgeTests(uint threadID, int iNrCoarseLights, uint2 viTilLL, uint2 viTilUR, float fTileFarPlane) |
|||
{ |
|||
if(threadID==0) lightOffs2 = 0; |
|||
|
|||
const bool bOnlyNeedFrustumSideEdges = true; |
|||
const int nrFrustEdges = bOnlyNeedFrustumSideEdges ? 4 : 8; // max 8 since we never need to test 4 far edges of frustum since they are identical vectors to near edges and plane is placed at vP0 on light hull. |
|||
|
|||
const int totNrEdgePairs = 12*nrFrustEdges; |
|||
for(int l=0; l<iNrCoarseLights; l++) |
|||
{ |
|||
if(threadID==0) ldsIsLightInvisible=0; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
const int idxCoarse = coarseList[l]; |
|||
[branch]if(g_vLightData[idxCoarse].lightType!=SPHERE_LIGHT) // don't bother doing edge tests for sphere lights since these have camera aligned bboxes. |
|||
{ |
|||
SFiniteLightBound lgtDat = g_data[idxCoarse]; |
|||
|
|||
const float3 boxX = lgtDat.boxAxisX.xyz; |
|||
const float3 boxY = lgtDat.boxAxisY.xyz; |
|||
const float3 boxZ = -lgtDat.boxAxisZ.xyz; // flip axis (so it points away from the light direction for a spot-light) |
|||
const float3 center = lgtDat.center.xyz; |
|||
const float2 scaleXY = lgtDat.scaleXY; |
|||
|
|||
for(int i=threadID; i<totNrEdgePairs; i+=NR_THREADS) |
|||
{ |
|||
int e0 = (int) (((uint)i)/((uint) nrFrustEdges)); // should become a shift right |
|||
int e1 = i - e0*nrFrustEdges; |
|||
|
|||
int idx_cur=0, idx_twin=0; |
|||
float3 vP0, vE0; |
|||
GetHullEdge(idx_cur, idx_twin, vP0, vE0, e0, boxX, boxY, boxZ, center, scaleXY); |
|||
|
|||
|
|||
float3 vP1, vE1; |
|||
GetFrustEdge(vP1, vE1, e1, viTilLL, viTilUR, fTileFarPlane); |
|||
|
|||
// potential separation plane |
|||
float3 vN = cross(vE0, vE1); |
|||
|
|||
int positive=0, negative=0; |
|||
for(int k=1; k<8; k++) // only need to test 7 verts (technically just 6). |
|||
{ |
|||
int j = (idx_cur+k)&0x7; |
|||
float3 vPh = GetHullVertex(boxX, boxY, boxZ, center, scaleXY, j); |
|||
float fSignDist = idx_twin==j ? 0.0 : dot(vN, vPh-vP0); |
|||
if(fSignDist>0) ++positive; else if(fSignDist<0) ++negative; |
|||
} |
|||
int resh = (positive>0 && negative>0) ? 0 : (positive>0 ? 1 : (negative>0 ? (-1) : 0)); |
|||
|
|||
positive=0; negative=0; |
|||
for(int j=0; j<8; j++) |
|||
{ |
|||
float3 vPf = GetTileVertex(viTilLL, viTilUR, j, fTileFarPlane); |
|||
float fSignDist = dot(vN, vPf-vP0); |
|||
if(fSignDist>0) ++positive; else if(fSignDist<0) ++negative; |
|||
} |
|||
int resf = (positive>0 && negative>0) ? 0 : (positive>0 ? 1 : (negative>0 ? (-1) : 0)); |
|||
|
|||
bool bFoundSepPlane = (resh*resf)<0; |
|||
|
|||
if(bFoundSepPlane) InterlockedOr(ldsIsLightInvisible, 1); |
|||
} |
|||
} |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
if(threadID==0 && ldsIsLightInvisible==0) |
|||
{ |
|||
coarseList[lightOffs2++] = coarseList[l]; |
|||
} |
|||
} |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
return lightOffs2; |
|||
} |
|||
#endif |
|||
|
|||
|
|||
|
|||
[numthreads(1, 1, 1)] |
|||
void ClearAtomic(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) |
|||
{ |
|||
g_LayeredSingleIdxBuffer[0]=0; |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0bb1b7e0ddcd5c44baf3ddc7456eb196 |
|||
timeCreated: 1479689584 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 4 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef __SHADERBASE_H__ |
|||
#define __SHADERBASE_H__ |
|||
|
|||
#ifdef SHADER_API_PSSL |
|||
|
|||
#ifndef Texture2DMS |
|||
#define Texture2DMS MS_Texture2D |
|||
#endif |
|||
|
|||
#ifndef SampleCmpLevelZero |
|||
#define SampleCmpLevelZero SampleCmpLOD0 |
|||
#endif |
|||
|
|||
#ifndef firstbithigh |
|||
#define firstbithigh FirstSetBit_Hi |
|||
#endif |
|||
|
|||
#endif |
|||
|
|||
float FetchDepth(Texture2D depthTexture, uint2 pixCoord) |
|||
{ |
|||
return 1 - depthTexture.Load(uint3(pixCoord.xy, 0)).x; |
|||
} |
|||
|
|||
float FetchDepthMSAA(Texture2DMS<float> depthTexture, uint2 pixCoord, uint sampleIdx) |
|||
{ |
|||
return 1 - depthTexture.Load(uint3(pixCoord.xy, 0), sampleIdx).x; |
|||
} |
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 3c90176b54c922b4e9cf65c9ec9cb750 |
|||
timeCreated: 1479691479 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: fafbb144d7f66074785b7727293d89c5 |
|||
folderAsset: yes |
|||
timeCreated: 1474297943 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine.Rendering; |
|||
using UnityEngine.Experimental.Rendering; |
|||
using System.Collections.Generic; |
|||
using System; |
|||
|
|||
namespace UnityEngine.Experimental.ScriptableRenderLoop |
|||
{ |
|||
[Serializable] |
|||
public class SkyParameters |
|||
{ |
|||
public Cubemap skyHDRI; |
|||
public float rotation = 0.0f; |
|||
public float exposure = 0.0f; |
|||
public float multiplier = 1.0f; |
|||
} |
|||
|
|||
public class SkyRenderer |
|||
{ |
|||
const int kSkyCubemapSize = 256; |
|||
|
|||
RenderTexture m_SkyboxCubemapRT = null; |
|||
|
|||
Material m_StandardSkyboxMaterial = null; // This is the Unity standard skybox material. Used to pass the correct cubemap to Enlighten.
|
|||
Material m_SkyHDRIMaterial = null; // Renders a cubemap into a render texture (can be cube or 2D)
|
|||
|
|||
GameObject[] m_CubemapFaceCamera = new GameObject[6]; |
|||
|
|||
Mesh BuildSkyMesh(Camera camera, bool forceUVBottom) |
|||
{ |
|||
Vector4 vertData0 = new Vector4(-1.0f, -1.0f, 1.0f, 1.0f); |
|||
Vector4 vertData1 = new Vector4(1.0f, -1.0f, 1.0f, 1.0f); |
|||
Vector4 vertData2 = new Vector4(1.0f, 1.0f, 1.0f, 1.0f); |
|||
Vector4 vertData3 = new Vector4(-1.0f, 1.0f, 1.0f, 1.0f); |
|||
|
|||
Vector3[] vertData = new Vector3[4]; |
|||
vertData[0] = new Vector3(vertData0.x, vertData0.y, vertData0.z); |
|||
vertData[1] = new Vector3(vertData1.x, vertData1.y, vertData1.z); |
|||
vertData[2] = new Vector3(vertData2.x, vertData2.y, vertData2.z); |
|||
vertData[3] = new Vector3(vertData3.x, vertData3.y, vertData3.z); |
|||
|
|||
// Get view vector vased on the frustrum, i.e (invert transform frustrum get position etc...)
|
|||
Vector3[] eyeVectorData = new Vector3[4]; |
|||
|
|||
Matrix4x4 transformMatrix = camera.cameraToWorldMatrix * camera.projectionMatrix.inverse; |
|||
|
|||
Vector4 posWorldSpace0 = transformMatrix * vertData0; |
|||
Vector4 posWorldSpace1 = transformMatrix * vertData1; |
|||
Vector4 posWorldSpace2 = transformMatrix * vertData2; |
|||
Vector4 posWorldSpace3 = transformMatrix * vertData3; |
|||
|
|||
Vector3 temp = camera.GetComponent<Transform>().position; |
|||
Vector4 cameraPosition = new Vector4(temp.x, temp.y, temp.z, 0.0f); |
|||
|
|||
Vector4 direction0 = (posWorldSpace0 / posWorldSpace0.w - cameraPosition); |
|||
Vector4 direction1 = (posWorldSpace1 / posWorldSpace1.w - cameraPosition); |
|||
Vector4 direction2 = (posWorldSpace2 / posWorldSpace2.w - cameraPosition); |
|||
Vector4 direction3 = (posWorldSpace3 / posWorldSpace3.w - cameraPosition); |
|||
|
|||
if (SystemInfo.graphicsUVStartsAtTop && !forceUVBottom) |
|||
{ |
|||
eyeVectorData[3] = new Vector3(direction0.x, direction0.y, direction0.z).normalized; |
|||
eyeVectorData[2] = new Vector3(direction1.x, direction1.y, direction1.z).normalized; |
|||
eyeVectorData[1] = new Vector3(direction2.x, direction2.y, direction2.z).normalized; |
|||
eyeVectorData[0] = new Vector3(direction3.x, direction3.y, direction3.z).normalized; |
|||
} |
|||
else |
|||
{ |
|||
eyeVectorData[0] = new Vector3(direction0.x, direction0.y, direction0.z).normalized; |
|||
eyeVectorData[1] = new Vector3(direction1.x, direction1.y, direction1.z).normalized; |
|||
eyeVectorData[2] = new Vector3(direction2.x, direction2.y, direction2.z).normalized; |
|||
eyeVectorData[3] = new Vector3(direction3.x, direction3.y, direction3.z).normalized; |
|||
} |
|||
|
|||
// Write out the mesh
|
|||
var triangles = new int[6] { 0, 1, 2, 2, 3, 0 }; |
|||
|
|||
return new Mesh |
|||
{ |
|||
vertices = vertData, |
|||
normals = eyeVectorData, |
|||
triangles = triangles |
|||
}; |
|||
} |
|||
|
|||
public void Rebuild() |
|||
{ |
|||
// TODO: We need to have an API to send our sky information to Enlighten. For now use a workaround through skybox/cubemap material...
|
|||
m_StandardSkyboxMaterial = Utilities.CreateEngineMaterial("Skybox/Cubemap"); |
|||
|
|||
m_SkyHDRIMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderLoop/SkyHDRI"); |
|||
|
|||
m_SkyboxCubemapRT = new RenderTexture(kSkyCubemapSize, kSkyCubemapSize, 1, RenderTextureFormat.ARGBHalf); |
|||
m_SkyboxCubemapRT.dimension = TextureDimension.Cube; |
|||
m_SkyboxCubemapRT.useMipMap = true; |
|||
m_SkyboxCubemapRT.autoGenerateMips = true; |
|||
m_SkyboxCubemapRT.Create(); |
|||
|
|||
Matrix4x4 cubeProj = Matrix4x4.Perspective(90.0f, 1.0f, 0.1f, 1.0f); |
|||
|
|||
Vector3[] lookAtList = { |
|||
new Vector3(1.0f, 0.0f, 0.0f), |
|||
new Vector3(-1.0f, 0.0f, 0.0f), |
|||
new Vector3(0.0f, 1.0f, 0.0f), |
|||
new Vector3(0.0f, -1.0f, 0.0f), |
|||
new Vector3(0.0f, 0.0f, 1.0f), |
|||
new Vector3(0.0f, 0.0f, -1.0f), |
|||
}; |
|||
|
|||
Vector3[] UpVectorList = { |
|||
new Vector3(0.0f, 1.0f, 0.0f), |
|||
new Vector3(0.0f, 1.0f, 0.0f), |
|||
new Vector3(0.0f, 0.0f, -1.0f), |
|||
new Vector3(0.0f, 0.0f, 1.0f), |
|||
new Vector3(0.0f, 1.0f, 0.0f), |
|||
new Vector3(0.0f, 1.0f, 0.0f), |
|||
}; |
|||
|
|||
for (int i = 0; i < 6; ++i) |
|||
{ |
|||
m_CubemapFaceCamera[i] = new GameObject(); |
|||
m_CubemapFaceCamera[i].hideFlags = HideFlags.HideAndDontSave; |
|||
|
|||
Camera camera = m_CubemapFaceCamera[i].AddComponent<Camera>(); |
|||
camera.projectionMatrix = cubeProj; |
|||
Transform transform = camera.GetComponent<Transform>(); |
|||
transform.LookAt(lookAtList[i], UpVectorList[i]); |
|||
} |
|||
} |
|||
|
|||
public void OnDisable() |
|||
{ |
|||
Utilities.Destroy(m_StandardSkyboxMaterial); |
|||
Utilities.Destroy(m_SkyHDRIMaterial); |
|||
Utilities.Destroy(m_SkyboxCubemapRT); |
|||
|
|||
for(int i = 0 ; i < 6 ; ++i) |
|||
{ |
|||
Utilities.Destroy(m_CubemapFaceCamera[i]); |
|||
} |
|||
|
|||
} |
|||
|
|||
private void RenderSky(Camera camera, SkyParameters skyParameters, bool forceUVBottom, RenderLoop renderLoop) |
|||
{ |
|||
Mesh skyMesh = BuildSkyMesh(camera, forceUVBottom); |
|||
|
|||
m_SkyHDRIMaterial.SetTexture("_Cubemap", skyParameters.skyHDRI); |
|||
m_SkyHDRIMaterial.SetVector("_SkyParam", new Vector4(skyParameters.exposure, skyParameters.multiplier, skyParameters.rotation, 0.0f)); |
|||
|
|||
var cmd = new CommandBuffer { name = "Skybox" }; |
|||
cmd.DrawMesh(skyMesh, Matrix4x4.identity, m_SkyHDRIMaterial); |
|||
renderLoop.ExecuteCommandBuffer(cmd); |
|||
cmd.Dispose(); |
|||
} |
|||
|
|||
public void RenderSky(Camera camera, SkyParameters skyParameters, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, RenderLoop renderLoop) |
|||
{ |
|||
// Render sky into a cubemap - doesn't happen every frame, can be control
|
|||
for (int i = 0; i < 6; ++i) |
|||
{ |
|||
Utilities.SetRenderTarget(renderLoop, m_SkyboxCubemapRT, "", 0, (CubemapFace)i); |
|||
Camera faceCamera = m_CubemapFaceCamera[i].GetComponent<Camera>(); |
|||
RenderSky(faceCamera, skyParameters, true, renderLoop); |
|||
} |
|||
|
|||
m_StandardSkyboxMaterial.SetTexture("_Tex", m_SkyboxCubemapRT); |
|||
RenderSettings.skybox = m_StandardSkyboxMaterial; // Setup this material as the default to be use in RenderSettings
|
|||
RenderSettings.ambientIntensity = 1.0f; // fix this to 1, this parameter should not exist!
|
|||
RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Skybox; // Force skybox for our HDRI
|
|||
RenderSettings.reflectionIntensity = 1.0f; |
|||
DynamicGI.UpdateEnvironment(); |
|||
|
|||
// TODO: do a render to texture here
|
|||
|
|||
// Downsample the cubemap and provide it to Enlighten
|
|||
|
|||
// TODO: currently workaround is to set the cubemap in a Skybox/cubemap material
|
|||
//m_SkyboxMaterial.SetTexture(cubemap);
|
|||
|
|||
// Render the sky itself
|
|||
Utilities.SetRenderTarget(renderLoop, colorBuffer, depthBuffer, "Sky Pass"); |
|||
RenderSky(camera, skyParameters, false, renderLoop); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: cf8a015aab8d3b643aa3ef3816f85447 |
|||
timeCreated: 1479314393 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
using UnityEngine; |
|||
using UnityEngine.Rendering; |
|||
using UnityEngine.Experimental.Rendering; |
|||
|
|||
using UnityObject = UnityEngine.Object; |
|||
|
|||
namespace UnityEngine.Experimental.ScriptableRenderLoop |
|||
{ |
|||
[Flags] |
|||
public enum ClearFlag |
|||
{ |
|||
ClearNone = 0, |
|||
ClearColor = 1, |
|||
ClearDepth = 2 |
|||
} |
|||
|
|||
public class Utilities |
|||
{ |
|||
public const RendererConfiguration kRendererConfigurationBakedLighting = RendererConfiguration.PerObjectLightProbe | RendererConfiguration.PerObjectReflectionProbes | RendererConfiguration.PerObjectLightmaps | RendererConfiguration.PerObjectLightProbeProxyVolume; |
|||
|
|||
|
|||
// Render Target Management.
|
|||
public const ClearFlag kClearAll = ClearFlag.ClearDepth | ClearFlag.ClearColor; |
|||
|
|||
public static void SetRenderTarget(RenderLoop renderLoop, RenderTargetIdentifier buffer, string name = "", int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown) |
|||
{ |
|||
var cmd = new CommandBuffer(); |
|||
cmd.name = name; |
|||
cmd.SetRenderTarget(buffer, miplevel, cubemapFace); |
|||
renderLoop.ExecuteCommandBuffer(cmd); |
|||
cmd.Dispose(); |
|||
} |
|||
|
|||
public static void SetRenderTarget(RenderLoop renderLoop, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, string name = "", int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown) |
|||
{ |
|||
SetRenderTarget(renderLoop, colorBuffer, depthBuffer, ClearFlag.ClearNone, new Color(0.0f, 0.0f, 0.0f, 0.0f), name, miplevel, cubemapFace); |
|||
} |
|||
|
|||
public static void SetRenderTarget(RenderLoop renderLoop, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, string name = "", int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown) |
|||
{ |
|||
SetRenderTarget(renderLoop, colorBuffer, depthBuffer, clearFlag, new Color(0.0f, 0.0f, 0.0f, 0.0f), name, miplevel, cubemapFace); |
|||
} |
|||
|
|||
public static void SetRenderTarget(RenderLoop renderLoop, RenderTargetIdentifier colorBuffer, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor, string name = "", int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown) |
|||
{ |
|||
var cmd = new CommandBuffer(); |
|||
cmd.name = name; |
|||
cmd.SetRenderTarget(colorBuffer, depthBuffer, miplevel, cubemapFace); |
|||
if (clearFlag != ClearFlag.ClearNone) |
|||
cmd.ClearRenderTarget((clearFlag & ClearFlag.ClearDepth) != 0, (clearFlag & ClearFlag.ClearColor) != 0, clearColor); |
|||
renderLoop.ExecuteCommandBuffer(cmd); |
|||
cmd.Dispose(); |
|||
} |
|||
|
|||
public static void SetRenderTarget(RenderLoop renderLoop, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, string name = "") |
|||
{ |
|||
SetRenderTarget(renderLoop, colorBuffers, depthBuffer, ClearFlag.ClearNone, Color.black, name); |
|||
} |
|||
|
|||
public static void SetRenderTarget(RenderLoop renderLoop, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag = ClearFlag.ClearNone, string name = "") |
|||
{ |
|||
SetRenderTarget(renderLoop, colorBuffers, depthBuffer, clearFlag, Color.black, name); |
|||
} |
|||
|
|||
public static void SetRenderTarget(RenderLoop renderLoop, RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthBuffer, ClearFlag clearFlag, Color clearColor, string name = "") |
|||
{ |
|||
var cmd = new CommandBuffer(); |
|||
cmd.name = name; |
|||
cmd.SetRenderTarget(colorBuffers, depthBuffer); |
|||
if (clearFlag != ClearFlag.ClearNone) |
|||
cmd.ClearRenderTarget((clearFlag & ClearFlag.ClearDepth) != 0, (clearFlag & ClearFlag.ClearColor) != 0, clearColor); |
|||
renderLoop.ExecuteCommandBuffer(cmd); |
|||
cmd.Dispose(); |
|||
} |
|||
|
|||
// Miscellanous
|
|||
public static Material CreateEngineMaterial(string shaderPath) |
|||
{ |
|||
var mat = new Material(Shader.Find(shaderPath)) |
|||
{ |
|||
hideFlags = HideFlags.HideAndDontSave |
|||
}; |
|||
return mat; |
|||
} |
|||
|
|||
public static void Destroy(UnityObject obj) |
|||
{ |
|||
if (obj != null) |
|||
{ |
|||
#if UNITY_EDITOR
|
|||
if (Application.isPlaying) |
|||
UnityObject.Destroy(obj); |
|||
else |
|||
UnityObject.DestroyImmediate(obj); |
|||
#else
|
|||
UnityObject.Destroy(obj); |
|||
#endif
|
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: b91b03c2b2270d648a49e0fb6880ca3f |
|||
timeCreated: 1479315130 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue