Evgenii Golubev
8 年前
当前提交
0aace9e1
共有 31 个文件被更改,包括 2610 次插入 和 460 次删除
-
2Assets/ScriptableRenderLoop/AdditionalLightData.cs
-
2Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.asset.meta
-
461Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs
-
81Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/LightDefinition.cs
-
170Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/LightDefinition.cs.hlsl
-
8Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/Resources/Deferred.shader
-
105Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.cs
-
15Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.hlsl
-
11Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePassLoop.hlsl
-
59Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
-
1Assets/ScriptableRenderLoop/HDRenderLoop/Material/Material.hlsl
-
25Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl
-
22Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass.meta
-
12Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs.meta
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources.meta
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/lightlistbuild.compute.meta
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/scrbound.compute.meta
-
442Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/lightlistbuild.compute
-
465Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/Resources/scrbound.compute
-
128Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/LightingConvexHullUtils.hlsl
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/LightingConvexHullUtils.hlsl.meta
-
117Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/SortingComputeUtils.hlsl
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/SortingComputeUtils.hlsl.meta
-
148Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs.hlsl
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs.hlsl.meta
-
674Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs
-
50Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.cs.hlsl
-
9Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.cs.hlsl.meta
|
|||
fileFormatVersion: 2 |
|||
guid: 2400b74f5ce370c4481e5dc417d03703 |
|||
timeCreated: 1479240578 |
|||
timeCreated: 1479345431 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
userData: |
|
|||
fileFormatVersion: 2 |
|||
guid: ef8815a81d7dd9147b37093f06d9977c |
|||
folderAsset: yes |
|||
timeCreated: 1479218330 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 292dbec5e9c0baa44b67d675e23f4f71 |
|||
timeCreated: 1479218330 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 10637537837597a41861afbe118b246a |
|||
folderAsset: yes |
|||
timeCreated: 1479306736 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 65af3444cbf4b3747a4dead7ee00cfee |
|||
timeCreated: 1479306737 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 4 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 728dce960f8a9c44bbc3abb3b851d8f6 |
|||
timeCreated: 1479306737 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 4 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
// The implementation is based on the demo on "fine pruned tiled lighting" published in GPU Pro 7. |
|||
// https://github.com/wolfgangfengel/GPU-Pro-7 |
|||
|
|||
#pragma kernel TileLightListGen LIGHTLISTGEN=TileLightListGen |
|||
#pragma kernel TileLightListGen_SrcBigTile LIGHTLISTGEN=TileLightListGen_SrcBigTile USE_TWO_PASS_TILED_LIGHTING |
|||
|
|||
float FetchDepth(Texture2D depthTexture, uint2 pixCoord) |
|||
{ |
|||
return 1 - depthTexture.Load(uint3(pixCoord.xy, 0)).x; |
|||
} |
|||
|
|||
#include "../TilePass.cs.hlsl" |
|||
#include "../LightingConvexHullUtils.hlsl" |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
#include "../SortingComputeUtils.hlsl" |
|||
#endif |
|||
|
|||
|
|||
#define FINE_PRUNING_ENABLED |
|||
#define PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
|
|||
|
|||
uniform int g_iNrVisibLights; |
|||
uniform uint2 g_viDimensions; |
|||
uniform float4x4 g_mInvScrProjection; |
|||
uniform float4x4 g_mScrProjection; |
|||
|
|||
|
|||
Texture2D g_depth_tex : register( t0 ); |
|||
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_vLightList : register( u0 ); |
|||
|
|||
|
|||
#define MAX_NR_COARSE_ENTRIES 64 |
|||
#define MAX_NR_PRUNED_ENTRIES 24 |
|||
|
|||
groupshared unsigned int coarseList[MAX_NR_COARSE_ENTRIES]; |
|||
groupshared unsigned int prunedList[MAX_NR_COARSE_ENTRIES]; // temporarily support room for all 64 while in LDS |
|||
|
|||
groupshared uint ldsZMin; |
|||
groupshared uint ldsZMax; |
|||
groupshared uint lightOffs; |
|||
#ifdef FINE_PRUNING_ENABLED |
|||
groupshared uint ldsDoesLightIntersect[2]; |
|||
#endif |
|||
groupshared int ldsNrLightsFinal; |
|||
|
|||
groupshared int ldsModelListCount[NR_LIGHT_MODELS]; // since NR_LIGHT_MODELS is 2 |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
groupshared uint lightOffsSph; |
|||
#endif |
|||
|
|||
|
|||
//float GetLinearDepth(float3 vP) |
|||
//{ |
|||
// float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
// return v4Pres.z / v4Pres.w; |
|||
//} |
|||
|
|||
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 |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate); |
|||
#endif |
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths); |
|||
#endif |
|||
|
|||
|
|||
[numthreads(NR_THREADS, 1, 1)] |
|||
void LIGHTLISTGEN(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) |
|||
{ |
|||
uint2 tileIDX = u3GroupID.xy; |
|||
uint t=threadID; |
|||
|
|||
if(t<MAX_NR_COARSE_ENTRIES) |
|||
prunedList[t]=0; |
|||
|
|||
uint iWidth = g_viDimensions.x; |
|||
uint iHeight = g_viDimensions.y; |
|||
uint nrTilesX = (iWidth+15)/16; |
|||
uint nrTilesY = (iHeight+15)/16; |
|||
|
|||
// build tile scr boundary |
|||
const uint uFltMax = 0x7f7fffff; // FLT_MAX as a uint |
|||
if(t==0) |
|||
{ |
|||
ldsZMin = uFltMax; |
|||
ldsZMax = 0; |
|||
lightOffs = 0; |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
|
|||
uint2 viTilLL = 16*tileIDX; |
|||
|
|||
// establish min and max depth first |
|||
float dpt_mi=asfloat(uFltMax), dpt_ma=0.0; |
|||
|
|||
|
|||
float4 vLinDepths; |
|||
{ |
|||
// Fetch depths and calculate min/max |
|||
[unroll] |
|||
for(int i = 0; i < 4; i++) |
|||
{ |
|||
int idx = i * NR_THREADS + t; |
|||
uint2 uCrd = min( uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1) ); |
|||
const float fDepth = FetchDepth(g_depth_tex, uCrd); |
|||
vLinDepths[i] = GetLinearDepth(fDepth); |
|||
if(fDepth<VIEWPORT_SCALE_Z) // if not skydome |
|||
{ |
|||
dpt_mi = min(fDepth, dpt_mi); |
|||
dpt_ma = max(fDepth, dpt_ma); |
|||
} |
|||
} |
|||
|
|||
InterlockedMax(ldsZMax, asuint(dpt_ma)); |
|||
InterlockedMin(ldsZMin, asuint(dpt_mi)); |
|||
|
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
} |
|||
|
|||
|
|||
float3 vTileLL = float3(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight, asfloat(ldsZMin)); |
|||
float3 vTileUR = float3((viTilLL.x+16)/(float) iWidth, (viTilLL.y+16)/(float) iHeight, asfloat(ldsZMax)); |
|||
vTileUR.xy = min(vTileUR.xy,float2(1.0,1.0)).xy; |
|||
|
|||
|
|||
// 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>vTileLL) && all(vMi<vTileUR)) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffs, uInc, uIndex); |
|||
if(uIndex<MAX_NR_COARSE_ENTRIES) coarseList[uIndex] = l; // add to light list |
|||
} |
|||
} |
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
if(t<2) ldsDoesLightIntersect[t] = 0; |
|||
#endif |
|||
|
|||
#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 |
|||
|
|||
#ifndef FINE_PRUNING_ENABLED |
|||
{ |
|||
if((int)t<iNrCoarseLights) prunedList[t] = coarseList[t]; |
|||
if(t==0) ldsNrLightsFinal=iNrCoarseLights; |
|||
} |
|||
#else |
|||
{ |
|||
// initializes ldsNrLightsFinal with the number of accepted lights. |
|||
// all accepted entries delivered in prunedList[]. |
|||
FinePruneLights(t, iNrCoarseLights, viTilLL, vLinDepths); |
|||
} |
|||
#endif |
|||
|
|||
// |
|||
if(t<NR_LIGHT_MODELS) ldsModelListCount[t]=0; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
|
|||
int nrLightsCombinedList = min(ldsNrLightsFinal,MAX_NR_COARSE_ENTRIES); |
|||
for(int i=t; i<nrLightsCombinedList; i+=NR_THREADS) |
|||
{ |
|||
InterlockedAdd(ldsModelListCount[ g_vLightData[ prunedList[i] ].lightModel ], 1); |
|||
} |
|||
|
|||
|
|||
// sort lights (gives a more efficient execution in both deferred and tiled forward lighting). |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
SORTLIST(prunedList, nrLightsCombinedList, MAX_NR_COARSE_ENTRIES, t, NR_THREADS); |
|||
//MERGESORTLIST(prunedList, coarseList, nrLightsCombinedList, t, NR_THREADS); |
|||
#endif |
|||
|
|||
// write lights to global buffers |
|||
int localOffs=0; |
|||
int offs = tileIDX.y*nrTilesX + tileIDX.x; |
|||
for(int m=0; m<NR_LIGHT_MODELS; m++) |
|||
{ |
|||
int nrLightsFinal = ldsModelListCount[ m ]; |
|||
int nrLightsFinalClamped = nrLightsFinal<MAX_NR_PRUNED_ENTRIES ? nrLightsFinal : MAX_NR_PRUNED_ENTRIES; |
|||
|
|||
|
|||
const int nrDWords = ((nrLightsFinalClamped+1)+1)>>1; |
|||
for(int l=(int) t; l<(int) nrDWords; l += NR_THREADS) |
|||
{ |
|||
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[2*l-1+localOffs]; |
|||
uint uHigh = prunedList[2*l+0+localOffs]; |
|||
|
|||
g_vLightList[16*offs + l] = (uLow&0xffff) | (uHigh<<16); |
|||
} |
|||
|
|||
localOffs += nrLightsFinal; |
|||
offs += (nrTilesX*nrTilesY); |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate) |
|||
{ |
|||
lightOffsSph = 0; |
|||
|
|||
// make a copy of coarseList in prunedList. |
|||
for(int l=threadID; l<iNrCoarseLights; l+=NR_THREADS) |
|||
prunedList[l]=coarseList[l]; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
#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 lightData = g_data[coarseList[l]]; |
|||
|
|||
if( DoesSphereOverlapTile(V, halfTileSizeAtZDistOne, lightData.center.xyz, lightData.radius) ) |
|||
{ |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffsSph, 1, uIndex); |
|||
coarseList[uIndex]=prunedList[l]; // read from the original copy of coarseList which is backed up in prunedList |
|||
} |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
return lightOffsSph; |
|||
} |
|||
#endif |
|||
|
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
// initializes ldsNrLightsFinal with the number of accepted lights. |
|||
// all accepted entries delivered in prunedList[]. |
|||
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths) |
|||
{ |
|||
uint t = threadID; |
|||
uint iWidth = g_viDimensions.x; |
|||
uint iHeight = g_viDimensions.y; |
|||
|
|||
uint uLightsFlags[2] = {0,0}; |
|||
int l=0; |
|||
// need this outer loop even on xb1 and ps4 since direct lights and |
|||
// reflection lights are kept in separate regions. |
|||
while(l<iNrCoarseLights) |
|||
{ |
|||
// fetch light |
|||
int idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uint uLgtType = l<iNrCoarseLights ? g_vLightData[idxCoarse].lightType : 0; |
|||
|
|||
// spot |
|||
while(l<iNrCoarseLights && uLgtType==SPOT_LIGHT) |
|||
{ |
|||
SFiniteLightData lightData = g_vLightData[idxCoarse]; |
|||
const bool bIsSpotDisc = (lightData.flags&IS_CIRCULAR_SPOT_SHAPE)!=0; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 fromLight = vVPos-lightData.lightPos.xyz; |
|||
float distSq = dot(fromLight,fromLight); |
|||
const float fSclProj = dot(fromLight, lightData.lightAxisZ.xyz); // spotDir = lightData.lightAxisZ.xyz |
|||
|
|||
float2 V = abs( float2( dot(fromLight, lightData.lightAxisX.xyz), dot(fromLight, lightData.lightAxisY.xyz) ) ); |
|||
|
|||
float fDist2D = bIsSpotDisc ? length(V) : max(V.x,V.y); |
|||
if( all( float2(lightData.radiusSq, fSclProj) > float2(distSq, fDist2D*lightData.cotan) ) ) uVal = 1; |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLgtType = l<iNrCoarseLights ? g_vLightData[idxCoarse].lightType : 0; |
|||
} |
|||
|
|||
// sphere |
|||
while(l<iNrCoarseLights && uLgtType==SPHERE_LIGHT) |
|||
{ |
|||
SFiniteLightData lightData = g_vLightData[idxCoarse]; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 vLp = lightData.lightPos.xyz; |
|||
float3 toLight = vLp - vVPos; |
|||
float distSq = dot(toLight,toLight); |
|||
|
|||
if(lightData.radiusSq>distSq) uVal = 1; |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLgtType = l<iNrCoarseLights ? g_vLightData[idxCoarse].lightType : 0; |
|||
} |
|||
|
|||
// Box |
|||
while(l<iNrCoarseLights && uLgtType==BOX_LIGHT) |
|||
{ |
|||
SFiniteLightData lightData = g_vLightData[idxCoarse]; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 toLight = lightData.lightPos.xyz - vVPos; |
|||
|
|||
float3 dist = float3( dot(toLight, lightData.lightAxisX), dot(toLight, lightData.lightAxisY), dot(toLight, lightData.lightAxisZ) ); |
|||
dist = (abs(dist) - lightData.boxInnerDist) * lightData.boxInvRange; // not as efficient as it could be |
|||
if( max(max(dist.x, dist.y), dist.z)<1 ) uVal = 1; // but allows us to not write out OuterDists |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLgtType = l<iNrCoarseLights ? g_vLightData[idxCoarse].lightType : 0; |
|||
} |
|||
|
|||
// in case we have some corrupt data make sure we terminate |
|||
if(uLgtType>=MAX_TYPES) ++l; |
|||
} |
|||
|
|||
InterlockedOr(ldsDoesLightIntersect[0], uLightsFlags[0]); |
|||
InterlockedOr(ldsDoesLightIntersect[1], uLightsFlags[1]); |
|||
if(t==0) ldsNrLightsFinal = 0; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
if(t<(uint) iNrCoarseLights && (ldsDoesLightIntersect[t<32 ? 0 : 1]&(1<<(t&31)))!=0 ) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(ldsNrLightsFinal, uInc, uIndex); |
|||
if(uIndex<MAX_NR_COARSE_ENTRIES) prunedList[uIndex] = coarseList[t]; // we allow up to 64 pruned lights while stored in LDS. |
|||
} |
|||
} |
|||
#endif |
|
|||
// The implementation is based on the demo on "fine pruned tiled lighting" published in GPU Pro 7. |
|||
// https://github.com/wolfgangfengel/GPU-Pro-7 |
|||
|
|||
#pragma kernel ScreenBoundsAABB |
|||
|
|||
#include "../TilePass.cs.hlsl" |
|||
|
|||
uniform int g_iNrVisibLights; |
|||
uniform float4x4 g_mInvProjection; |
|||
uniform float4x4 g_mProjection; |
|||
|
|||
|
|||
StructuredBuffer<SFiniteLightBound> g_data : register( t0 ); |
|||
|
|||
|
|||
|
|||
#define FLT_EPSILON 1.192092896e-07F // smallest such that 1.0+FLT_EPSILON != 1.0 |
|||
#define NR_THREADS 64 |
|||
|
|||
// output buffer |
|||
RWStructuredBuffer<float3> g_vBoundsBuffer : register( u0 ); |
|||
|
|||
#define MAX_PNTS 9 // strictly this should be 10=6+4 but we get more wavefronts and 10 seems to never hit (fingers crossed) |
|||
// However, worst case the plane that would be skipped if such an extreme case ever happened would be backplane |
|||
// clipping gets skipped which doesn't cause any errors. |
|||
|
|||
|
|||
// LDS (2496 bytes) |
|||
groupshared float posX[MAX_PNTS*8*2]; |
|||
groupshared float posY[MAX_PNTS*8*2]; |
|||
groupshared float posZ[MAX_PNTS*8*2]; |
|||
groupshared float posW[MAX_PNTS*8*2]; |
|||
groupshared unsigned int clipFlags[48]; |
|||
|
|||
|
|||
unsigned int GetClip(const float4 P); |
|||
int ClipAgainstPlane(const int iSrcIndex, const int iNrSrcVerts, const int subLigt, const int p); |
|||
void CalcBound(out bool2 bIsMinValid, out bool2 bIsMaxValid, out float2 vMin, out float2 vMax, float4x4 InvProjection, float3 pos_view_space, float r); |
|||
|
|||
#include "../LightingConvexHullUtils.hlsl" |
|||
|
|||
|
|||
[numthreads(NR_THREADS, 1, 1)] |
|||
void ScreenBoundsAABB(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) |
|||
{ |
|||
uint groupID = u3GroupID.x; |
|||
|
|||
//uint vindex = groupID * NR_THREADS + threadID; |
|||
unsigned int g = groupID; |
|||
unsigned int t = threadID; |
|||
|
|||
const int subLigt = (int) (t/8); |
|||
const int lgtIndex = subLigt+(int) g*8; |
|||
const int sideIndex = (int) (t%8); |
|||
|
|||
SFiniteLightBound lgtDat = g_data[lgtIndex]; |
|||
|
|||
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; |
|||
|
|||
{ |
|||
if(sideIndex<6 && lgtIndex<(int) g_iNrVisibLights) // mask 2 out of 8 threads |
|||
{ |
|||
float3 q0, q1, q2, q3; |
|||
GetQuad(q0, q1, q2, q3, boxX, boxY, boxZ, center, scaleXY, sideIndex); |
|||
|
|||
|
|||
const float4 vP0 = mul(g_mProjection, float4(q0, 1)); |
|||
const float4 vP1 = mul(g_mProjection, float4(q1, 1)); |
|||
const float4 vP2 = mul(g_mProjection, float4(q2, 1)); |
|||
const float4 vP3 = mul(g_mProjection, float4(q3, 1)); |
|||
|
|||
// test vertices of one quad (of the convex hull) for intersection |
|||
const unsigned int uFlag0 = GetClip(vP0); |
|||
const unsigned int uFlag1 = GetClip(vP1); |
|||
const unsigned int uFlag2 = GetClip(vP2); |
|||
const unsigned int uFlag3 = GetClip(vP3); |
|||
|
|||
const float4 vPnts[] = {vP0, vP1, vP2, vP3}; |
|||
|
|||
// screen-space AABB of one quad (assuming no intersection) |
|||
float3 vMin, vMax; |
|||
for(int k=0; k<4; k++) |
|||
{ |
|||
float fW = vPnts[k].w; |
|||
float fS = fW<0 ? -1 : 1; |
|||
float fWabs = fW<0 ? (-fW) : fW; |
|||
fW = fS * (fWabs<FLT_EPSILON ? FLT_EPSILON : fWabs); |
|||
float3 vP = float3(vPnts[k].x/fW, vPnts[k].y/fW, vPnts[k].z/fW); |
|||
if(k==0) { vMin=vP; vMax=vP; } |
|||
|
|||
vMax = max(vMax, vP); vMin = min(vMin, vP); |
|||
} |
|||
|
|||
clipFlags[subLigt*6+sideIndex] = (uFlag0<<0) | (uFlag1<<6) | (uFlag2<<12) | (uFlag3<<18); |
|||
|
|||
// store in clip buffer (only use these vMin and vMax if light is 100% visible in which case clipping isn't needed) |
|||
posX[subLigt*MAX_PNTS*2 + sideIndex] = vMin.x; |
|||
posY[subLigt*MAX_PNTS*2 + sideIndex] = vMin.y; |
|||
posZ[subLigt*MAX_PNTS*2 + sideIndex] = vMin.z; |
|||
|
|||
posX[subLigt*MAX_PNTS*2 + sideIndex + 6] = vMax.x; |
|||
posY[subLigt*MAX_PNTS*2 + sideIndex + 6] = vMax.y; |
|||
posZ[subLigt*MAX_PNTS*2 + sideIndex + 6] = vMax.z; |
|||
} |
|||
} |
|||
|
|||
// if not XBONE and not PLAYSTATION4 we need a memorybarrier here |
|||
// since we can't rely on the gpu cores being 64 wide. |
|||
// We need a pound define around this. |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
|
|||
|
|||
{ |
|||
int f=0; |
|||
|
|||
if(sideIndex==0 && lgtIndex<(int) g_iNrVisibLights) |
|||
{ |
|||
// quick acceptance or rejection |
|||
unsigned int uCollectiveAnd = (unsigned int) -1; |
|||
unsigned int uCollectiveOr = 0; |
|||
for(f=0; f<6; f++) |
|||
{ |
|||
unsigned int uFlagAnd = clipFlags[subLigt*6+f]&0x3f; |
|||
unsigned int uFlagOr = uFlagAnd; |
|||
for(int i=1; i<4; i++) |
|||
{ |
|||
unsigned int uClipBits = (clipFlags[subLigt*6+f]>>(i*6))&0x3f; |
|||
uFlagAnd &= uClipBits; |
|||
uFlagOr |= uClipBits; |
|||
} |
|||
|
|||
uCollectiveAnd &= uFlagAnd; |
|||
uCollectiveOr |= uFlagOr; |
|||
} |
|||
|
|||
bool bSetBoundYet = false; |
|||
float3 vMin=0.0, vMax=0.0; |
|||
if(uCollectiveAnd!=0 || uCollectiveOr==0) // all invisible or all visible (early out) |
|||
{ |
|||
if(uCollectiveOr==0) // all visible |
|||
{ |
|||
for(f=0; f<6; f++) |
|||
{ |
|||
const int sideIndex = f; |
|||
|
|||
float3 vFaceMi = float3(posX[subLigt*MAX_PNTS*2 + sideIndex + 0], posY[subLigt*MAX_PNTS*2 + sideIndex + 0], posZ[subLigt*MAX_PNTS*2 + sideIndex + 0]); |
|||
float3 vFaceMa = float3(posX[subLigt*MAX_PNTS*2 + sideIndex + 6], posY[subLigt*MAX_PNTS*2 + sideIndex + 6], posZ[subLigt*MAX_PNTS*2 + sideIndex + 6]); |
|||
|
|||
for(int k=0; k<2; k++) |
|||
{ |
|||
float3 vP = k==0 ? vFaceMi : vFaceMa; |
|||
if(f==0 && k==0) { vMin=vP; vMax=vP; } |
|||
|
|||
vMax = max(vMax, vP); vMin = min(vMin, vP); |
|||
} |
|||
} |
|||
bSetBoundYet=true; |
|||
} |
|||
} |
|||
else // :( need true clipping |
|||
{ |
|||
|
|||
for(f=0; f<6; f++) |
|||
{ |
|||
float3 q0, q1, q2, q3; |
|||
GetQuad(q0, q1, q2, q3, boxX, boxY, boxZ, center, scaleXY, f); |
|||
|
|||
// 4 vertices to a quad of the convex hull in post projection space |
|||
const float4 vP0 = mul(g_mProjection, float4(q0, 1)); |
|||
const float4 vP1 = mul(g_mProjection, float4(q1, 1)); |
|||
const float4 vP2 = mul(g_mProjection, float4(q2, 1)); |
|||
const float4 vP3 = mul(g_mProjection, float4(q3, 1)); |
|||
|
|||
|
|||
int iSrcIndex = 0; |
|||
|
|||
int offs = iSrcIndex*MAX_PNTS+subLigt*MAX_PNTS*2; |
|||
|
|||
// fill up source clip buffer with the quad |
|||
posX[offs+0]=vP0.x; posX[offs+1]=vP1.x; posX[offs+2]=vP2.x; posX[offs+3]=vP3.x; |
|||
posY[offs+0]=vP0.y; posY[offs+1]=vP1.y; posY[offs+2]=vP2.y; posY[offs+3]=vP3.y; |
|||
posZ[offs+0]=vP0.z; posZ[offs+1]=vP1.z; posZ[offs+2]=vP2.z; posZ[offs+3]=vP3.z; |
|||
posW[offs+0]=vP0.w; posW[offs+1]=vP1.w; posW[offs+2]=vP2.w; posW[offs+3]=vP3.w; |
|||
|
|||
int iNrSrcVerts = 4; |
|||
|
|||
// do true clipping |
|||
for(int p=0; p<6; p++) |
|||
{ |
|||
const int nrVertsDst = ClipAgainstPlane(iSrcIndex, iNrSrcVerts, subLigt, p); |
|||
|
|||
iSrcIndex = 1-iSrcIndex; |
|||
iNrSrcVerts = nrVertsDst; |
|||
|
|||
if(iNrSrcVerts<3 || iNrSrcVerts>=MAX_PNTS) break; |
|||
} |
|||
|
|||
// final clipped convex primitive is in src buffer |
|||
if(iNrSrcVerts>2) |
|||
{ |
|||
int offs_src = iSrcIndex*MAX_PNTS+subLigt*MAX_PNTS*2; |
|||
for(int k=0; k<iNrSrcVerts; k++) |
|||
{ |
|||
float4 vCur = float4(posX[offs_src+k], posY[offs_src+k], posZ[offs_src+k], posW[offs_src+k]); |
|||
|
|||
// project and apply toward AABB |
|||
float3 vP = float3(vCur.x/vCur.w, vCur.y/vCur.w, vCur.z/vCur.w); |
|||
if(!bSetBoundYet) { vMin=vP; vMax=vP; bSetBoundYet=true; } |
|||
|
|||
vMax = max(vMax, vP); vMin = min(vMin, vP); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
////////////////////// look for camera frustum verts that need to be included. That is frustum vertices inside the convex hull for the light |
|||
int i=0; |
|||
for(i=0; i<8; i++) // establish 8 camera frustum vertices |
|||
{ |
|||
float3 vVertPSpace = float3((i&1)!=0 ? 1 : (-1), (i&2)!=0 ? 1 : (-1), (i&4)!=0 ? 1 : 0); |
|||
|
|||
float4 v4ViewSpace = mul(g_mInvProjection, float4(vVertPSpace,1)); |
|||
float3 vViewSpace = float3(v4ViewSpace.x/v4ViewSpace.w, v4ViewSpace.y/v4ViewSpace.w, v4ViewSpace.z/v4ViewSpace.w); |
|||
|
|||
posX[subLigt*MAX_PNTS*2 + i] = vViewSpace.x; |
|||
posY[subLigt*MAX_PNTS*2 + i] = vViewSpace.y; |
|||
posZ[subLigt*MAX_PNTS*2 + i] = vViewSpace.z; |
|||
} |
|||
|
|||
// determine which camera frustum vertices are inside the convex hull |
|||
uint uVisibFl = 0xff; |
|||
for(f=0; f<6; f++) |
|||
{ |
|||
float3 vP0, vN; |
|||
GetPlane(vP0, vN, boxX, boxY, boxZ, center, scaleXY, f); |
|||
|
|||
for(i=0; i<8; i++) |
|||
{ |
|||
float3 vViewSpace = float3(posX[subLigt*MAX_PNTS*2 + i], posY[subLigt*MAX_PNTS*2 + i], posZ[subLigt*MAX_PNTS*2 + i]); |
|||
uVisibFl &= ( dot(vViewSpace-vP0, vN)<0 ? 0xff : (~(1<<i)) ); |
|||
} |
|||
} |
|||
|
|||
// apply camera frustum vertices inside the convex hull to the AABB |
|||
for(i=0; i<8; i++) |
|||
{ |
|||
if((uVisibFl&(1<<i))!=0) |
|||
{ |
|||
float3 vP = float3((i&1)!=0 ? 1 : (-1), (i&2)!=0 ? 1 : (-1), (i&4)!=0 ? 1 : 0); |
|||
|
|||
if(!bSetBoundYet) { vMin=vP; vMax=vP; bSetBoundYet=true; } |
|||
|
|||
vMax = max(vMax, vP); vMin = min(vMin, vP); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
// determine AABB bound in [-1;1]x[-1;1] screen space using bounding sphere. |
|||
// Use the result to make our already established AABB from the convex hull |
|||
// potentially tighter. |
|||
if(!bSetBoundYet) |
|||
{ |
|||
// set the AABB off-screen |
|||
vMin = float3(-3,-3,-3); |
|||
vMax = float3(-2,-2,-2); |
|||
} |
|||
else |
|||
{ |
|||
//if((center.z+radius)<0.0) |
|||
if( length(center)>radius) |
|||
{ |
|||
float2 vMi, vMa; |
|||
bool2 bMi, bMa; |
|||
CalcBound(bMi, bMa, vMi, vMa, g_mInvProjection, center, radius); |
|||
|
|||
vMin.xy = bMi ? max(vMin.xy, vMi) : vMin.xy; |
|||
vMax.xy = bMa ? min(vMax.xy, vMa) : vMax.xy; |
|||
} |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
if((center.z-radius)>0.0) |
|||
{ |
|||
float4 vPosF = mul(g_mProjection, float4(0,0,center.z-radius,1)); |
|||
vMin.z = max(vMin.z, vPosF.z/vPosF.w); |
|||
} |
|||
if((center.z+radius)>0.0) |
|||
{ |
|||
float4 vPosB = mul(g_mProjection, float4(0,0,center.z+radius,1)); |
|||
vMax.z = min(vMax.z, vPosB.z/vPosB.w); |
|||
} |
|||
#else |
|||
if((center.z+radius)<0.0) |
|||
{ |
|||
float4 vPosF = mul(g_mProjection, float4(0,0,center.z+radius,1)); |
|||
vMin.z = max(vMin.z, vPosF.z/vPosF.w); |
|||
} |
|||
if((center.z-radius)<0.0) |
|||
{ |
|||
float4 vPosB = mul(g_mProjection, float4(0,0,center.z-radius,1)); |
|||
vMax.z = min(vMax.z, vPosB.z/vPosB.w); |
|||
} |
|||
#endif |
|||
else |
|||
{ |
|||
vMin = float3(-3,-3,-3); |
|||
vMax = float3(-2,-2,-2); |
|||
} |
|||
} |
|||
|
|||
|
|||
// we should consider doing a look-up here into a max depth mip chain |
|||
// to see if the light is occluded: vMin.z*VIEWPORT_SCALE_Z > MipTexelMaxDepth |
|||
//g_vBoundsBuffer[lgtIndex+0] = float3(0.5*vMin.x+0.5, -0.5*vMax.y+0.5, vMin.z*VIEWPORT_SCALE_Z); |
|||
//g_vBoundsBuffer[lgtIndex+g_iNrVisibLights] = float3(0.5*vMax.x+0.5, -0.5*vMin.y+0.5, vMax.z*VIEWPORT_SCALE_Z); |
|||
|
|||
// changed for unity |
|||
g_vBoundsBuffer[lgtIndex+0] = float3(0.5*vMin.x+0.5, 0.5*vMin.y+0.5, vMin.z*VIEWPORT_SCALE_Z); |
|||
g_vBoundsBuffer[lgtIndex+(int) g_iNrVisibLights] = float3(0.5*vMax.x+0.5, 0.5*vMax.y+0.5, vMax.z*VIEWPORT_SCALE_Z); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
float4 GenNewVert(const float4 vVisib, const float4 vInvisib, const int p); |
|||
|
|||
int ClipAgainstPlane(const int iSrcIndex, const int iNrSrcVerts, const int subLigt, const int p) |
|||
{ |
|||
int offs_src = iSrcIndex*MAX_PNTS+subLigt*MAX_PNTS*2; |
|||
int offs_dst = (1-iSrcIndex)*MAX_PNTS+subLigt*MAX_PNTS*2; |
|||
|
|||
float4 vPrev = float4(posX[offs_src+(iNrSrcVerts-1)], posY[offs_src+(iNrSrcVerts-1)], posZ[offs_src+(iNrSrcVerts-1)], posW[offs_src+(iNrSrcVerts-1)]); |
|||
|
|||
int nrVertsDst = 0; |
|||
|
|||
unsigned int uMask = (1<<p); |
|||
bool bIsPrevVisib = (GetClip(vPrev)&uMask)==0; |
|||
for(int i=0; i<iNrSrcVerts; i++) |
|||
{ |
|||
float4 vCur = float4(posX[offs_src+i], posY[offs_src+i], posZ[offs_src+i], posW[offs_src+i]); |
|||
bool bIsCurVisib = (GetClip(vCur)&uMask)==0; |
|||
if( (bIsCurVisib && !bIsPrevVisib) || (!bIsCurVisib && bIsPrevVisib) ) |
|||
{ |
|||
//assert(nrVertsDst<MAX_PNTS); |
|||
if(nrVertsDst<MAX_PNTS) |
|||
{ |
|||
// generate new vertex |
|||
float4 vNew = GenNewVert(bIsCurVisib ? vCur : vPrev, bIsCurVisib ? vPrev : vCur, p); |
|||
posX[offs_dst+nrVertsDst]=vNew.x; posY[offs_dst+nrVertsDst]=vNew.y; posZ[offs_dst+nrVertsDst]=vNew.z; posW[offs_dst+nrVertsDst]=vNew.w; |
|||
++nrVertsDst; |
|||
} |
|||
} |
|||
|
|||
if(bIsCurVisib) |
|||
{ |
|||
//assert(nrVertsDst<MAX_PNTS); |
|||
if(nrVertsDst<MAX_PNTS) |
|||
{ |
|||
posX[offs_dst+nrVertsDst]=vCur.x; posY[offs_dst+nrVertsDst]=vCur.y; posZ[offs_dst+nrVertsDst]=vCur.z; posW[offs_dst+nrVertsDst]=vCur.w; |
|||
++nrVertsDst; |
|||
} |
|||
} |
|||
|
|||
vPrev = vCur; |
|||
bIsPrevVisib = bIsCurVisib; |
|||
} |
|||
|
|||
return nrVertsDst; |
|||
} |
|||
|
|||
|
|||
|
|||
unsigned int GetClip(const float4 P) |
|||
{ |
|||
//-P.w <= P.x <= P.w |
|||
return ((P.x<-P.w)?1:0) | ((P.x>P.w)?2:0) | ((P.y<-P.w)?4:0) | ((P.y>P.w)?8:0) | ((P.z<0)?16:0) | ((P.z>P.w)?32:0); |
|||
} |
|||
|
|||
float4 GenNewVert(const float4 vVisib, const float4 vInvisib, const int p) |
|||
{ |
|||
const float fS = p==4 ? 0 : ((p&1)==0 ? -1 : 1); |
|||
const int index = ((uint) p)/2; |
|||
float x1 = index==0 ? vVisib.x : (index==1 ? vVisib.y : vVisib.z); |
|||
float x0 = index==0 ? vInvisib.x : (index==1 ? vInvisib.y : vInvisib.z); |
|||
|
|||
//fS*((vVisib.w-vInvisib.w)*t + vInvisib.w) = (x1-x0)*t + x0; |
|||
|
|||
const float fT = (fS*vInvisib.w-x0)/((x1-x0) - fS*(vVisib.w-vInvisib.w)); |
|||
float4 vNew = vVisib*fT + vInvisib*(1-fT); |
|||
|
|||
// just to be really anal we make sure the clipped against coordinate is precise |
|||
if(index==0) vNew.x = fS*vNew.w; |
|||
else if(index==1) vNew.y = fS*vNew.w; |
|||
else vNew.z = fS*vNew.w; |
|||
|
|||
return vNew; |
|||
} |
|||
|
|||
|
|||
float4 TransformPlaneToPostSpace(float4x4 InvProjection, float4 plane) |
|||
{ |
|||
return mul(plane, InvProjection); |
|||
} |
|||
|
|||
float4 EvalPlanePair(float2 posXY_in, float r) |
|||
{ |
|||
// rotate by 90 degrees to avoid potential division by zero |
|||
bool bMustFlip = abs(posXY_in.y)<abs(posXY_in.x); |
|||
float2 posXY = bMustFlip ? float2(-posXY_in.y, posXY_in.x) : posXY_in; |
|||
|
|||
float fLenSQ = dot(posXY, posXY); |
|||
float D = posXY.y * sqrt(fLenSQ - r*r); |
|||
|
|||
float4 res; |
|||
res.x = (-r*posXY.x - D) / fLenSQ; |
|||
res.z = (-r*posXY.x + D) / fLenSQ; |
|||
res.y = (-r-res.x*posXY.x) / posXY.y; |
|||
res.w = (-r-res.z*posXY.x) / posXY.y; |
|||
|
|||
// rotate back by 90 degrees |
|||
res = bMustFlip ? float4(res.y, -res.x, res.w, -res.z) : res; |
|||
|
|||
return res; |
|||
} |
|||
|
|||
void CalcBound(out bool2 bIsMinValid, out bool2 bIsMaxValid, out float2 vMin, out float2 vMax, float4x4 InvProjection, float3 pos_view_space, float r) |
|||
{ |
|||
float4 planeX = EvalPlanePair(float2(pos_view_space.x, pos_view_space.z), r); |
|||
float4 planeY = EvalPlanePair(float2(pos_view_space.y, pos_view_space.z), r); |
|||
|
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
planeX = planeX.zwxy; // need to swap left/right and top/bottom planes when using left hand system |
|||
planeY = planeY.zwxy; |
|||
#endif |
|||
|
|||
bIsMinValid = bool2(planeX.z<0, planeY.z<0); |
|||
bIsMaxValid = bool2((-planeX.x)<0, (-planeY.x)<0); |
|||
|
|||
// hopefully the compiler takes zeros into account |
|||
// should be the case since the transformation in TransformPlaneToPostSpace() |
|||
// is done using multiply-adds and not dot product instructions. |
|||
float4 planeX0 = TransformPlaneToPostSpace(InvProjection, float4(planeX.x, 0, planeX.y, 0)); |
|||
float4 planeX1 = TransformPlaneToPostSpace(InvProjection, float4(planeX.z, 0, planeX.w, 0)); |
|||
float4 planeY0 = TransformPlaneToPostSpace(InvProjection, float4(0, planeY.x, planeY.y, 0)); |
|||
float4 planeY1 = TransformPlaneToPostSpace(InvProjection, float4(0, planeY.z, planeY.w, 0)); |
|||
|
|||
|
|||
// convert planes to the forms (1,0,0,D) and (0,1,0,D) |
|||
// 2D bound is given by -D components |
|||
float2 A = -float2(planeX0.w / planeX0.x, planeY0.w / planeY0.y); |
|||
float2 B = -float2(planeX1.w / planeX1.x, planeY1.w / planeY1.y); |
|||
|
|||
// Bound is complete |
|||
vMin = B; |
|||
vMax = A; |
|||
} |
|
|||
#ifndef __LIGHTINGCONVEXHULLUTILS_H__ |
|||
#define __LIGHTINGCONVEXHULLUTILS_H__ |
|||
|
|||
#include "TilePass.cs.hlsl" |
|||
|
|||
float3 GetHullVertex(const float3 boxX, const float3 boxY, const float3 boxZ, const float3 center, const float2 scaleXY, const int p) |
|||
{ |
|||
const bool bIsTopVertex = (p&4)!=0; |
|||
float3 vScales = float3( ((p&1)!=0 ? 1.0f : (-1.0f))*(bIsTopVertex ? scaleXY.x : 1.0), ((p&2)!=0 ? 1.0f : (-1.0f))*(bIsTopVertex ? scaleXY.y : 1.0), (p&4)!=0 ? 1.0f : (-1.0f) ); |
|||
return (vScales.x*boxX + vScales.y*boxY + vScales.z*boxZ) + center; |
|||
} |
|||
|
|||
void GetHullEdge(out int idx0, out int idx_twin, out float3 vP0, out float3 vE0, const int e0, const float3 boxX, const float3 boxY, const float3 boxZ, const float3 center, const float2 scaleXY) |
|||
{ |
|||
int iAxis = e0>>2; |
|||
int iSwizzle = e0&0x3; |
|||
bool bIsSwizzleOneOrTwo = ((iSwizzle-1)&0x2)==0; |
|||
|
|||
const int i0 = iAxis==0 ? (2*iSwizzle+0) : ( iAxis==1 ? (iSwizzle+(iSwizzle&2)) : iSwizzle); |
|||
const int i1 = i0 + (1<<iAxis); |
|||
const bool bSwap = iAxis==0 ? (!bIsSwizzleOneOrTwo) : (iAxis==1 ? false : bIsSwizzleOneOrTwo); |
|||
|
|||
idx0 = bSwap ? i1 : i0; |
|||
idx_twin = bSwap ? i0 : i1; |
|||
float3 p0 = GetHullVertex(boxX, boxY, boxZ, center, scaleXY, idx0); |
|||
float3 p1 = GetHullVertex(boxX, boxY, boxZ, center, scaleXY, idx_twin); |
|||
|
|||
vP0 = p0; |
|||
vE0 = p1-p0; |
|||
} |
|||
|
|||
void GetQuad(out float3 p0, out float3 p1, out float3 p2, out float3 p3, const float3 boxX, const float3 boxY, const float3 boxZ, const float3 center, const float2 scaleXY, const int sideIndex) |
|||
{ |
|||
//const int iAbsSide = (sideIndex == 0 || sideIndex == 1) ? 0 : ((sideIndex == 2 || sideIndex == 3) ? 1 : 2); |
|||
const int iAbsSide = min(sideIndex>>1, 2); |
|||
const float fS = (sideIndex & 1) != 0 ? 1 : (-1); |
|||
|
|||
float3 vA = fS*(iAbsSide == 0 ? boxX : (iAbsSide == 1 ? (-boxY) : boxZ)); |
|||
float3 vB = fS*(iAbsSide == 0 ? (-boxY) : (iAbsSide == 1 ? (-boxX) : (-boxY))); |
|||
float3 vC = iAbsSide == 0 ? boxZ : (iAbsSide == 1 ? boxZ : (-boxX)); |
|||
|
|||
bool bIsTopQuad = iAbsSide == 2 && (sideIndex & 1) != 0; // in this case all 4 verts get scaled. |
|||
bool bIsSideQuad = (iAbsSide == 0 || iAbsSide == 1); // if side quad only two verts get scaled (impacts q1 and q2) |
|||
|
|||
if (bIsTopQuad) { vB *= scaleXY.y; vC *= scaleXY.x; } |
|||
|
|||
float3 vA2 = vA; |
|||
float3 vB2 = vB; |
|||
|
|||
if (bIsSideQuad) { vA2 *= (iAbsSide == 0 ? scaleXY.x : scaleXY.y); vB2 *= (iAbsSide == 0 ? scaleXY.y : scaleXY.x); } |
|||
|
|||
// delivered counterclockwise in right hand space and clockwise in left hand space |
|||
p0 = center + (vA + vB - vC); // center + vA is center of face when scaleXY is 1.0 |
|||
p1 = center + (vA - vB - vC); |
|||
p2 = center + (vA2 - vB2 + vC); |
|||
p3 = center + (vA2 + vB2 + vC); |
|||
} |
|||
|
|||
void GetPlane(out float3 p0, out float3 vN, const float3 boxX, const float3 boxY, const float3 boxZ, const float3 center, const float2 scaleXY, const int sideIndex) |
|||
{ |
|||
//const int iAbsSide = (sideIndex == 0 || sideIndex == 1) ? 0 : ((sideIndex == 2 || sideIndex == 3) ? 1 : 2); |
|||
const int iAbsSide = min(sideIndex>>1, 2); |
|||
const float fS = (sideIndex & 1) != 0 ? 1 : (-1); |
|||
|
|||
float3 vA = fS*(iAbsSide == 0 ? boxX : (iAbsSide == 1 ? (-boxY) : boxZ)); |
|||
float3 vB = fS*(iAbsSide == 0 ? (-boxY) : (iAbsSide == 1 ? (-boxX) : (-boxY))); |
|||
float3 vC = iAbsSide == 0 ? boxZ : (iAbsSide == 1 ? boxZ : (-boxX)); |
|||
|
|||
bool bIsTopQuad = iAbsSide == 2 && (sideIndex & 1) != 0; // in this case all 4 verts get scaled. |
|||
bool bIsSideQuad = (iAbsSide == 0 || iAbsSide == 1); // if side quad only two verts get scaled (impacts q1 and q2) |
|||
|
|||
if (bIsTopQuad) { vB *= scaleXY.y; vC *= scaleXY.x; } |
|||
|
|||
float3 vA2 = vA; |
|||
float3 vB2 = vB; |
|||
|
|||
if (bIsSideQuad) { vA2 *= (iAbsSide == 0 ? scaleXY.x : scaleXY.y); vB2 *= (iAbsSide == 0 ? scaleXY.y : scaleXY.x); } |
|||
|
|||
p0 = center + (vA + vB - vC); // center + vA is center of face when scaleXY is 1.0 |
|||
float3 vNout = cross( vB2, 0.5*(vA-vA2) - vC ); |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
vNout = -vNout; |
|||
#endif |
|||
|
|||
vN = vNout; |
|||
} |
|||
|
|||
float4 GetPlaneEq(const float3 boxX, const float3 boxY, const float3 boxZ, const float3 center, const float2 scaleXY, const int sideIndex) |
|||
{ |
|||
float3 p0, vN; |
|||
GetPlane(p0, vN, boxX, boxY, boxZ, center, scaleXY, sideIndex); |
|||
|
|||
return float4(vN, -dot(vN,p0)); |
|||
} |
|||
|
|||
bool DoesSphereOverlapTile(float3 dir, float halfTileSizeAtZDistOne, float3 sphCen, float sphRadiusIn) |
|||
{ |
|||
float3 V = dir; // ray direction down center of tile (does not need to be normalized). |
|||
|
|||
#if 1 |
|||
float3 maxZdir = float3(-sphCen.z*sphCen.x, -sphCen.z*sphCen.y, sphCen.x*sphCen.x + sphCen.y*sphCen.y); // cross(sphCen,cross(Zaxis,sphCen)) |
|||
float len = length(maxZdir); |
|||
float scalarProj = len>0.0001 ? (maxZdir.z/len) : len; // since len>=(maxZdir.z/len) we can use len as an approximate value when len<=epsilon |
|||
float offs = scalarProj*sphRadiusIn; |
|||
#else |
|||
float offs = sphRadiusIn; // more false positives due to larger radius but works too |
|||
#endif |
|||
|
|||
// enlarge sphere so it overlaps the center of the tile assuming it overlaps the tile to begin with. |
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float sphRadius = sphRadiusIn + (sphCen.z+offs)*halfTileSizeAtZDistOne; |
|||
#else |
|||
float sphRadius = sphRadiusIn - (sphCen.z-offs)*halfTileSizeAtZDistOne; |
|||
#endif |
|||
|
|||
float a = dot(V,V); |
|||
float CdotV = dot(sphCen,V); |
|||
float c = dot(sphCen,sphCen) - sphRadius*sphRadius; |
|||
|
|||
float fDescDivFour = CdotV*CdotV - a*c; |
|||
|
|||
return c<0 || (fDescDivFour>0 && CdotV>0); // if ray hits bounding sphere |
|||
} |
|||
|
|||
|
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 7a025524906ace949b463f8f79a03b5c |
|||
timeCreated: 1479344028 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef __SORTINGCOMPUTEUTILS_H__ |
|||
#define __SORTINGCOMPUTEUTILS_H__ |
|||
|
|||
unsigned int LimitPow2AndClamp(unsigned int value_in, unsigned int maxValue) |
|||
{ |
|||
#if 0 |
|||
unsigned int value = 1; |
|||
|
|||
while(value<value_in && (value<<1)<=maxValue) |
|||
value<<=1; |
|||
|
|||
return value_in==0 ? 0 : value; |
|||
#else |
|||
uint valpw2 = value_in==0 ? 0 : (1<<firstbithigh(value_in)); // firstbithigh(0) returns -1 |
|||
valpw2 = max(valpw2, valpw2<<(valpw2!=value_in ? 1 : 0)); // max() just in case of overflow |
|||
return min(valpw2, maxValue); |
|||
#endif |
|||
} |
|||
|
|||
// have to make this sort routine a macro unfortunately because hlsl doesn't take |
|||
// groupshared memory of unspecified length as an input parameter to a function. |
|||
// maxcapacity_in must be a power of two. |
|||
// all data from length_in and up to closest power of two will be filled with 0xffffffff |
|||
#define SORTLIST(data, length_in, maxcapacity_in, localThreadID_in, nrthreads_in) \ |
|||
{ \ |
|||
int length=(int) length_in, maxcapacity=(int) maxcapacity_in, localThreadID=(int) localThreadID_in, nrthreads=(int) nrthreads_in; \ |
|||
\ |
|||
const int N = (const int) LimitPow2AndClamp((unsigned int) length, (uint) maxcapacity); \ |
|||
for(int t=length+localThreadID; t<N; t+=nrthreads) { data[t]=0xffffffff; } \ |
|||
GroupMemoryBarrierWithGroupSync(); \ |
|||
\ |
|||
for(int k=2; k<=N; k=2*k) \ |
|||
{ \ |
|||
for(int j=k>>1; j>0; j=j>>1) \ |
|||
{ \ |
|||
for(int i=localThreadID; i<N; i+=nrthreads) \ |
|||
{ \ |
|||
int ixj=i^j; \ |
|||
if((ixj)>i) \ |
|||
{ \ |
|||
const unsigned int Avalue = data[i]; \ |
|||
const unsigned int Bvalue = data[ixj]; \ |
|||
\ |
|||
const bool mustSwap = ((i&k)!=0^(Avalue>Bvalue)) && Avalue!=Bvalue; \ |
|||
if(mustSwap) \ |
|||
{ \ |
|||
data[i]=Bvalue; \ |
|||
data[ixj]=Avalue; \ |
|||
} \ |
|||
} \ |
|||
} \ |
|||
\ |
|||
GroupMemoryBarrierWithGroupSync(); \ |
|||
} \ |
|||
} \ |
|||
} |
|||
|
|||
// have to make this sort routine a macro unfortunately because hlsl doesn't take |
|||
// groupshared memory of unspecified length as an input parameter to a function. |
|||
// merge-sort is not in-place so two buffers are required: data and tmpdata. |
|||
// These must both have a capacity of at least length_in entries and initial |
|||
// input is assumed to be in data and results will be delivered in data. |
|||
#define MERGESORTLIST(data, tmpdata, length_in, localThreadID_in, nrthreads_in) \ |
|||
{ \ |
|||
int length=(int) length_in, localThreadID=(int) localThreadID_in, nrthreads=(int) nrthreads_in; \ |
|||
\ |
|||
for(int curr_size=1; curr_size<=length-1; curr_size = 2*curr_size) \ |
|||
{ \ |
|||
for(int left_start=localThreadID*(2*curr_size); left_start<(length-1); left_start+=nrthreads*(2*curr_size)) \ |
|||
{ \ |
|||
int mid = left_start + curr_size - 1; \ |
|||
int right_end = min(left_start + 2*curr_size - 1, length-1); \ |
|||
{ \ |
|||
int l=left_start, m=mid, r=right_end; \ |
|||
\ |
|||
int i, j, k; \ |
|||
\ |
|||
int ol = l; \ |
|||
int or = m+1; \ |
|||
int sl = m - l + 1; \ |
|||
int sr = r - m; \ |
|||
\ |
|||
for(int i=l; i<=r; i++) tmpdata[i] = data[i]; \ |
|||
\ |
|||
i = 0; j = 0; k = l; \ |
|||
while (i < sl && j < sr) \ |
|||
{ \ |
|||
const uint lVal = tmpdata[ol+i]; \ |
|||
const uint rVal = tmpdata[or+j]; \ |
|||
bool pickLeft = lVal <= rVal; \ |
|||
i = pickLeft ? (i+1) : i; \ |
|||
j = pickLeft ? j : (j+1); \ |
|||
data[k] = pickLeft ? lVal : rVal; \ |
|||
k++; \ |
|||
} \ |
|||
\ |
|||
while (i < sl) \ |
|||
{ \ |
|||
data[k] = tmpdata[ol+i]; \ |
|||
i++; k++; \ |
|||
} \ |
|||
\ |
|||
while (j < sr) \ |
|||
{ \ |
|||
data[k] = tmpdata[or+j]; \ |
|||
j++; k++; \ |
|||
} \ |
|||
} \ |
|||
} \ |
|||
\ |
|||
GroupMemoryBarrierWithGroupSync(); \ |
|||
} \ |
|||
} |
|||
|
|||
|
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 66b6d3029d5cdb2498af99c4cc141e85 |
|||
timeCreated: 1479344254 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
// |
|||
// This file was automatically generated from Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs. Please don't edit by hand. |
|||
// |
|||
|
|||
#ifndef TILEPASS_CS_HLSL |
|||
#define TILEPASS_CS_HLSL |
|||
// |
|||
// UnityEngine.Experimental.ScriptableRenderLoop.TilePass.LightDefinitions: static fields |
|||
// |
|||
#define MAX_NR_LIGHTS_PER_CAMERA (1024) |
|||
#define MAX_NR_BIGTILE_LIGHTS_PLUSONE (512) |
|||
#define VIEWPORT_SCALE_Z (1) |
|||
#define USE_LEFTHAND_CAMERASPACE (0) |
|||
#define IS_CIRCULAR_SPOT_SHAPE (1) |
|||
#define HAS_COOKIE_TEXTURE (2) |
|||
#define IS_BOX_PROJECTED (4) |
|||
#define HAS_SHADOW (8) |
|||
#define MAX_TYPES (3) |
|||
#define SPOT_LIGHT (0) |
|||
#define SPHERE_LIGHT (1) |
|||
#define BOX_LIGHT (2) |
|||
#define DIRECTIONAL_LIGHT (3) |
|||
#define NR_LIGHT_MODELS (2) |
|||
#define DIRECT_LIGHT (0) |
|||
#define REFLECTION_LIGHT (1) |
|||
|
|||
// Generated from UnityEngine.Experimental.ScriptableRenderLoop.TilePass.SFiniteLightBound |
|||
// PackingRules = Exact |
|||
struct SFiniteLightBound |
|||
{ |
|||
float3 boxAxisX; |
|||
float3 boxAxisY; |
|||
float3 boxAxisZ; |
|||
float3 center; |
|||
float2 scaleXY; |
|||
float radius; |
|||
}; |
|||
|
|||
// Generated from UnityEngine.Experimental.ScriptableRenderLoop.TilePass.SFiniteLightData |
|||
// PackingRules = Exact |
|||
struct SFiniteLightData |
|||
{ |
|||
float3 lightPos; |
|||
int flags; |
|||
float3 lightAxisX; |
|||
uint lightType; |
|||
float3 lightAxisY; |
|||
float radiusSq; |
|||
float3 lightAxisZ; |
|||
float cotan; |
|||
float3 color; |
|||
uint lightModel; |
|||
float3 boxInnerDist; |
|||
float unusued; |
|||
float3 boxInvRange; |
|||
float unused2; |
|||
}; |
|||
|
|||
// |
|||
// Accessors for UnityEngine.Experimental.ScriptableRenderLoop.TilePass.SFiniteLightBound |
|||
// |
|||
float3 GetBoxAxisX(SFiniteLightBound value) |
|||
{ |
|||
return value.boxAxisX; |
|||
} |
|||
float3 GetBoxAxisY(SFiniteLightBound value) |
|||
{ |
|||
return value.boxAxisY; |
|||
} |
|||
float3 GetBoxAxisZ(SFiniteLightBound value) |
|||
{ |
|||
return value.boxAxisZ; |
|||
} |
|||
float3 GetCenter(SFiniteLightBound value) |
|||
{ |
|||
return value.center; |
|||
} |
|||
float2 GetScaleXY(SFiniteLightBound value) |
|||
{ |
|||
return value.scaleXY; |
|||
} |
|||
float GetRadius(SFiniteLightBound value) |
|||
{ |
|||
return value.radius; |
|||
} |
|||
|
|||
// |
|||
// Accessors for UnityEngine.Experimental.ScriptableRenderLoop.TilePass.SFiniteLightData |
|||
// |
|||
float3 GetLightPos(SFiniteLightData value) |
|||
{ |
|||
return value.lightPos; |
|||
} |
|||
int GetFlags(SFiniteLightData value) |
|||
{ |
|||
return value.flags; |
|||
} |
|||
float3 GetLightAxisX(SFiniteLightData value) |
|||
{ |
|||
return value.lightAxisX; |
|||
} |
|||
uint GetLightType(SFiniteLightData value) |
|||
{ |
|||
return value.lightType; |
|||
} |
|||
float3 GetLightAxisY(SFiniteLightData value) |
|||
{ |
|||
return value.lightAxisY; |
|||
} |
|||
float GetRadiusSq(SFiniteLightData value) |
|||
{ |
|||
return value.radiusSq; |
|||
} |
|||
float3 GetLightAxisZ(SFiniteLightData value) |
|||
{ |
|||
return value.lightAxisZ; |
|||
} |
|||
float GetCotan(SFiniteLightData value) |
|||
{ |
|||
return value.cotan; |
|||
} |
|||
float3 GetColor(SFiniteLightData value) |
|||
{ |
|||
return value.color; |
|||
} |
|||
uint GetLightModel(SFiniteLightData value) |
|||
{ |
|||
return value.lightModel; |
|||
} |
|||
float3 GetBoxInnerDist(SFiniteLightData value) |
|||
{ |
|||
return value.boxInnerDist; |
|||
} |
|||
float GetUnusued(SFiniteLightData value) |
|||
{ |
|||
return value.unusued; |
|||
} |
|||
float3 GetBoxInvRange(SFiniteLightData value) |
|||
{ |
|||
return value.boxInvRange; |
|||
} |
|||
float GetUnused2(SFiniteLightData value) |
|||
{ |
|||
return value.unused2; |
|||
} |
|||
|
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: a9b85578530535241bc9f921bee3ad98 |
|||
timeCreated: 1479344047 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.Rendering; |
|||
using System; |
|||
|
|||
namespace UnityEngine.Experimental.ScriptableRenderLoop |
|||
{ |
|||
namespace TilePass |
|||
{ |
|||
//-----------------------------------------------------------------------------
|
|||
// structure definition
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
[GenerateHLSL] |
|||
public class LightDefinitions |
|||
{ |
|||
public static int MAX_NR_LIGHTS_PER_CAMERA = 1024; |
|||
public static int MAX_NR_BIGTILE_LIGHTS_PLUSONE = 512; // may be overkill but the footprint is 2 bits per pixel using uint16.
|
|||
public static float VIEWPORT_SCALE_Z = 1.0f; |
|||
|
|||
// enable unity's original left-hand shader camera space (right-hand internally in unity).
|
|||
public static int USE_LEFTHAND_CAMERASPACE = 0; |
|||
|
|||
// flags
|
|||
public static int IS_CIRCULAR_SPOT_SHAPE = 1; |
|||
public static int HAS_COOKIE_TEXTURE = 2; |
|||
public static int IS_BOX_PROJECTED = 4; |
|||
public static int HAS_SHADOW = 8; |
|||
|
|||
|
|||
// types
|
|||
public static int MAX_TYPES = 3; |
|||
|
|||
public static int SPOT_LIGHT = 0; |
|||
public static int SPHERE_LIGHT = 1; |
|||
public static int BOX_LIGHT = 2; |
|||
public static int DIRECTIONAL_LIGHT = 3; |
|||
|
|||
// direct lights and reflection probes for now
|
|||
public static int NR_LIGHT_MODELS = 2; |
|||
public static int DIRECT_LIGHT = 0; |
|||
public static int REFLECTION_LIGHT = 1; |
|||
} |
|||
|
|||
[GenerateHLSL] |
|||
public struct SFiniteLightBound |
|||
{ |
|||
public Vector3 boxAxisX; |
|||
public Vector3 boxAxisY; |
|||
public Vector3 boxAxisZ; |
|||
public Vector3 center; // a center in camera space inside the bounding volume of the light source.
|
|||
public Vector2 scaleXY; |
|||
public float radius; |
|||
}; |
|||
|
|||
[GenerateHLSL] |
|||
public struct SFiniteLightData |
|||
{ |
|||
public Vector3 lightPos; |
|||
public int flags; |
|||
|
|||
public Vector3 lightAxisX; |
|||
public uint lightType; |
|||
|
|||
public Vector3 lightAxisY; |
|||
public float radiusSq; |
|||
|
|||
public Vector3 lightAxisZ; // spot +Z axis
|
|||
public float cotan; |
|||
|
|||
public Vector3 color; |
|||
public uint lightModel; // DIRECT_LIGHT=0, REFLECTION_LIGHT=1
|
|||
|
|||
public Vector3 boxInnerDist; |
|||
public float unusued; |
|||
|
|||
public Vector3 boxInvRange; |
|||
public float unused2; |
|||
}; |
|||
|
|||
public class LightLoop |
|||
{ |
|||
string GetKeyword() |
|||
{ |
|||
return "LIGHTLOOP_SINGLE_PASS"; |
|||
} |
|||
|
|||
/* |
|||
public const int MaxNumLights = HDRenderLoop.k_MaxPunctualLightsOnSCreen + HDRenderLoop.k_MaxAreaLightsOnSCreen + HDRenderLoop.k_MaxEnvLightsOnSCreen; |
|||
public const int MaxNumDirLights = 2; |
|||
public const float FltMax = 3.402823466e+38F; |
|||
|
|||
ComputeShader buildScreenAABBShader; |
|||
ComputeShader buildPerTileLightListShader; // FPTL
|
|||
ComputeShader buildPerBigTileLightListShader; |
|||
ComputeShader buildPerVoxelLightListShader; // clustered
|
|||
|
|||
private static int s_GenAABBKernel; |
|||
private static int s_GenListPerTileKernel; |
|||
private static int s_GenListPerVoxelKernel; |
|||
private static int s_ClearVoxelAtomicKernel; |
|||
private static ComputeBuffer s_LightDataBuffer; |
|||
private static ComputeBuffer s_ConvexBoundsBuffer; |
|||
private static ComputeBuffer s_AABBBoundsBuffer; |
|||
private static ComputeBuffer s_LightList; |
|||
private static ComputeBuffer s_DirLightList; |
|||
|
|||
private static ComputeBuffer s_BigTileLightList; // used for pre-pass coarse culling on 64x64 tiles
|
|||
private static int s_GenListPerBigTileKernel; |
|||
|
|||
// clustered light list specific buffers and data begin
|
|||
public bool enableClustered = false; |
|||
public bool disableFptlWhenClustered = false; // still useful on opaques
|
|||
public bool enableBigTilePrepass = true; |
|||
public bool enableDrawLightBoundsDebug = false; |
|||
public bool enableDrawTileDebug = false; |
|||
public bool enableComputeLightEvaluation = false; |
|||
const bool k_UseDepthBuffer = true; // only has an impact when EnableClustered is true (requires a depth-prepass)
|
|||
const bool k_UseAsyncCompute = true; // should not use on mobile
|
|||
|
|||
const int k_Log2NumClusters = 6; // accepted range is from 0 to 6. NumClusters is 1<<g_iLog2NumClusters
|
|||
const float k_ClustLogBase = 1.02f; // each slice 2% bigger than the previous
|
|||
float m_ClustScale; |
|||
private static ComputeBuffer s_PerVoxelLightLists; |
|||
private static ComputeBuffer s_PerVoxelOffset; |
|||
private static ComputeBuffer s_PerTileLogBaseTweak; |
|||
private static ComputeBuffer s_GlobalLightListAtomic; |
|||
// clustered light list specific buffers and data end
|
|||
|
|||
const int k_TileSize = 16; |
|||
*/ |
|||
|
|||
bool usingFptl |
|||
{ |
|||
get |
|||
{ |
|||
/* |
|||
bool isEnabledMSAA = false; |
|||
Debug.Assert(!isEnabledMSAA || enableClustered); |
|||
bool disableFptl = (disableFptlWhenClustered && enableClustered) || isEnabledMSAA; |
|||
return !disableFptl; |
|||
*/ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
// Local function
|
|||
void ClearComputeBuffers() |
|||
{ |
|||
/* |
|||
ReleaseResolutionDependentBuffers(); |
|||
|
|||
if (s_AABBBoundsBuffer != null) |
|||
s_AABBBoundsBuffer.Release(); |
|||
|
|||
if (s_ConvexBoundsBuffer != null) |
|||
s_ConvexBoundsBuffer.Release(); |
|||
|
|||
if (s_LightDataBuffer != null) |
|||
s_LightDataBuffer.Release(); |
|||
|
|||
if (s_DirLightList != null) |
|||
s_DirLightList.Release(); |
|||
|
|||
if (enableClustered) |
|||
{ |
|||
if (s_GlobalLightListAtomic != null) |
|||
s_GlobalLightListAtomic.Release(); |
|||
} |
|||
*/ |
|||
} |
|||
|
|||
public void Rebuild() |
|||
{ |
|||
/* |
|||
ClearComputeBuffers(); |
|||
|
|||
buildScreenAABBShader = Resources.Load<ComputeShader>("scrbound"); |
|||
buildPerTileLightListShader = Resources.Load<ComputeShader>("lightlistbuild"); |
|||
buildPerBigTileLightListShader = Resources.Load<ComputeShader>("lightlistbuild-bigtile"); |
|||
buildPerVoxelLightListShader = Resources.Load<ComputeShader>("lightlistbuild-clustered"); |
|||
|
|||
s_GenAABBKernel = buildScreenAABBShader.FindKernel("ScreenBoundsAABB"); |
|||
s_GenListPerTileKernel = buildPerTileLightListShader.FindKernel(enableBigTilePrepass ? "TileLightListGen_SrcBigTile" : "TileLightListGen"); |
|||
s_AABBBoundsBuffer = new ComputeBuffer(2 * MaxNumLights, 3 * sizeof(float)); |
|||
s_ConvexBoundsBuffer = new ComputeBuffer(MaxNumLights, System.Runtime.InteropServices.Marshal.SizeOf(typeof(SFiniteLightBound))); |
|||
s_LightDataBuffer = new ComputeBuffer(MaxNumLights, System.Runtime.InteropServices.Marshal.SizeOf(typeof(SFiniteLightData))); |
|||
s_DirLightList = new ComputeBuffer(MaxNumDirLights, System.Runtime.InteropServices.Marshal.SizeOf(typeof(DirectionalLight))); |
|||
|
|||
buildScreenAABBShader.SetBuffer(s_GenAABBKernel, "g_data", s_ConvexBoundsBuffer); |
|||
buildPerTileLightListShader.SetBuffer(s_GenListPerTileKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer); |
|||
buildPerTileLightListShader.SetBuffer(s_GenListPerTileKernel, "g_vLightData", s_LightDataBuffer); |
|||
buildPerTileLightListShader.SetBuffer(s_GenListPerTileKernel, "g_data", s_ConvexBoundsBuffer); |
|||
|
|||
if (enableClustered) |
|||
{ |
|||
var kernelName = enableBigTilePrepass ? (k_UseDepthBuffer ? "TileLightListGen_DepthRT_SrcBigTile" : "TileLightListGen_NoDepthRT_SrcBigTile") : (k_UseDepthBuffer ? "TileLightListGen_DepthRT" : "TileLightListGen_NoDepthRT"); |
|||
s_GenListPerVoxelKernel = buildPerVoxelLightListShader.FindKernel(kernelName); |
|||
s_ClearVoxelAtomicKernel = buildPerVoxelLightListShader.FindKernel("ClearAtomic"); |
|||
buildPerVoxelLightListShader.SetBuffer(s_GenListPerVoxelKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer); |
|||
buildPerVoxelLightListShader.SetBuffer(s_GenListPerVoxelKernel, "g_vLightData", s_LightDataBuffer); |
|||
buildPerVoxelLightListShader.SetBuffer(s_GenListPerVoxelKernel, "g_data", s_ConvexBoundsBuffer); |
|||
|
|||
s_GlobalLightListAtomic = new ComputeBuffer(1, sizeof(uint)); |
|||
} |
|||
|
|||
if (enableBigTilePrepass) |
|||
{ |
|||
s_GenListPerBigTileKernel = buildPerBigTileLightListShader.FindKernel("BigTileLightListGen"); |
|||
buildPerBigTileLightListShader.SetBuffer(s_GenListPerBigTileKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer); |
|||
buildPerBigTileLightListShader.SetBuffer(s_GenListPerBigTileKernel, "g_vLightData", s_LightDataBuffer); |
|||
buildPerBigTileLightListShader.SetBuffer(s_GenListPerBigTileKernel, "g_data", s_ConvexBoundsBuffer); |
|||
} |
|||
*/ |
|||
} |
|||
|
|||
public void OnDisable() |
|||
{/* |
|||
// TODO: do something for Resources.Load<ComputeShader> ?
|
|||
|
|||
s_AABBBoundsBuffer.Release(); |
|||
s_ConvexBoundsBuffer.Release(); |
|||
s_LightDataBuffer.Release(); |
|||
ReleaseResolutionDependentBuffers(); |
|||
s_DirLightList.Release(); |
|||
|
|||
if (enableClustered) |
|||
{ |
|||
s_GlobalLightListAtomic.Release(); |
|||
} |
|||
*/ |
|||
} |
|||
|
|||
/* |
|||
public bool NeedResize() |
|||
{ |
|||
return s_LightList == null || (s_BigTileLightList == null && enableBigTilePrepass) || (s_PerVoxelLightLists == null && enableClustered); |
|||
} |
|||
|
|||
public void ReleaseResolutionDependentBuffers() |
|||
{ |
|||
if (s_LightList != null) |
|||
s_LightList.Release(); |
|||
|
|||
if (enableClustered) |
|||
{ |
|||
if (s_PerVoxelLightLists != null) |
|||
s_PerVoxelLightLists.Release(); |
|||
|
|||
if (s_PerVoxelOffset != null) |
|||
s_PerVoxelOffset.Release(); |
|||
|
|||
if (k_UseDepthBuffer && s_PerTileLogBaseTweak != null) |
|||
s_PerTileLogBaseTweak.Release(); |
|||
} |
|||
|
|||
if (enableBigTilePrepass) |
|||
{ |
|||
if (s_BigTileLightList != null) |
|||
s_BigTileLightList.Release(); |
|||
} |
|||
} |
|||
|
|||
int NumLightIndicesPerClusteredTile() |
|||
{ |
|||
return 8 * (1 << k_Log2NumClusters); // total footprint for all layers of the tile (measured in light index entries)
|
|||
} |
|||
|
|||
public void AllocResolutionDependentBuffers(int width, int height) |
|||
{ |
|||
var nrTilesX = (width + k_TileSize - 1) / k_TileSize; |
|||
var nrTilesY = (height + k_TileSize - 1) / k_TileSize; |
|||
var nrTiles = nrTilesX * nrTilesY; |
|||
const int capacityUShortsPerTile = 32; |
|||
const int dwordsPerTile = (capacityUShortsPerTile + 1) >> 1; // room for 31 lights and a nrLights value.
|
|||
|
|||
s_LightList = new ComputeBuffer(LightDefinitions.NR_LIGHT_MODELS * dwordsPerTile * nrTiles, sizeof(uint)); // enough list memory for a 4k x 4k display
|
|||
|
|||
if (enableClustered) |
|||
{ |
|||
s_PerVoxelOffset = new ComputeBuffer(LightDefinitions.NR_LIGHT_MODELS * (1 << k_Log2NumClusters) * nrTiles, sizeof(uint)); |
|||
s_PerVoxelLightLists = new ComputeBuffer(NumLightIndicesPerClusteredTile() * nrTiles, sizeof(uint)); |
|||
|
|||
if (k_UseDepthBuffer) |
|||
{ |
|||
s_PerTileLogBaseTweak = new ComputeBuffer(nrTiles, sizeof(float)); |
|||
} |
|||
} |
|||
|
|||
if (enableBigTilePrepass) |
|||
{ |
|||
var nrBigTilesX = (width + 63) / 64; |
|||
var nrBigTilesY = (height + 63) / 64; |
|||
var nrBigTiles = nrBigTilesX * nrBigTilesY; |
|||
s_BigTileLightList = new ComputeBuffer(LightDefinitions.MAX_NR_BIGTILE_LIGHTS_PLUSONE * nrBigTiles, sizeof(uint)); |
|||
} |
|||
} |
|||
*/ |
|||
|
|||
/* |
|||
int GenerateSourceLightBuffers(Camera camera, CullResults inputs) |
|||
{ |
|||
var probes = inputs.visibleReflectionProbes; |
|||
//ReflectionProbe[] probes = Object.FindObjectsOfType<ReflectionProbe>();
|
|||
|
|||
var numModels = (int)LightDefinitions.NR_LIGHT_MODELS; |
|||
var numVolTypes = (int)LightDefinitions.MAX_TYPES; |
|||
var numEntries = new int[numModels, numVolTypes]; |
|||
var offsets = new int[numModels, numVolTypes]; |
|||
var numEntries2nd = new int[numModels, numVolTypes]; |
|||
|
|||
// first pass. Figure out how much we have of each and establish offsets
|
|||
foreach (var cl in inputs.visibleLights) |
|||
{ |
|||
var volType = cl.lightType == LightType.Spot ? LightDefinitions.SPOT_LIGHT : (cl.lightType == LightType.Point ? LightDefinitions.SPHERE_LIGHT : -1); |
|||
if (volType >= 0) ++numEntries[LightDefinitions.DIRECT_LIGHT, volType]; |
|||
} |
|||
|
|||
foreach (var rl in probes) |
|||
{ |
|||
var volType = LightDefinitions.BOX_LIGHT; // always a box for now
|
|||
if (rl.texture != null) ++numEntries[LightDefinitions.REFLECTION_LIGHT, volType]; |
|||
} |
|||
|
|||
// add decals here too similar to the above
|
|||
|
|||
// establish offsets
|
|||
for (var m = 0; m < numModels; m++) |
|||
{ |
|||
offsets[m, 0] = m == 0 ? 0 : (numEntries[m - 1, numVolTypes - 1] + offsets[m - 1, numVolTypes - 1]); |
|||
for (var v = 1; v < numVolTypes; v++) offsets[m, v] = numEntries[m, v - 1] + offsets[m, v - 1]; |
|||
} |
|||
|
|||
|
|||
var numLights = inputs.visibleLights.Length; |
|||
var numProbes = probes.Length; |
|||
var numVolumes = numLights + numProbes; |
|||
|
|||
|
|||
var lightData = new SFiniteLightData[numVolumes]; |
|||
var boundData = new SFiniteLightBound[numVolumes]; |
|||
var worldToView = WorldToCamera(camera); |
|||
bool isNegDeterminant = Vector3.Dot(worldToView.GetColumn(0), Vector3.Cross(worldToView.GetColumn(1), worldToView.GetColumn(2))) < 0.0f; // 3x3 Determinant.
|
|||
|
|||
uint shadowLightIndex = 0; |
|||
foreach (var cl in inputs.visibleLights) |
|||
{ |
|||
var range = cl.range; |
|||
|
|||
var lightToWorld = cl.localToWorld; |
|||
|
|||
Vector3 lightPos = lightToWorld.GetColumn(3); |
|||
|
|||
var bound = new SFiniteLightBound(); |
|||
var light = new SFiniteLightData(); |
|||
|
|||
bound.boxAxisX.Set(1, 0, 0); |
|||
bound.boxAxisY.Set(0, 1, 0); |
|||
bound.boxAxisZ.Set(0, 0, 1); |
|||
bound.scaleXY.Set(1.0f, 1.0f); |
|||
bound.radius = range; |
|||
|
|||
light.flags = 0; |
|||
light.recipRange = 1.0f / range; |
|||
light.color.Set(cl.finalColor.r, cl.finalColor.g, cl.finalColor.b); |
|||
light.sliceIndex = 0; |
|||
light.lightModel = (uint)LightDefinitions.DIRECT_LIGHT; |
|||
light.shadowLightIndex = shadowLightIndex; |
|||
shadowLightIndex++; |
|||
|
|||
var bHasCookie = cl.light.cookie != null; |
|||
var bHasShadow = cl.light.shadows != LightShadows.None; |
|||
|
|||
var idxOut = 0; |
|||
|
|||
if (cl.lightType == LightType.Spot) |
|||
{ |
|||
var isCircularSpot = !bHasCookie; |
|||
if (!isCircularSpot) // square spots always have cookie
|
|||
{ |
|||
light.sliceIndex = m_CookieTexArray.FetchSlice(cl.light.cookie); |
|||
} |
|||
|
|||
Vector3 lightDir = lightToWorld.GetColumn(2); // Z axis in world space
|
|||
|
|||
// represents a left hand coordinate system in world space
|
|||
Vector3 vx = lightToWorld.GetColumn(0); // X axis in world space
|
|||
Vector3 vy = lightToWorld.GetColumn(1); // Y axis in world space
|
|||
var vz = lightDir; // Z axis in world space
|
|||
|
|||
// transform to camera space (becomes a left hand coordinate frame in Unity since Determinant(worldToView)<0)
|
|||
vx = worldToView.MultiplyVector(vx); |
|||
vy = worldToView.MultiplyVector(vy); |
|||
vz = worldToView.MultiplyVector(vz); |
|||
|
|||
|
|||
const float pi = 3.1415926535897932384626433832795f; |
|||
const float degToRad = (float)(pi / 180.0); |
|||
|
|||
|
|||
var sa = cl.light.spotAngle; |
|||
|
|||
var cs = Mathf.Cos(0.5f * sa * degToRad); |
|||
var si = Mathf.Sin(0.5f * sa * degToRad); |
|||
var ta = cs > 0.0f ? (si / cs) : FltMax; |
|||
|
|||
var cota = si > 0.0f ? (cs / si) : FltMax; |
|||
|
|||
//const float cotasa = l.GetCotanHalfSpotAngle();
|
|||
|
|||
// apply nonuniform scale to OBB of spot light
|
|||
var squeeze = true;//sa < 0.7f * 90.0f; // arb heuristic
|
|||
var fS = squeeze ? ta : si; |
|||
bound.center = worldToView.MultiplyPoint(lightPos + ((0.5f * range) * lightDir)); // use mid point of the spot as the center of the bounding volume for building screen-space AABB for tiled lighting.
|
|||
|
|||
light.lightAxisX = vx; |
|||
light.lightAxisY = vy; |
|||
light.lightAxisZ = vz; |
|||
|
|||
// scale axis to match box or base of pyramid
|
|||
bound.boxAxisX = (fS * range) * vx; |
|||
bound.boxAxisY = (fS * range) * vy; |
|||
bound.boxAxisZ = (0.5f * range) * vz; |
|||
|
|||
// generate bounding sphere radius
|
|||
var fAltDx = si; |
|||
var fAltDy = cs; |
|||
fAltDy = fAltDy - 0.5f; |
|||
//if(fAltDy<0) fAltDy=-fAltDy;
|
|||
|
|||
fAltDx *= range; fAltDy *= range; |
|||
|
|||
var altDist = Mathf.Sqrt(fAltDy * fAltDy + (isCircularSpot ? 1.0f : 2.0f) * fAltDx * fAltDx); |
|||
bound.radius = altDist > (0.5f * range) ? altDist : (0.5f * range); // will always pick fAltDist
|
|||
bound.scaleXY = squeeze ? new Vector2(0.01f, 0.01f) : new Vector2(1.0f, 1.0f); |
|||
|
|||
// fill up ldata
|
|||
light.lightType = (uint)LightDefinitions.SPOT_LIGHT; |
|||
light.lightPos = worldToView.MultiplyPoint(lightPos); |
|||
light.radiusSq = range * range; |
|||
light.penumbra = cs; |
|||
light.cotan = cota; |
|||
light.flags |= (isCircularSpot ? LightDefinitions.IS_CIRCULAR_SPOT_SHAPE : 0); |
|||
|
|||
light.flags |= (bHasCookie ? LightDefinitions.HAS_COOKIE_TEXTURE : 0); |
|||
light.flags |= (bHasShadow ? LightDefinitions.HAS_SHADOW : 0); |
|||
|
|||
int i = LightDefinitions.DIRECT_LIGHT, j = LightDefinitions.SPOT_LIGHT; |
|||
idxOut = numEntries2nd[i, j] + offsets[i, j]; ++numEntries2nd[i, j]; |
|||
} |
|||
else if (cl.lightType == LightType.Point) |
|||
{ |
|||
if (bHasCookie) |
|||
{ |
|||
light.sliceIndex = m_CubeCookieTexArray.FetchSlice(cl.light.cookie); |
|||
} |
|||
|
|||
bound.center = worldToView.MultiplyPoint(lightPos); |
|||
bound.boxAxisX.Set(range, 0, 0); |
|||
bound.boxAxisY.Set(0, range, 0); |
|||
bound.boxAxisZ.Set(0, 0, isNegDeterminant ? (-range) : range); // transform to camera space (becomes a left hand coordinate frame in Unity since Determinant(worldToView)<0)
|
|||
bound.scaleXY.Set(1.0f, 1.0f); |
|||
bound.radius = range; |
|||
|
|||
// represents a left hand coordinate system in world space since det(worldToView)<0
|
|||
var lightToView = worldToView * lightToWorld; |
|||
Vector3 vx = lightToView.GetColumn(0); |
|||
Vector3 vy = lightToView.GetColumn(1); |
|||
Vector3 vz = lightToView.GetColumn(2); |
|||
|
|||
// fill up ldata
|
|||
light.lightType = (uint)LightDefinitions.SPHERE_LIGHT; |
|||
light.lightPos = bound.center; |
|||
light.radiusSq = range * range; |
|||
|
|||
light.lightAxisX = vx; |
|||
light.lightAxisY = vy; |
|||
light.lightAxisZ = vz; |
|||
|
|||
light.flags |= (bHasCookie ? LightDefinitions.HAS_COOKIE_TEXTURE : 0); |
|||
light.flags |= (bHasShadow ? LightDefinitions.HAS_SHADOW : 0); |
|||
|
|||
int i = LightDefinitions.DIRECT_LIGHT, j = LightDefinitions.SPHERE_LIGHT; |
|||
idxOut = numEntries2nd[i, j] + offsets[i, j]; ++numEntries2nd[i, j]; |
|||
} |
|||
else |
|||
{ |
|||
//Assert(false);
|
|||
} |
|||
|
|||
// next light
|
|||
if (cl.lightType == LightType.Spot || cl.lightType == LightType.Point) |
|||
{ |
|||
boundData[idxOut] = bound; |
|||
lightData[idxOut] = light; |
|||
} |
|||
} |
|||
var numLightsOut = offsets[LightDefinitions.DIRECT_LIGHT, numVolTypes - 1] + numEntries[LightDefinitions.DIRECT_LIGHT, numVolTypes - 1]; |
|||
|
|||
// probe.m_BlendDistance
|
|||
// Vector3f extents = 0.5*Abs(probe.m_BoxSize);
|
|||
// C center of rendered refl box <-- GetComponent (Transform).GetPosition() + m_BoxOffset;
|
|||
// cube map capture point: GetComponent (Transform).GetPosition()
|
|||
// shader parameter min and max are C+/-(extents+blendDistance)
|
|||
foreach (var rl in probes) |
|||
{ |
|||
var cubemap = rl.texture; |
|||
|
|||
// always a box for now
|
|||
if (cubemap == null) |
|||
continue; |
|||
|
|||
var bndData = new SFiniteLightBound(); |
|||
var lgtData = new SFiniteLightData(); |
|||
|
|||
var idxOut = 0; |
|||
lgtData.flags = 0; |
|||
|
|||
var bnds = rl.bounds; |
|||
var boxOffset = rl.center; // reflection volume offset relative to cube map capture point
|
|||
var blendDistance = rl.blendDistance; |
|||
float imp = rl.importance; |
|||
|
|||
var mat = rl.localToWorld; |
|||
//Matrix4x4 mat = rl.transform.localToWorldMatrix;
|
|||
Vector3 cubeCapturePos = mat.GetColumn(3); // cube map capture position in world space
|
|||
|
|||
|
|||
// implicit in CalculateHDRDecodeValues() --> float ints = rl.intensity;
|
|||
var boxProj = (rl.boxProjection != 0); |
|||
var decodeVals = rl.hdr; |
|||
//Vector4 decodeVals = rl.CalculateHDRDecodeValues();
|
|||
|
|||
// C is reflection volume center in world space (NOT same as cube map capture point)
|
|||
var e = bnds.extents; // 0.5f * Vector3.Max(-boxSizes[p], boxSizes[p]);
|
|||
//Vector3 C = bnds.center; // P + boxOffset;
|
|||
var C = mat.MultiplyPoint(boxOffset); // same as commented out line above when rot is identity
|
|||
|
|||
//Vector3 posForShaderParam = bnds.center - boxOffset; // gives same as rl.GetComponent<Transform>().position;
|
|||
var posForShaderParam = cubeCapturePos; // same as commented out line above when rot is identity
|
|||
var combinedExtent = e + new Vector3(blendDistance, blendDistance, blendDistance); |
|||
|
|||
Vector3 vx = mat.GetColumn(0); |
|||
Vector3 vy = mat.GetColumn(1); |
|||
Vector3 vz = mat.GetColumn(2); |
|||
|
|||
// transform to camera space (becomes a left hand coordinate frame in Unity since Determinant(worldToView)<0)
|
|||
vx = worldToView.MultiplyVector(vx); |
|||
vy = worldToView.MultiplyVector(vy); |
|||
vz = worldToView.MultiplyVector(vz); |
|||
|
|||
var Cw = worldToView.MultiplyPoint(C); |
|||
|
|||
if (boxProj) lgtData.flags |= LightDefinitions.IS_BOX_PROJECTED; |
|||
|
|||
lgtData.lightPos = Cw; |
|||
lgtData.lightAxisX = vx; |
|||
lgtData.lightAxisY = vy; |
|||
lgtData.lightAxisZ = vz; |
|||
lgtData.localCubeCapturePoint = -boxOffset; |
|||
lgtData.probeBlendDistance = blendDistance; |
|||
|
|||
lgtData.lightIntensity = decodeVals.x; |
|||
lgtData.decodeExp = decodeVals.y; |
|||
|
|||
lgtData.sliceIndex = m_CubeReflTexArray.FetchSlice(cubemap); |
|||
|
|||
var delta = combinedExtent - e; |
|||
lgtData.boxInnerDist = e; |
|||
lgtData.boxInvRange.Set(1.0f / delta.x, 1.0f / delta.y, 1.0f / delta.z); |
|||
|
|||
bndData.center = Cw; |
|||
bndData.boxAxisX = combinedExtent.x * vx; |
|||
bndData.boxAxisY = combinedExtent.y * vy; |
|||
bndData.boxAxisZ = combinedExtent.z * vz; |
|||
bndData.scaleXY.Set(1.0f, 1.0f); |
|||
bndData.radius = combinedExtent.magnitude; |
|||
|
|||
// fill up ldata
|
|||
lgtData.lightType = (uint)LightDefinitions.BOX_LIGHT; |
|||
lgtData.lightModel = (uint)LightDefinitions.REFLECTION_LIGHT; |
|||
|
|||
|
|||
int i = LightDefinitions.REFLECTION_LIGHT, j = LightDefinitions.BOX_LIGHT; |
|||
idxOut = numEntries2nd[i, j] + offsets[i, j]; ++numEntries2nd[i, j]; |
|||
boundData[idxOut] = bndData; |
|||
lightData[idxOut] = lgtData; |
|||
} |
|||
|
|||
var numProbesOut = offsets[LightDefinitions.REFLECTION_LIGHT, numVolTypes - 1] + numEntries[LightDefinitions.REFLECTION_LIGHT, numVolTypes - 1]; |
|||
for (var m = 0; m < numModels; m++) |
|||
{ |
|||
for (var v = 0; v < numVolTypes; v++) |
|||
Debug.Assert(numEntries[m, v] == numEntries2nd[m, v], "count mismatch on second pass!"); |
|||
} |
|||
|
|||
s_ConvexBoundsBuffer.SetData(boundData); |
|||
s_LightDataBuffer.SetData(lightData); |
|||
|
|||
|
|||
return numLightsOut + numProbesOut; |
|||
} |
|||
|
|||
|
|||
void BuildPerTileLightLists(Camera camera, RenderLoop loop, int numLights, Matrix4x4 projscr, Matrix4x4 invProjscr) |
|||
{ |
|||
var w = camera.pixelWidth; |
|||
var h = camera.pixelHeight; |
|||
var numTilesX = (w + 15) / 16; |
|||
var numTilesY = (h + 15) / 16; |
|||
var numBigTilesX = (w + 63) / 64; |
|||
var numBigTilesY = (h + 63) / 64; |
|||
|
|||
var cmd = new CommandBuffer() { name = "Build light list" }; |
|||
|
|||
// generate screen-space AABBs (used for both fptl and clustered).
|
|||
{ |
|||
var proj = CameraProjection(camera); |
|||
var temp = new Matrix4x4(); |
|||
temp.SetRow(0, new Vector4(1.0f, 0.0f, 0.0f, 0.0f)); |
|||
temp.SetRow(1, new Vector4(0.0f, 1.0f, 0.0f, 0.0f)); |
|||
temp.SetRow(2, new Vector4(0.0f, 0.0f, 0.5f, 0.5f)); |
|||
temp.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); |
|||
var projh = temp * proj; |
|||
var invProjh = projh.inverse; |
|||
|
|||
cmd.SetComputeIntParam(buildScreenAABBShader, "g_iNrVisibLights", numLights); |
|||
SetMatrixCS(cmd, buildScreenAABBShader, "g_mProjection", projh); |
|||
SetMatrixCS(cmd, buildScreenAABBShader, "g_mInvProjection", invProjh); |
|||
cmd.SetComputeBufferParam(buildScreenAABBShader, s_GenAABBKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer); |
|||
cmd.DispatchCompute(buildScreenAABBShader, s_GenAABBKernel, (numLights + 7) / 8, 1, 1); |
|||
} |
|||
|
|||
// enable coarse 2D pass on 64x64 tiles (used for both fptl and clustered).
|
|||
if (enableBigTilePrepass) |
|||
{ |
|||
cmd.SetComputeIntParams(buildPerBigTileLightListShader, "g_viDimensions", new int[2] { w, h }); |
|||
cmd.SetComputeIntParam(buildPerBigTileLightListShader, "g_iNrVisibLights", numLights); |
|||
SetMatrixCS(cmd, buildPerBigTileLightListShader, "g_mScrProjection", projscr); |
|||
SetMatrixCS(cmd, buildPerBigTileLightListShader, "g_mInvScrProjection", invProjscr); |
|||
cmd.SetComputeFloatParam(buildPerBigTileLightListShader, "g_fNearPlane", camera.nearClipPlane); |
|||
cmd.SetComputeFloatParam(buildPerBigTileLightListShader, "g_fFarPlane", camera.farClipPlane); |
|||
cmd.SetComputeBufferParam(buildPerBigTileLightListShader, s_GenListPerBigTileKernel, "g_vLightList", s_BigTileLightList); |
|||
cmd.DispatchCompute(buildPerBigTileLightListShader, s_GenListPerBigTileKernel, numBigTilesX, numBigTilesY, 1); |
|||
} |
|||
|
|||
if (usingFptl) // optimized for opaques only
|
|||
{ |
|||
cmd.SetComputeIntParams(buildPerTileLightListShader, "g_viDimensions", new int[2] { w, h }); |
|||
cmd.SetComputeIntParam(buildPerTileLightListShader, "g_iNrVisibLights", numLights); |
|||
SetMatrixCS(cmd, buildPerTileLightListShader, "g_mScrProjection", projscr); |
|||
SetMatrixCS(cmd, buildPerTileLightListShader, "g_mInvScrProjection", invProjscr); |
|||
cmd.SetComputeTextureParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_depth_tex", new RenderTargetIdentifier(s_CameraDepthTexture)); |
|||
cmd.SetComputeBufferParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_vLightList", s_LightList); |
|||
if (enableBigTilePrepass) cmd.SetComputeBufferParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_vBigTileLightList", s_BigTileLightList); |
|||
cmd.DispatchCompute(buildPerTileLightListShader, s_GenListPerTileKernel, numTilesX, numTilesY, 1); |
|||
} |
|||
|
|||
if (enableClustered) // works for transparencies too.
|
|||
{ |
|||
VoxelLightListGeneration(cmd, camera, numLights, projscr, invProjscr); |
|||
} |
|||
|
|||
loop.ExecuteCommandBuffer(cmd); |
|||
cmd.Dispose(); |
|||
} |
|||
*/ |
|||
|
|||
public void PushGlobalParams(Camera camera, RenderLoop loop, HDRenderLoop.LightList lightList) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
// |
|||
// This file was automatically generated from Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.cs. Please don't edit by hand. |
|||
// |
|||
|
|||
#ifndef SINGLEPASS_CS_HLSL |
|||
#define SINGLEPASS_CS_HLSL |
|||
// |
|||
// UnityEngine.Experimental.ScriptableRenderLoop.ShadowType: static fields |
|||
// |
|||
#define SHADOWTYPE_SPOT (0) |
|||
#define SHADOWTYPE_DIRECTIONAL (1) |
|||
#define SHADOWTYPE_POINT (2) |
|||
|
|||
// Generated from UnityEngine.Experimental.ScriptableRenderLoop.PunctualShadowData |
|||
// PackingRules = Exact |
|||
struct PunctualShadowData |
|||
{ |
|||
float4x4 worldToShadow; |
|||
int shadowType; |
|||
float bias; |
|||
float quality; |
|||
float2 unused; |
|||
}; |
|||
|
|||
// |
|||
// Accessors for UnityEngine.Experimental.ScriptableRenderLoop.PunctualShadowData |
|||
// |
|||
float4x4 GetWorldToShadow(PunctualShadowData value) |
|||
{ |
|||
return value.worldToShadow; |
|||
} |
|||
int GetShadowType(PunctualShadowData value) |
|||
{ |
|||
return value.shadowType; |
|||
} |
|||
float GetBias(PunctualShadowData value) |
|||
{ |
|||
return value.bias; |
|||
} |
|||
float GetQuality(PunctualShadowData value) |
|||
{ |
|||
return value.quality; |
|||
} |
|||
float2 GetUnused(PunctualShadowData value) |
|||
{ |
|||
return value.unused; |
|||
} |
|||
|
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 353b54fe916c28f41b202e2d9396e4cf |
|||
timeCreated: 1477611341 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue