Antti Tapaninen
8 年前
当前提交
9e51e66d
共有 76 个文件被更改,包括 7706 次插入 和 0 次删除
-
9Assets/ScriptableRenderPipeline/fptl.meta
-
9Assets/TestScenes/FPTL.meta
-
12Assets/ScriptableRenderPipeline/fptl/FptlLighting.cs.meta
-
9Assets/ScriptableRenderPipeline/fptl/Internal-DeferredReflections.shader.meta
-
9Assets/ScriptableRenderPipeline/fptl/Internal-DeferredShading.shader.meta
-
12Assets/ScriptableRenderPipeline/fptl/LightDefinitions.cs.meta
-
9Assets/ScriptableRenderPipeline/fptl/lightlistbuild.compute.meta
-
466Assets/ScriptableRenderPipeline/fptl/scrbound.compute
-
9Assets/ScriptableRenderPipeline/fptl/scrbound.compute.meta
-
48Assets/ScriptableRenderPipeline/fptl/FinalPass.shader
-
9Assets/ScriptableRenderPipeline/fptl/FinalPass.shader.meta
-
9Assets/ScriptableRenderPipeline/fptl/lightlistbuild-clustered.compute.meta
-
90Assets/ScriptableRenderPipeline/fptl/ClusteredUtils.h
-
20Assets/ScriptableRenderPipeline/fptl/ClusteredUtils.h.meta
-
9Assets/ScriptableRenderPipeline/fptl/LightDefinitions.cs.hlsl.meta
-
172Assets/ScriptableRenderPipeline/fptl/StandardTest.shader
-
165Assets/ScriptableRenderPipeline/fptl/ReflectionTemplate.hlsl
-
9Assets/ScriptableRenderPipeline/fptl/LightingTemplate.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/ReflectionTemplate.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/StandardTest.shader.meta
-
9Assets/ScriptableRenderPipeline/fptl/TiledLightingTemplate.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/TiledLightingUtils.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/TiledReflectionTemplate.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/UnityStandardForwardNew.cginc.meta
-
9Assets/ScriptableRenderPipeline/fptl/LightingUtils.hlsl.meta
-
19Assets/ScriptableRenderPipeline/fptl/RegularForwardLightingTemplate.hlsl
-
25Assets/ScriptableRenderPipeline/fptl/RegularForwardLightingUtils.hlsl
-
18Assets/ScriptableRenderPipeline/fptl/RegularForwardReflectionTemplate.hlsl
-
9Assets/ScriptableRenderPipeline/fptl/RegularForwardLightingTemplate.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/RegularForwardLightingUtils.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/RegularForwardReflectionTemplate.hlsl.meta
-
154Assets/ScriptableRenderPipeline/fptl/UnityStandardForwardNew.cginc
-
9Assets/ScriptableRenderPipeline/fptl/LightBoundsDebug.shader.meta
-
9Assets/ScriptableRenderPipeline/fptl/LightingConvexHullUtils.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/lightlistbuild-bigtile.compute.meta
-
117Assets/ScriptableRenderPipeline/fptl/SortingComputeUtils.hlsl
-
9Assets/ScriptableRenderPipeline/fptl/SortingComputeUtils.hlsl.meta
-
9Assets/ScriptableRenderPipeline/fptl/Internal-DeferredComputeShading.compute.meta
-
139Assets/ScriptableRenderPipeline/fptl/LightingUtils.hlsl
-
281Assets/ScriptableRenderPipeline/fptl/LightingTemplate.hlsl
-
146Assets/ScriptableRenderPipeline/fptl/Internal-DeferredComputeShading.compute
-
131Assets/ScriptableRenderPipeline/fptl/LightingConvexHullUtils.hlsl
-
9Assets/ScriptableRenderPipeline/fptl/FPTLRenderPipeline.asset.meta
-
48Assets/ScriptableRenderPipeline/fptl/FPTLRenderPipeline.asset
-
440Assets/ScriptableRenderPipeline/fptl/lightlistbuild.compute
-
270Assets/ScriptableRenderPipeline/fptl/lightlistbuild-bigtile.compute
-
63Assets/ScriptableRenderPipeline/fptl/LightBoundsDebug.shader
-
140Assets/ScriptableRenderPipeline/fptl/Internal-DeferredShading.shader
-
146Assets/ScriptableRenderPipeline/fptl/Internal-DeferredReflections.shader
-
97Assets/ScriptableRenderPipeline/fptl/LightDefinitions.cs
-
229Assets/ScriptableRenderPipeline/fptl/LightDefinitions.cs.hlsl
-
19Assets/ScriptableRenderPipeline/fptl/TiledLightingTemplate.hlsl
-
100Assets/ScriptableRenderPipeline/fptl/TiledLightingUtils.hlsl
-
20Assets/ScriptableRenderPipeline/fptl/TiledReflectionTemplate.hlsl
-
558Assets/ScriptableRenderPipeline/fptl/lightlistbuild-clustered.compute
-
1001Assets/ScriptableRenderPipeline/fptl/FptlLighting.cs
-
9Assets/TestScenes/FPTL/FPTL.meta
-
8Assets/TestScenes/FPTL/FPTL.unity.meta
-
9Assets/TestScenes/FPTL/Materials.meta
-
1001Assets/TestScenes/FPTL/FPTL.unity
-
7Assets/TestScenes/FPTL/FPTL/LightingData.asset
-
8Assets/TestScenes/FPTL/FPTL/LightingData.asset.meta
-
891Assets/TestScenes/FPTL/FPTL/ReflectionProbe-0.exr
-
101Assets/TestScenes/FPTL/FPTL/ReflectionProbe-0.exr.meta
-
8Assets/TestScenes/FPTL/Materials/Custom_NewSurfaceShader.mat.meta
-
8Assets/TestScenes/FPTL/Materials/gray.mat.meta
-
8Assets/TestScenes/FPTL/Materials/FwdMat.mat.meta
-
80Assets/TestScenes/FPTL/Materials/Custom_NewSurfaceShader.mat
-
108Assets/TestScenes/FPTL/Materials/gray.mat
-
80Assets/TestScenes/fptl/Materials/FwdMat.mat
|
|||
fileFormatVersion: 2 |
|||
guid: 4ae727bb0a95bdf4aada784867082de5 |
|||
folderAsset: yes |
|||
timeCreated: 1467916766 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: e6f3b555b1b3c514f823d65f7bdbbf9e |
|||
folderAsset: yes |
|||
timeCreated: 1473161495 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: ad5bf4f8e45bdd1429eadc3445df2c89 |
|||
timeCreated: 1467917164 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 3899e06d641c2cb4cbff794df0da536b |
|||
timeCreated: 1467917168 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 1c102a89f3460254a8c413dbdcd63a2a |
|||
timeCreated: 1467917168 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: b796ac9ec090af44aba9d5cf983c21b3 |
|||
timeCreated: 1467917164 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: f54ef7cb596a714488693ef9cdaf63fb |
|||
timeCreated: 1467917168 |
|||
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 ScreenBoundsAABB |
|||
|
|||
#include "..\common\ShaderBase.h" |
|||
#include "LightDefinitions.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; |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e7a739144e735934b89a42a4b9d9e23c |
|||
timeCreated: 1467917168 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 4 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
// Final compositing pass, just does gamma conversion for now. |
|||
|
|||
Shader "Hidden/FinalPass" |
|||
{ |
|||
Properties { _MainTex ("Texture", any) = "" {} } |
|||
SubShader { |
|||
Pass { |
|||
ZTest Always Cull Off ZWrite Off |
|||
|
|||
CGPROGRAM |
|||
#pragma vertex vert |
|||
#pragma fragment frag |
|||
#pragma target 2.0 |
|||
#pragma multi_compile __ UNITY_COLORSPACE_GAMMA |
|||
|
|||
#include "UnityCG.cginc" |
|||
|
|||
sampler2D _MainTex; |
|||
uniform float4 _MainTex_ST; |
|||
|
|||
struct appdata_t { |
|||
float4 vertex : POSITION; |
|||
float2 texcoord : TEXCOORD0; |
|||
}; |
|||
|
|||
struct v2f { |
|||
float4 vertex : SV_POSITION; |
|||
float2 texcoord : TEXCOORD0; |
|||
}; |
|||
|
|||
v2f vert (appdata_t v) |
|||
{ |
|||
v2f o; |
|||
o.vertex = UnityObjectToClipPos(v.vertex); |
|||
o.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex); |
|||
return o; |
|||
} |
|||
|
|||
fixed4 frag (v2f i) : SV_Target |
|||
{ |
|||
return tex2D(_MainTex, i.texcoord); |
|||
} |
|||
ENDCG |
|||
|
|||
} |
|||
} |
|||
Fallback Off |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5590f54ad211f594da4e687b698f2258 |
|||
timeCreated: 1474297133 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 4c2d6eb0553e2514bba3ea9a85d8c53c |
|||
timeCreated: 1475075348 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 4 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#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: cbef1fe8de4d82246b1f88d4dcc90833 |
|||
timeCreated: 1475179985 |
|||
licenseType: Pro |
|||
PluginImporter: |
|||
serializedVersion: 1 |
|||
iconMap: {} |
|||
executionOrder: {} |
|||
isPreloaded: 0 |
|||
platformData: |
|||
Any: |
|||
enabled: 1 |
|||
settings: {} |
|||
Editor: |
|||
enabled: 0 |
|||
settings: |
|||
DefaultValueInitialized: true |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 70f1451131ffdfa4798fd3c62bd0ec51 |
|||
timeCreated: 1475179983 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
Shader "Experim/StdShader" |
|||
{ |
|||
Properties |
|||
{ |
|||
_Color("Color", Color) = (1,1,1,1) |
|||
_MainTex("Albedo", 2D) = "white" {} |
|||
|
|||
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 |
|||
|
|||
_Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5 |
|||
_GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0 |
|||
[Enum(Metallic Alpha,0,Albedo Alpha,1)] _SmoothnessTextureChannel ("Smoothness texture channel", Float) = 0 |
|||
|
|||
[Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 |
|||
_MetallicGlossMap("Metallic", 2D) = "white" {} |
|||
|
|||
[ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 |
|||
[ToggleOff] _GlossyReflections("Glossy Reflections", Float) = 1.0 |
|||
|
|||
_BumpScale("Scale", Float) = 1.0 |
|||
_BumpMap("Normal Map", 2D) = "bump" {} |
|||
|
|||
_Parallax ("Height Scale", Range (0.005, 0.08)) = 0.02 |
|||
_ParallaxMap ("Height Map", 2D) = "black" {} |
|||
|
|||
_OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0 |
|||
_OcclusionMap("Occlusion", 2D) = "white" {} |
|||
|
|||
_EmissionColor("Color", Color) = (0,0,0) |
|||
_EmissionMap("Emission", 2D) = "white" {} |
|||
|
|||
_DetailMask("Detail Mask", 2D) = "white" {} |
|||
|
|||
_DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {} |
|||
_DetailNormalMapScale("Scale", Float) = 1.0 |
|||
_DetailNormalMap("Normal Map", 2D) = "bump" {} |
|||
|
|||
[Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0 |
|||
|
|||
|
|||
// Blending state |
|||
[HideInInspector] _Mode ("__mode", Float) = 0.0 |
|||
[HideInInspector] _SrcBlend ("__src", Float) = 1.0 |
|||
[HideInInspector] _DstBlend ("__dst", Float) = 0.0 |
|||
[HideInInspector] _ZWrite ("__zw", Float) = 1.0 |
|||
} |
|||
|
|||
CGINCLUDE |
|||
#define UNITY_SETUP_BRDF_INPUT MetallicSetup |
|||
ENDCG |
|||
|
|||
SubShader |
|||
{ |
|||
Tags { "RenderType" = "Opaque" "PerformanceChecks" = "False" } |
|||
LOD 300 |
|||
|
|||
|
|||
// ------------------------------------------------------------------ |
|||
// Forward pass |
|||
Pass |
|||
{ |
|||
Name "FORWARD" |
|||
Tags { "LightMode" = "ForwardSinglePass" } |
|||
|
|||
Blend [_SrcBlend] [_DstBlend] |
|||
ZWrite [_ZWrite] |
|||
|
|||
CGPROGRAM |
|||
#pragma target 4.5 |
|||
|
|||
// ------------------------------------- |
|||
|
|||
#pragma shader_feature _NORMALMAP |
|||
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON |
|||
#pragma shader_feature _EMISSION |
|||
#pragma shader_feature _METALLICGLOSSMAP |
|||
#pragma shader_feature ___ _DETAIL_MULX2 |
|||
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A |
|||
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF |
|||
#pragma shader_feature _ _GLOSSYREFLECTIONS_OFF |
|||
#pragma shader_feature _PARALLAXMAP |
|||
|
|||
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON |
|||
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE |
|||
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON |
|||
#pragma multi_compile_fog |
|||
#pragma multi_compile TILED_FORWARD REGULAR_FORWARD |
|||
|
|||
#pragma vertex vertForward |
|||
#pragma fragment fragForward |
|||
|
|||
#include "UnityStandardForwardNew.cginc" |
|||
|
|||
|
|||
ENDCG |
|||
} |
|||
|
|||
// ------------------------------------------------------------------ |
|||
// Depth Only |
|||
Pass |
|||
{ |
|||
Name "DEPTHONLY" |
|||
Tags { "LightMode" = "DepthOnly" } |
|||
|
|||
Blend [_SrcBlend] [_DstBlend] |
|||
//ZWrite [_ZWrite] |
|||
ZWrite On ZTest LEqual |
|||
|
|||
CGPROGRAM |
|||
#pragma target 4.5 |
|||
|
|||
// TODO: figure out what's needed here wrt. alpha test etc. |
|||
|
|||
#pragma shader_feature _NORMALMAP |
|||
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON |
|||
#pragma shader_feature _EMISSION |
|||
#pragma shader_feature _METALLICGLOSSMAP |
|||
#pragma shader_feature ___ _DETAIL_MULX2 |
|||
#pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A |
|||
#pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF |
|||
#pragma shader_feature _ _GLOSSYREFLECTIONS_OFF |
|||
#pragma shader_feature _PARALLAXMAP |
|||
|
|||
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON |
|||
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE |
|||
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON |
|||
#pragma multi_compile_fog |
|||
|
|||
#pragma vertex vertForward |
|||
#pragma fragment fragNoLight |
|||
|
|||
#include "UnityStandardForwardNew.cginc" |
|||
|
|||
|
|||
ENDCG |
|||
} |
|||
|
|||
|
|||
// ------------------------------------------------------------------ |
|||
// Shadow rendering pass |
|||
Pass { |
|||
Name "ShadowCaster" |
|||
Tags { "LightMode" = "ShadowCaster" } |
|||
|
|||
ZWrite On ZTest LEqual |
|||
|
|||
CGPROGRAM |
|||
#pragma target 4.5 |
|||
|
|||
// ------------------------------------- |
|||
|
|||
|
|||
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON |
|||
#pragma shader_feature _METALLICGLOSSMAP |
|||
#pragma multi_compile_shadowcaster |
|||
|
|||
#pragma vertex vertShadowCaster |
|||
#pragma fragment fragShadowCaster |
|||
|
|||
#include "UnityStandardShadow.cginc" |
|||
|
|||
ENDCG |
|||
} |
|||
// ------------------------------------------------------------------ |
|||
// Deferred pass |
|||
|
|||
} |
|||
|
|||
|
|||
FallBack "VertexLit" |
|||
CustomEditor "StandardShaderGUI" |
|||
} |
|
|||
#ifndef __REFLECTIONTEMPLATE_H__ |
|||
#define __REFLECTIONTEMPLATE_H__ |
|||
|
|||
#include "UnityCG.cginc" |
|||
#include "UnityStandardBRDF.cginc" |
|||
#include "UnityStandardUtils.cginc" |
|||
#include "UnityPBSLighting.cginc" |
|||
|
|||
|
|||
UNITY_DECLARE_ABSTRACT_CUBE_ARRAY(_reflCubeTextures); |
|||
UNITY_DECLARE_TEXCUBE(_reflRootCubeTexture); |
|||
//uniform int _reflRootSliceIndex; |
|||
uniform float _reflRootHdrDecodeMult; |
|||
uniform float _reflRootHdrDecodeExp; |
|||
|
|||
|
|||
half3 Unity_GlossyEnvironment (UNITY_ARGS_ABSTRACT_CUBE_ARRAY(tex), int sliceIndex, half4 hdr, Unity_GlossyEnvironmentData glossIn); |
|||
|
|||
half3 distanceFromAABB(half3 p, half3 aabbMin, half3 aabbMax) |
|||
{ |
|||
return max(max(p - aabbMax, aabbMin - p), half3(0.0, 0.0, 0.0)); |
|||
} |
|||
|
|||
|
|||
float3 ExecuteReflectionList(uint start, uint numReflProbes, float3 vP, float3 vNw, float3 Vworld, float smoothness) |
|||
{ |
|||
float3 worldNormalRefl = reflect(-Vworld, vNw); |
|||
|
|||
float3 vspaceRefl = mul((float3x3) g_mWorldToView, worldNormalRefl).xyz; |
|||
|
|||
float percRoughness = SmoothnessToPerceptualRoughness(smoothness); |
|||
|
|||
UnityLight light; |
|||
light.color = 0; |
|||
light.dir = 0; |
|||
|
|||
float3 ints = 0; |
|||
|
|||
// root ibl begin |
|||
{ |
|||
Unity_GlossyEnvironmentData g; |
|||
g.roughness = percRoughness; |
|||
g.reflUVW = worldNormalRefl; |
|||
|
|||
half3 env0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBE(_reflRootCubeTexture), float4(_reflRootHdrDecodeMult, _reflRootHdrDecodeExp, 0.0, 0.0), g); |
|||
//half3 env0 = Unity_GlossyEnvironment(UNITY_PASS_TEXCUBEARRAY(_reflCubeTextures), _reflRootSliceIndex, float4(_reflRootHdrDecodeMult, _reflRootHdrDecodeExp, 0.0, 0.0), g); |
|||
|
|||
UnityIndirect ind; |
|||
ind.diffuse = 0; |
|||
ind.specular = env0;// * data.occlusion; |
|||
ints = EvalIndirectSpecular(light, ind); |
|||
} |
|||
// root ibl end |
|||
|
|||
uint l=0; |
|||
// don't need the outer loop since the probes are sorted by volume type (currently one type in fact) |
|||
//while(l<numReflProbes) |
|||
if(numReflProbes>0) |
|||
{ |
|||
uint uIndex = l<numReflProbes ? FetchIndex(start, l) : 0; |
|||
uint uLgtType = l<numReflProbes ? g_vLightData[uIndex].lightType : 0; |
|||
|
|||
// specialized loop for sphere lights |
|||
while(l<numReflProbes && uLgtType==(uint) BOX_LIGHT) |
|||
{ |
|||
SFiniteLightData lgtDat = g_vLightData[uIndex]; |
|||
float3 vLp = lgtDat.lightPos.xyz; |
|||
float3 vecToSurfPos = vP - vLp; // vector from reflection volume to surface position in camera space |
|||
float3 posInReflVolumeSpace = float3( dot(vecToSurfPos, lgtDat.lightAxisX), dot(vecToSurfPos, lgtDat.lightAxisY), dot(vecToSurfPos, lgtDat.lightAxisZ) ); |
|||
|
|||
|
|||
float blendDistance = lgtDat.probeBlendDistance;//unity_SpecCube1_ProbePosition.w; // will be set to blend distance for this probe |
|||
|
|||
float3 sampleDir; |
|||
if((lgtDat.flags&IS_BOX_PROJECTED)!=0) |
|||
{ |
|||
// For box projection, use expanded bounds as they are rendered; otherwise |
|||
// box projection artifacts when outside of the box. |
|||
//float4 boxMin = unity_SpecCube0_BoxMin - float4(blendDistance,blendDistance,blendDistance,0); |
|||
//float4 boxMax = unity_SpecCube0_BoxMax + float4(blendDistance,blendDistance,blendDistance,0); |
|||
//sampleDir = BoxProjectedCubemapDirection (worldNormalRefl, worldPos, unity_SpecCube0_ProbePosition, boxMin, boxMax); |
|||
|
|||
float4 boxOuterDistance = float4( lgtDat.boxInnerDist + float3(blendDistance, blendDistance, blendDistance), 0.0 ); |
|||
#if 0 |
|||
// if rotation is NOT supported |
|||
sampleDir = BoxProjectedCubemapDirection(worldNormalRefl, posInReflVolumeSpace, float4(lgtDat.localCubeCapturePoint, 1.0), -boxOuterDistance, boxOuterDistance); |
|||
#else |
|||
float3 volumeSpaceRefl = float3( dot(vspaceRefl, lgtDat.lightAxisX), dot(vspaceRefl, lgtDat.lightAxisY), dot(vspaceRefl, lgtDat.lightAxisZ) ); |
|||
float3 vPR = BoxProjectedCubemapDirection(volumeSpaceRefl, posInReflVolumeSpace, float4(lgtDat.localCubeCapturePoint, 1.0), -boxOuterDistance, boxOuterDistance); // Volume space corrected reflection vector |
|||
sampleDir = mul( (float3x3) g_mViewToWorld, vPR.x*lgtDat.lightAxisX + vPR.y*lgtDat.lightAxisY + vPR.z*lgtDat.lightAxisZ ); |
|||
#endif |
|||
} |
|||
else |
|||
sampleDir = worldNormalRefl; |
|||
|
|||
Unity_GlossyEnvironmentData g; |
|||
g.roughness = percRoughness; |
|||
g.reflUVW = sampleDir; |
|||
|
|||
half3 env0 = Unity_GlossyEnvironment(UNITY_PASS_ABSTRACT_CUBE_ARRAY(_reflCubeTextures), lgtDat.sliceIndex, float4(lgtDat.lightIntensity, lgtDat.decodeExp, 0.0, 0.0), g); |
|||
|
|||
|
|||
UnityIndirect ind; |
|||
ind.diffuse = 0; |
|||
ind.specular = env0;// * data.occlusion; |
|||
|
|||
//half3 rgb = UNITY_BRDF_PBS(0, data.specularColor, oneMinusReflectivity, data.smoothness, data.normalWorld, vWSpaceVDir, light, ind).rgb; |
|||
half3 rgb = EvalIndirectSpecular(light, ind); |
|||
|
|||
// Calculate falloff value, so reflections on the edges of the Volume would gradually blend to previous reflection. |
|||
// Also this ensures that pixels not located in the reflection Volume AABB won't |
|||
// accidentally pick up reflections from this Volume. |
|||
//half3 distance = distanceFromAABB(worldPos, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz); |
|||
half3 distance = distanceFromAABB(posInReflVolumeSpace, -lgtDat.boxInnerDist, lgtDat.boxInnerDist); |
|||
half falloff = saturate(1.0 - length(distance)/blendDistance); |
|||
|
|||
ints = lerp(ints, rgb, falloff); |
|||
|
|||
// next probe |
|||
++l; uIndex = l<numReflProbes ? FetchIndex(start, l) : 0; |
|||
uLgtType = l<numReflProbes ? g_vLightData[uIndex].lightType : 0; |
|||
} |
|||
|
|||
//if(uLgtType!=BOX_LIGHT) ++l; |
|||
} |
|||
|
|||
return ints; |
|||
} |
|||
|
|||
|
|||
half3 Unity_GlossyEnvironment (UNITY_ARGS_ABSTRACT_CUBE_ARRAY(tex), int sliceIndex, half4 hdr, Unity_GlossyEnvironmentData glossIn) |
|||
{ |
|||
#if UNITY_GLOSS_MATCHES_MARMOSET_TOOLBAG2 && (SHADER_TARGET >= 30) |
|||
// TODO: remove pow, store cubemap mips differently |
|||
half perceptualRoughness = pow(glossIn.roughness, 3.0/4.0); |
|||
#else |
|||
half perceptualRoughness = glossIn.roughness; // MM: switched to this |
|||
#endif |
|||
//perceptualRoughness = sqrt(sqrt(2/(64.0+2))); // spec power to the square root of real roughness |
|||
|
|||
#if 0 |
|||
float m = perceptualRoughness*perceptualRoughness; // m is the real roughness parameter |
|||
const float fEps = 1.192092896e-07F; // smallest such that 1.0+FLT_EPSILON != 1.0 (+1e-4h is NOT good here. is visibly very wrong) |
|||
float n = (2.0/max(fEps, m*m))-2.0; // remap to spec power. See eq. 21 in --> https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf |
|||
|
|||
n /= 4; // remap from n_dot_h formulatino to n_dot_r. See section "Pre-convolved Cube Maps vs Path Tracers" --> https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html |
|||
|
|||
perceptualRoughness = pow( 2/(n+2), 0.25); // remap back to square root of real roughness |
|||
#else |
|||
// MM: came up with a surprisingly close approximation to what the #if 0'ed out code above does. |
|||
perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness); |
|||
#endif |
|||
|
|||
|
|||
|
|||
half mip = perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS; |
|||
half4 rgbm = UNITY_SAMPLE_ABSTRACT_CUBE_ARRAY_LOD(tex, float4(glossIn.reflUVW.xyz, sliceIndex), mip); |
|||
|
|||
return DecodeHDR(rgbm, hdr); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 055113b0dcb47d0468619612ccb7de75 |
|||
timeCreated: 1476168722 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 7e1ced85dc3e259469da295c01d95ecd |
|||
timeCreated: 1476168722 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 8f28d6dbfdba66d4dbae80224aca5669 |
|||
timeCreated: 1476168726 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: b25f3fae508f5c04f8f15d77515e4a23 |
|||
timeCreated: 1476168722 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 25c458a8106d44444bea6b074b79cfdf |
|||
timeCreated: 1476168722 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: a9b744e06937f8d4ca633dfa63e357b4 |
|||
timeCreated: 1476168722 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: c185aa276c9670d4381a830ece205577 |
|||
timeCreated: 1476168722 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 0f0336214df2a1845afb1ce1b72075f5 |
|||
timeCreated: 1476376272 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef __REGULARFORWARDLIGHTINGTEMPLATE_H__ |
|||
#define __REGULARFORWARDLIGHTINGTEMPLATE_H__ |
|||
|
|||
|
|||
#include "RegularForwardLightingUtils.hlsl" |
|||
#include "LightingTemplate.hlsl" |
|||
|
|||
|
|||
float3 ExecuteLightList(out uint numLightsProcessed, uint2 pixCoord, float3 vP, float3 vPw, float3 Vworld) |
|||
{ |
|||
uint start = 0, numLights = 0; |
|||
GetCountAndStart(start, numLights, DIRECT_LIGHT); |
|||
|
|||
numLightsProcessed = numLights; // mainly for debugging/heat maps |
|||
return ExecuteLightList(start, numLights, vP, vPw, Vworld); |
|||
} |
|||
|
|||
|
|||
#endif |
|
|||
#ifndef __REGULARFORWARDLIGHTINGUTILS_H__ |
|||
#define __REGULARFORWARDLIGHTINGUTILS_H__ |
|||
|
|||
|
|||
#include "LightingUtils.hlsl" |
|||
|
|||
|
|||
StructuredBuffer<SFiniteLightData> g_vLightData; |
|||
Buffer<uint> g_vLightListMeshInst; // build on CPU if in use. direct lights first, then reflection probes. |
|||
|
|||
uniform int g_numLights; |
|||
uniform int g_numReflectionProbes; |
|||
|
|||
void GetCountAndStart(out uint start, out uint nrLights, uint model) |
|||
{ |
|||
start = model==REFLECTION_LIGHT ? g_numLights : 0; // offset by numLights entries |
|||
nrLights = model==REFLECTION_LIGHT ? g_numReflectionProbes : g_numLights; |
|||
} |
|||
|
|||
uint FetchIndex(const uint start, const uint l) |
|||
{ |
|||
return g_vLightListMeshInst[start+l]; |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef __REGULARFORWARDREFLECTIONTEMPLATE_H__ |
|||
#define __REGULARFORWARDREFLECTIONTEMPLATE_H__ |
|||
|
|||
|
|||
#include "RegularForwardLightingUtils.hlsl" |
|||
#include "ReflectionTemplate.hlsl" |
|||
|
|||
|
|||
float3 ExecuteReflectionList(out uint numReflectionProbesProcessed, uint2 pixCoord, float3 vP, float3 vNw, float3 Vworld, float smoothness) |
|||
{ |
|||
uint start = 0, numReflectionProbes = 0; |
|||
GetCountAndStart(start, numReflectionProbes, REFLECTION_LIGHT); |
|||
|
|||
numReflectionProbesProcessed = numReflectionProbes; // mainly for debugging/heat maps |
|||
return ExecuteReflectionList(start, numReflectionProbes, vP, vNw, Vworld, smoothness); |
|||
} |
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: addc185d48decc34d9bf21cb3a4ea28c |
|||
timeCreated: 1476774180 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 13dff6ea8f6c55743a3cbb841066cc27 |
|||
timeCreated: 1476774180 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 61d33edab0cf72c4e881ea8c05dcd596 |
|||
timeCreated: 1476774180 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef UNITY_STANDARD_FORWARDNEW_INCLUDED |
|||
#define UNITY_STANDARD_FORWARDNEW_INCLUDED |
|||
|
|||
|
|||
// NOTE: had to split shadow functions into separate file, |
|||
// otherwise compiler gives trouble with LIGHTING_COORDS macro (in UnityStandardCore.cginc) |
|||
|
|||
#include "UnityStandardConfig.cginc" |
|||
#include "UnityStandardCore.cginc" |
|||
|
|||
struct VertexOutputForwardNew |
|||
{ |
|||
float4 pos : SV_POSITION; |
|||
float4 tex : TEXCOORD0; |
|||
half4 ambientOrLightmapUV : TEXCOORD1; // SH or Lightmap UV |
|||
half4 tangentToWorldAndParallax[3] : TEXCOORD2; // [3x3:tangentToWorld | 1x3:empty] |
|||
|
|||
LIGHTING_COORDS(5,6) |
|||
UNITY_FOG_COORDS(7) |
|||
|
|||
UNITY_VERTEX_OUTPUT_STEREO |
|||
}; |
|||
|
|||
|
|||
|
|||
VertexOutputForwardNew vertForward(VertexInput v) |
|||
{ |
|||
UNITY_SETUP_INSTANCE_ID(v); |
|||
VertexOutputForwardNew o; |
|||
UNITY_INITIALIZE_OUTPUT(VertexOutputForwardNew, o); |
|||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); |
|||
|
|||
float4 posWorld = mul(unity_ObjectToWorld, v.vertex); |
|||
o.pos = UnityObjectToClipPos(v.vertex); |
|||
|
|||
o.tex = TexCoords(v); |
|||
|
|||
float3 normalWorld = UnityObjectToWorldNormal(v.normal); |
|||
#ifdef _TANGENT_TO_WORLD |
|||
float4 tangentWorld = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); |
|||
|
|||
float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld.xyz, tangentWorld.w); |
|||
o.tangentToWorldAndParallax[0].xyz = tangentToWorld[0]; |
|||
o.tangentToWorldAndParallax[1].xyz = tangentToWorld[1]; |
|||
o.tangentToWorldAndParallax[2].xyz = tangentToWorld[2]; |
|||
#else |
|||
o.tangentToWorldAndParallax[0].xyz = 0; |
|||
o.tangentToWorldAndParallax[1].xyz = 0; |
|||
o.tangentToWorldAndParallax[2].xyz = normalWorld; |
|||
#endif |
|||
|
|||
o.ambientOrLightmapUV = VertexGIForward(v, posWorld, normalWorld); |
|||
|
|||
UNITY_TRANSFER_FOG(o,o.pos); |
|||
|
|||
return o; |
|||
} |
|||
|
|||
#include "LightingUtils.hlsl" |
|||
|
|||
static FragmentCommonData gdata; |
|||
static float occlusion; |
|||
|
|||
half4 fragNoLight(VertexOutputForwardNew i) : SV_Target |
|||
{ |
|||
float linZ = GetLinearZFromSVPosW(i.pos.w); // matching script side where camera space is right handed. |
|||
float3 vP = GetViewPosFromLinDepth(i.pos.xy, linZ); |
|||
float3 vPw = mul(g_mViewToWorld, float4(vP,1.0)).xyz; |
|||
float3 Vworld = normalize(mul((float3x3) g_mViewToWorld, -vP).xyz); // not same as unity_CameraToWorld |
|||
|
|||
#ifdef _PARALLAXMAP |
|||
half3 tangent = i.tangentToWorldAndParallax[0].xyz; |
|||
half3 bitangent = i.tangentToWorldAndParallax[1].xyz; |
|||
half3 normal = i.tangentToWorldAndParallax[2].xyz; |
|||
float3 vDirForParallax = float3( dot(tangent, Vworld), dot(bitangent, Vworld), dot(normal, Vworld)); |
|||
#else |
|||
float3 vDirForParallax = Vworld; |
|||
#endif |
|||
gdata = FragmentSetup(i.tex, -Vworld, vDirForParallax, i.tangentToWorldAndParallax, vPw); // eyeVec = -Vworld |
|||
|
|||
return OutputForward (float4(0.0,0.0,0.0,1.0), gdata.alpha); // figure out some alpha test stuff |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
float3 EvalMaterial(UnityLight light, UnityIndirect ind) |
|||
{ |
|||
return UNITY_BRDF_PBS(gdata.diffColor, gdata.specColor, gdata.oneMinusReflectivity, gdata.smoothness, gdata.normalWorld, -gdata.eyeVec, light, ind); |
|||
} |
|||
|
|||
float3 EvalIndirectSpecular(UnityLight light, UnityIndirect ind) |
|||
{ |
|||
return occlusion * UNITY_BRDF_PBS(gdata.diffColor, gdata.specColor, gdata.oneMinusReflectivity, gdata.smoothness, gdata.normalWorld, -gdata.eyeVec, light, ind); |
|||
} |
|||
|
|||
|
|||
#ifdef REGULAR_FORWARD |
|||
|
|||
#include "RegularForwardLightingTemplate.hlsl" |
|||
#include "RegularForwardReflectionTemplate.hlsl" |
|||
|
|||
#else |
|||
|
|||
#include "TiledLightingTemplate.hlsl" |
|||
#include "TiledReflectionTemplate.hlsl" |
|||
|
|||
#endif |
|||
|
|||
|
|||
half4 fragForward(VertexOutputForwardNew i) : SV_Target |
|||
{ |
|||
float linZ = GetLinearZFromSVPosW(i.pos.w); // matching script side where camera space is right handed. |
|||
float3 vP = GetViewPosFromLinDepth(i.pos.xy, linZ); |
|||
float3 vPw = mul(g_mViewToWorld, float4(vP,1.0)).xyz; |
|||
float3 Vworld = normalize(mul((float3x3) g_mViewToWorld, -vP).xyz); // not same as unity_CameraToWorld |
|||
|
|||
#ifdef _PARALLAXMAP |
|||
half3 tangent = i.tangentToWorldAndParallax[0].xyz; |
|||
half3 bitangent = i.tangentToWorldAndParallax[1].xyz; |
|||
half3 normal = i.tangentToWorldAndParallax[2].xyz; |
|||
float3 vDirForParallax = float3( dot(tangent, Vworld), dot(bitangent, Vworld), dot(normal, Vworld)); |
|||
#else |
|||
float3 vDirForParallax = Vworld; |
|||
#endif |
|||
gdata = FragmentSetup(i.tex, -Vworld, vDirForParallax, i.tangentToWorldAndParallax, vPw); // eyeVec = -Vworld |
|||
|
|||
|
|||
uint2 pixCoord = ((uint2) i.pos.xy); |
|||
|
|||
float atten = 1.0; |
|||
occlusion = Occlusion(i.tex.xy); |
|||
UnityGI gi = FragmentGI (gdata, occlusion, i.ambientOrLightmapUV, atten, DummyLight(), false); |
|||
|
|||
uint numLightsProcessed = 0, numReflectionsProcessed = 0; |
|||
float3 res = 0; |
|||
|
|||
// direct light contributions |
|||
res += ExecuteLightList(numLightsProcessed, pixCoord, vP, vPw, Vworld); |
|||
|
|||
// specular GI |
|||
res += ExecuteReflectionList(numReflectionsProcessed, pixCoord, vP, gdata.normalWorld, Vworld, gdata.smoothness); |
|||
|
|||
// diffuse GI |
|||
res += UNITY_BRDF_PBS (gdata.diffColor, gdata.specColor, gdata.oneMinusReflectivity, gdata.smoothness, gdata.normalWorld, -gdata.eyeVec, gi.light, gi.indirect).xyz; |
|||
res += UNITY_BRDF_GI (gdata.diffColor, gdata.specColor, gdata.oneMinusReflectivity, gdata.smoothness, gdata.normalWorld, -gdata.eyeVec, occlusion, gi); |
|||
|
|||
//res = OverlayHeatMap(numLightsProcessed, res); |
|||
|
|||
//UNITY_APPLY_FOG(i.fogCoord, res); |
|||
return OutputForward (float4(res,1.0), gdata.alpha); |
|||
} |
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 33f2a444e9120d34396d41e40795d712 |
|||
timeCreated: 1477309800 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 97c18f9b04997a34aa7a246dbc1b2fac |
|||
timeCreated: 1477394758 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: b5507a2ffdae8a84f94211c10d428920 |
|||
timeCreated: 1477394781 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 4 |
|||
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: 5c0b30845c471c449967253c8cdf5bc2 |
|||
timeCreated: 1477583748 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 6994e4f8a80d87b428cca7242cb32a0e |
|||
timeCreated: 1478685321 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef __LIGHTINGUTILS_H__ |
|||
#define __LIGHTINGUTILS_H__ |
|||
|
|||
|
|||
#include "..\common\ShaderBase.h" |
|||
#include "LightDefinitions.cs.hlsl" |
|||
|
|||
|
|||
uniform float4x4 g_mViewToWorld; |
|||
uniform float4x4 g_mWorldToView; // used for reflection only |
|||
uniform float4x4 g_mScrProjection; |
|||
uniform float4x4 g_mInvScrProjection; |
|||
|
|||
|
|||
uniform uint g_widthRT; |
|||
uniform uint g_heightRT; |
|||
|
|||
|
|||
float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth) |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
//float fCx = g_mScrProjection[2].x; |
|||
float fCx = g_mScrProjection[0].z; |
|||
float fSy = g_mScrProjection[1].y; |
|||
//float fCy = g_mScrProjection[2].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 GetLinearZFromSVPosW(float posW) |
|||
{ |
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float linZ = posW; |
|||
#else |
|||
float linZ = -posW; |
|||
#endif |
|||
|
|||
return linZ; |
|||
} |
|||
|
|||
float GetLinearDepth(float zDptBufSpace) // 0 is near 1 is far |
|||
{ |
|||
// todo (simplify): m22 is zero and m23 is +1/-1 (depends on left/right hand proj) |
|||
float m22 = g_mInvScrProjection[2].z, m23 = g_mInvScrProjection[2].w; |
|||
float m32 = g_mInvScrProjection[3].z, m33 = g_mInvScrProjection[3].w; |
|||
|
|||
return (m22*zDptBufSpace+m23) / (m32*zDptBufSpace+m33); |
|||
|
|||
//float3 vP = float3(0.0f,0.0f,zDptBufSpace); |
|||
//float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
//return v4Pres.z / v4Pres.w; |
|||
} |
|||
|
|||
bool SampleDebugFont(int2 pixCoord, uint digit) |
|||
{ |
|||
if (pixCoord.x < 0 || pixCoord.y < 0 || pixCoord.x >= 5 || pixCoord.y >= 9 || digit > 9) |
|||
return false; |
|||
#define PACK_BITS25(_x0,_x1,_x2,_x3,_x4,_x5,_x6,_x7,_x8,_x9,_x10,_x11,_x12,_x13,_x14,_x15,_x16,_x17,_x18,_x19,_x20,_x21,_x22,_x23,_x24) (_x0|(_x1<<1)|(_x2<<2)|(_x3<<3)|(_x4<<4)|(_x5<<5)|(_x6<<6)|(_x7<<7)|(_x8<<8)|(_x9<<9)|(_x10<<10)|(_x11<<11)|(_x12<<12)|(_x13<<13)|(_x14<<14)|(_x15<<15)|(_x16<<16)|(_x17<<17)|(_x18<<18)|(_x19<<19)|(_x20<<20)|(_x21<<21)|(_x22<<22)|(_x23<<23)|(_x24<<24)) |
|||
#define _ 0 |
|||
#define x 1 |
|||
uint fontData[9][2] = { |
|||
{ PACK_BITS25(_,_,x,_,_, _,_,x,_,_, _,x,x,x,_, x,x,x,x,x, _,_,_,x,_), PACK_BITS25(x,x,x,x,x, _,x,x,x,_, x,x,x,x,x, _,x,x,x,_, _,x,x,x,_) }, |
|||
{ PACK_BITS25(_,x,_,x,_, _,x,x,_,_, x,_,_,_,x, _,_,_,_,x, _,_,_,x,_), PACK_BITS25(x,_,_,_,_, x,_,_,_,x, _,_,_,_,x, x,_,_,_,x, x,_,_,_,x) }, |
|||
{ PACK_BITS25(x,_,_,_,x, x,_,x,_,_, x,_,_,_,x, _,_,_,x,_, _,_,x,x,_), PACK_BITS25(x,_,_,_,_, x,_,_,_,_, _,_,_,x,_, x,_,_,_,x, x,_,_,_,x) }, |
|||
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,_,_,_,x, _,_,x,_,_, _,x,_,x,_), PACK_BITS25(x,_,x,x,_, x,_,_,_,_, _,_,_,x,_, x,_,_,_,x, x,_,_,_,x) }, |
|||
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,_,_,x,_, _,x,x,x,_, _,x,_,x,_), PACK_BITS25(x,x,_,_,x, x,x,x,x,_, _,_,x,_,_, _,x,x,x,_, _,x,x,x,x) }, |
|||
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,_,x,_,_, _,_,_,_,x, x,_,_,x,_), PACK_BITS25(_,_,_,_,x, x,_,_,_,x, _,_,x,_,_, x,_,_,_,x, _,_,_,_,x) }, |
|||
{ PACK_BITS25(x,_,_,_,x, _,_,x,_,_, _,x,_,_,_, _,_,_,_,x, x,x,x,x,x), PACK_BITS25(_,_,_,_,x, x,_,_,_,x, _,x,_,_,_, x,_,_,_,x, _,_,_,_,x) }, |
|||
{ PACK_BITS25(_,x,_,x,_, _,_,x,_,_, x,_,_,_,_, x,_,_,_,x, _,_,_,x,_), PACK_BITS25(x,_,_,_,x, x,_,_,_,x, _,x,_,_,_, x,_,_,_,x, x,_,_,_,x) }, |
|||
{ PACK_BITS25(_,_,x,_,_, x,x,x,x,x, x,x,x,x,x, _,x,x,x,_, _,_,_,x,_), PACK_BITS25(_,x,x,x,_, _,x,x,x,_, _,x,_,_,_, _,x,x,x,_, _,x,x,x,_) } |
|||
}; |
|||
#undef _ |
|||
#undef x |
|||
#undef PACK_BITS25 |
|||
return (fontData[8 - pixCoord.y][digit >= 5] >> ((digit % 5) * 5 + pixCoord.x)) & 1; |
|||
} |
|||
|
|||
bool SampleDebugFontNumber(int2 coord, uint number) |
|||
{ |
|||
coord.y -= 4; |
|||
if (number <= 9) |
|||
{ |
|||
return SampleDebugFont(coord - int2(6, 0), number); |
|||
|
|||
} |
|||
else |
|||
{ |
|||
return (SampleDebugFont(coord, number / 10) | SampleDebugFont(coord - int2(6, 0), number % 10)); |
|||
} |
|||
} |
|||
|
|||
|
|||
float3 OverlayHeatMap(uint2 pixCoord, uint numLights, float3 c) |
|||
{ |
|||
///////////////////////////////////////////////////////////////////// |
|||
// |
|||
const float4 kRadarColors[12] = |
|||
{ |
|||
float4(0.0,0.0,0.0,0.0), // black |
|||
float4(0.0,0.0,0.6,0.5), // dark blue |
|||
float4(0.0,0.0,0.9,0.5), // blue |
|||
float4(0.0,0.6,0.9,0.5), // light blue |
|||
float4(0.0,0.9,0.9,0.5), // cyan |
|||
float4(0.0,0.9,0.6,0.5), // blueish green |
|||
float4(0.0,0.9,0.0,0.5), // green |
|||
float4(0.6,0.9,0.0,0.5), // yellowish green |
|||
float4(0.9,0.9,0.0,0.5), // yellow |
|||
float4(0.9,0.6,0.0,0.5), // orange |
|||
float4(0.9,0.0,0.0,0.5), // red |
|||
float4(1.0,0.0,0.0,0.9) // strong red |
|||
}; |
|||
|
|||
float maxNrLightsPerTile = 31; |
|||
|
|||
int nColorIndex = numLights == 0 ? 0 : (1 + (int)floor(10 * (log2((float)numLights) / log2(maxNrLightsPerTile)))); |
|||
nColorIndex = nColorIndex<0 ? 0 : nColorIndex; |
|||
float4 col = nColorIndex>11 ? float4(1.0, 1.0, 1.0, 1.0) : kRadarColors[nColorIndex]; |
|||
|
|||
int2 coord = pixCoord - int2(1, 1); |
|||
|
|||
float3 color = lerp(c, pow(col.xyz, 2.2), 0.3*col.w); |
|||
if(numLights > 0) |
|||
{ |
|||
if (SampleDebugFontNumber(coord, numLights)) // Shadow |
|||
color = 0.0f; |
|||
if (SampleDebugFontNumber(coord + 1, numLights)) // Text |
|||
color = 1.0f; |
|||
} |
|||
return color; |
|||
} |
|||
|
|||
|
|||
|
|||
#endif |
|
|||
#ifndef __LIGHTINGTEMPLATE_H__ |
|||
#define __LIGHTINGTEMPLATE_H__ |
|||
|
|||
|
|||
#include "UnityCG.cginc" |
|||
#include "UnityStandardBRDF.cginc" |
|||
#include "UnityStandardUtils.cginc" |
|||
#include "UnityPBSLighting.cginc" |
|||
|
|||
|
|||
uniform uint g_nNumDirLights; |
|||
|
|||
//--------------------------------------------------------------------------------------------------------------------------------------------------------- |
|||
// TODO: clean up.. -va |
|||
#define MAX_SHADOW_LIGHTS 10 |
|||
#define MAX_SHADOWMAP_PER_LIGHT 6 |
|||
#define MAX_DIRECTIONAL_SPLIT 4 |
|||
|
|||
#define CUBEMAPFACE_POSITIVE_X 0 |
|||
#define CUBEMAPFACE_NEGATIVE_X 1 |
|||
#define CUBEMAPFACE_POSITIVE_Y 2 |
|||
#define CUBEMAPFACE_NEGATIVE_Y 3 |
|||
#define CUBEMAPFACE_POSITIVE_Z 4 |
|||
#define CUBEMAPFACE_NEGATIVE_Z 5 |
|||
|
|||
CBUFFER_START(ShadowLightData) |
|||
|
|||
float4 g_vShadow3x3PCFTerms0; |
|||
float4 g_vShadow3x3PCFTerms1; |
|||
float4 g_vShadow3x3PCFTerms2; |
|||
float4 g_vShadow3x3PCFTerms3; |
|||
|
|||
float4 g_vDirShadowSplitSpheres[MAX_DIRECTIONAL_SPLIT]; |
|||
float4x4 g_matWorldToShadow[MAX_SHADOW_LIGHTS * MAX_SHADOWMAP_PER_LIGHT]; |
|||
|
|||
CBUFFER_END |
|||
//--------------------------------------------------------------------------------------------------------------------------------------------------------- |
|||
|
|||
|
|||
//UNITY_DECLARE_TEX2D(_LightTextureB0); |
|||
sampler2D _LightTextureB0; |
|||
UNITY_DECLARE_TEX2DARRAY(_spotCookieTextures); |
|||
UNITY_DECLARE_ABSTRACT_CUBE_ARRAY(_pointCookieTextures); |
|||
|
|||
StructuredBuffer<DirectionalLight> g_dirLightData; |
|||
|
|||
|
|||
#define DECLARE_SHADOWMAP( tex ) Texture2D tex; SamplerComparisonState sampler##tex |
|||
#ifdef REVERSE_ZBUF |
|||
#define SAMPLE_SHADOW( tex, coord ) tex.SampleCmpLevelZero( sampler##tex, (coord).xy, (coord).z ) |
|||
#else |
|||
#define SAMPLE_SHADOW( tex, coord ) tex.SampleCmpLevelZero( sampler##tex, (coord).xy, 1.0-(coord).z ) |
|||
#endif |
|||
|
|||
DECLARE_SHADOWMAP(g_tShadowBuffer); |
|||
|
|||
float ComputeShadow_PCF_3x3_Gaussian(float3 vPositionWs, float4x4 matWorldToShadow) |
|||
{ |
|||
float4 vPositionTextureSpace = mul(float4(vPositionWs.xyz, 1.0), matWorldToShadow); |
|||
vPositionTextureSpace.xyz /= vPositionTextureSpace.w; |
|||
|
|||
float2 shadowMapCenter = vPositionTextureSpace.xy; |
|||
|
|||
if ((shadowMapCenter.x < 0.0f) || (shadowMapCenter.x > 1.0f) || (shadowMapCenter.y < 0.0f) || (shadowMapCenter.y > 1.0f)) |
|||
return 1.0f; |
|||
|
|||
float objDepth = saturate(257.0 / 256.0 - vPositionTextureSpace.z); |
|||
|
|||
float4 v20Taps; |
|||
v20Taps.x = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.xy, objDepth)).x; // 1 1 |
|||
v20Taps.y = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.zy, objDepth)).x; // -1 1 |
|||
v20Taps.z = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.xw, objDepth)).x; // 1 -1 |
|||
v20Taps.w = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.zw, objDepth)).x; // -1 -1 |
|||
float flSum = dot(v20Taps.xyzw, float4(0.25, 0.25, 0.25, 0.25)); |
|||
if ((flSum == 0.0) || (flSum == 1.0)) |
|||
return flSum; |
|||
flSum *= g_vShadow3x3PCFTerms0.x * 4.0; |
|||
|
|||
float4 v33Taps; |
|||
v33Taps.x = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms2.xz, objDepth)).x; // 1 0 |
|||
v33Taps.y = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms3.xz, objDepth)).x; // -1 0 |
|||
v33Taps.z = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms3.zy, objDepth)).x; // 0 -1 |
|||
v33Taps.w = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms2.zy, objDepth)).x; // 0 1 |
|||
flSum += dot(v33Taps.xyzw, g_vShadow3x3PCFTerms0.yyyy); |
|||
|
|||
flSum += SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy, objDepth)).x * g_vShadow3x3PCFTerms0.z; |
|||
|
|||
return flSum; |
|||
} |
|||
|
|||
//--------------------------------------------------------------------------------------------------------------------------------------------------------- |
|||
/** |
|||
* Gets the cascade weights based on the world position of the fragment and the positions of the split spheres for each cascade. |
|||
* Returns an invalid split index if past shadowDistance (ie 4 is invalid for cascade) |
|||
*/ |
|||
float GetSplitSphereIndexForDirshadows(float3 wpos) |
|||
{ |
|||
float3 fromCenter0 = wpos.xyz - g_vDirShadowSplitSpheres[0].xyz; |
|||
float3 fromCenter1 = wpos.xyz - g_vDirShadowSplitSpheres[1].xyz; |
|||
float3 fromCenter2 = wpos.xyz - g_vDirShadowSplitSpheres[2].xyz; |
|||
float3 fromCenter3 = wpos.xyz - g_vDirShadowSplitSpheres[3].xyz; |
|||
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3)); |
|||
|
|||
float4 vDirShadowSplitSphereSqRadii; |
|||
vDirShadowSplitSphereSqRadii.x = g_vDirShadowSplitSpheres[0].w; |
|||
vDirShadowSplitSphereSqRadii.y = g_vDirShadowSplitSpheres[1].w; |
|||
vDirShadowSplitSphereSqRadii.z = g_vDirShadowSplitSpheres[2].w; |
|||
vDirShadowSplitSphereSqRadii.w = g_vDirShadowSplitSpheres[3].w; |
|||
fixed4 weights = float4(distances2 < vDirShadowSplitSphereSqRadii); |
|||
weights.yzw = saturate(weights.yzw - weights.xyz); |
|||
return 4 - dot(weights, float4(4, 3, 2, 1)); |
|||
} |
|||
|
|||
float SampleShadow(uint type, float3 vPositionWs, float3 vPositionToLightDirWs, uint lightIndex) |
|||
{ |
|||
float flShadowScalar = 1.0; |
|||
int shadowSplitIndex = 0; |
|||
|
|||
if (type == DIRECTIONAL_LIGHT) |
|||
{ |
|||
shadowSplitIndex = GetSplitSphereIndexForDirshadows(vPositionWs); |
|||
} |
|||
|
|||
else if (type == SPHERE_LIGHT) |
|||
{ |
|||
float3 absPos = abs(vPositionToLightDirWs); |
|||
shadowSplitIndex = (vPositionToLightDirWs.z > 0) ? CUBEMAPFACE_NEGATIVE_Z : CUBEMAPFACE_POSITIVE_Z; |
|||
if (absPos.x > absPos.y) |
|||
{ |
|||
if (absPos.x > absPos.z) |
|||
{ |
|||
shadowSplitIndex = (vPositionToLightDirWs.x > 0) ? CUBEMAPFACE_NEGATIVE_X : CUBEMAPFACE_POSITIVE_X; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (absPos.y > absPos.z) |
|||
{ |
|||
shadowSplitIndex = (vPositionToLightDirWs.y > 0) ? CUBEMAPFACE_NEGATIVE_Y : CUBEMAPFACE_POSITIVE_Y; |
|||
} |
|||
} |
|||
} |
|||
|
|||
flShadowScalar = ComputeShadow_PCF_3x3_Gaussian(vPositionWs.xyz, g_matWorldToShadow[lightIndex * MAX_SHADOWMAP_PER_LIGHT + shadowSplitIndex]); |
|||
return flShadowScalar; |
|||
} |
|||
|
|||
|
|||
float3 ExecuteLightList(uint start, uint numLights, float3 vP, float3 vPw, float3 Vworld) |
|||
{ |
|||
UnityIndirect ind; |
|||
UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind); |
|||
ind.diffuse = 0; |
|||
ind.specular = 0; |
|||
|
|||
|
|||
float3 ints = 0; |
|||
|
|||
for (int i = 0; i < g_nNumDirLights; i++) |
|||
{ |
|||
DirectionalLight lightData = g_dirLightData[i]; |
|||
float atten = 1; |
|||
|
|||
[branch] |
|||
if (lightData.shadowLightIndex != 0xffffffff) |
|||
{ |
|||
float shadowScalar = SampleShadow(DIRECTIONAL_LIGHT, vPw, 0, lightData.shadowLightIndex); |
|||
atten *= shadowScalar; |
|||
} |
|||
|
|||
UnityLight light; |
|||
light.color.xyz = lightData.color.xyz * atten; |
|||
light.dir.xyz = mul((float3x3) g_mViewToWorld, -lightData.lightAxisZ).xyz; |
|||
|
|||
ints += EvalMaterial(light, ind); |
|||
} |
|||
|
|||
uint l=0; |
|||
// don't need the outer loop since the lights are sorted by volume type |
|||
//while(l<numLights) |
|||
if(numLights>0) |
|||
{ |
|||
uint uIndex = l<numLights ? FetchIndex(start, l) : 0; |
|||
uint uLgtType = l<numLights ? g_vLightData[uIndex].lightType : 0; |
|||
|
|||
// specialized loop for spot lights |
|||
while(l<numLights && uLgtType==SPOT_LIGHT) |
|||
{ |
|||
SFiniteLightData lgtDat = g_vLightData[uIndex]; |
|||
float3 vLp = lgtDat.lightPos.xyz; |
|||
|
|||
float3 toLight = vLp - vP; |
|||
float dist = length(toLight); |
|||
float3 vL = toLight / dist; |
|||
|
|||
float attLookUp = dist*lgtDat.recipRange; attLookUp *= attLookUp; |
|||
float atten = tex2Dlod(_LightTextureB0, float4(attLookUp.rr, 0.0, 0.0)).UNITY_ATTEN_CHANNEL; |
|||
|
|||
// spot attenuation |
|||
const float fProjVec = -dot(vL, lgtDat.lightAxisZ.xyz); // spotDir = lgtDat.lightAxisZ.xyz |
|||
float2 cookCoord = (-lgtDat.cotan)*float2( dot(vL, lgtDat.lightAxisX.xyz), dot(vL, lgtDat.lightAxisY.xyz) ) / fProjVec; |
|||
|
|||
const bool bHasCookie = (lgtDat.flags&IS_CIRCULAR_SPOT_SHAPE)==0; // all square spots have cookies |
|||
float d0 = 0.65; |
|||
float4 angularAtt = float4(1,1,1,smoothstep(0.0, 1.0-d0, 1.0-length(cookCoord))); |
|||
[branch]if(bHasCookie) |
|||
{ |
|||
cookCoord = cookCoord*0.5 + 0.5; |
|||
angularAtt = UNITY_SAMPLE_TEX2DARRAY_LOD(_spotCookieTextures, float3(cookCoord, lgtDat.sliceIndex), 0.0); |
|||
} |
|||
atten *= angularAtt.w*(fProjVec>0.0); // finally apply this to the dist att. |
|||
|
|||
const bool bHasShadow = (lgtDat.flags&HAS_SHADOW)!=0; |
|||
[branch]if(bHasShadow) |
|||
{ |
|||
float shadowScalar = SampleShadow(SPOT_LIGHT, vPw, 0, lgtDat.shadowLightIndex); |
|||
atten *= shadowScalar; |
|||
} |
|||
|
|||
UnityLight light; |
|||
light.color.xyz = lgtDat.color.xyz*atten*angularAtt.xyz; |
|||
light.dir.xyz = mul((float3x3) g_mViewToWorld, vL).xyz; //unity_CameraToWorld |
|||
|
|||
ints += EvalMaterial(light, ind); |
|||
|
|||
++l; uIndex = l<numLights ? FetchIndex(start, l) : 0; |
|||
uLgtType = l<numLights ? g_vLightData[uIndex].lightType : 0; |
|||
} |
|||
|
|||
// specialized loop for sphere lights |
|||
while(l<numLights && uLgtType==SPHERE_LIGHT) |
|||
{ |
|||
SFiniteLightData lgtDat = g_vLightData[uIndex]; |
|||
float3 vLp = lgtDat.lightPos.xyz; |
|||
|
|||
float3 toLight = vLp - vP; |
|||
float dist = length(toLight); |
|||
float3 vL = toLight / dist; |
|||
float3 vLw = mul((float3x3) g_mViewToWorld, vL).xyz; //unity_CameraToWorld |
|||
|
|||
float attLookUp = dist*lgtDat.recipRange; attLookUp *= attLookUp; |
|||
float atten = tex2Dlod(_LightTextureB0, float4(attLookUp.rr, 0.0, 0.0)).UNITY_ATTEN_CHANNEL; |
|||
|
|||
float4 cookieColor = float4(1,1,1,1); |
|||
|
|||
const bool bHasCookie = (lgtDat.flags&HAS_COOKIE_TEXTURE)!=0; |
|||
[branch]if(bHasCookie) |
|||
{ |
|||
float3 cookieCoord = -float3(dot(vL, lgtDat.lightAxisX.xyz), dot(vL, lgtDat.lightAxisY.xyz), dot(vL, lgtDat.lightAxisZ.xyz)); // negate to make vL a fromLight vector |
|||
cookieColor = UNITY_SAMPLE_ABSTRACT_CUBE_ARRAY_LOD(_pointCookieTextures, float4(cookieCoord, lgtDat.sliceIndex), 0.0); |
|||
atten *= cookieColor.w; |
|||
} |
|||
|
|||
const bool bHasShadow = (lgtDat.flags&HAS_SHADOW)!=0; |
|||
[branch]if(bHasShadow) |
|||
{ |
|||
float shadowScalar = SampleShadow(SPHERE_LIGHT, vPw, vLw, lgtDat.shadowLightIndex); |
|||
atten *= shadowScalar; |
|||
} |
|||
|
|||
UnityLight light; |
|||
light.color.xyz = lgtDat.color.xyz*atten*cookieColor.xyz; |
|||
light.dir.xyz = vLw; |
|||
|
|||
ints += EvalMaterial(light, ind); |
|||
|
|||
++l; uIndex = l<numLights ? FetchIndex(start, l) : 0; |
|||
uLgtType = l<numLights ? g_vLightData[uIndex].lightType : 0; |
|||
} |
|||
|
|||
//if(uLgtType!=SPOT_LIGHT && uLgtType!=SPHERE_LIGHT) ++l; |
|||
} |
|||
|
|||
return ints; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
#endif |
|
|||
#pragma kernel ShadeDeferred_Fptl SHADE_DEFERRED_ENTRY=ShadeDeferred_Fptl USE_FPTL_LIGHTLIST=1 ENABLE_DEBUG=0 |
|||
#pragma kernel ShadeDeferred_Clustered SHADE_DEFERRED_ENTRY=ShadeDeferred_Clustered USE_CLUSTERED_LIGHTLIST=1 ENABLE_DEBUG=0 //TODO: disabled clustered permutations so far as it leads to the error "All kernels must use same constant buffer layouts" |
|||
#pragma kernel ShadeDeferred_Fptl_Debug SHADE_DEFERRED_ENTRY=ShadeDeferred_Fptl_Debug USE_FPTL_LIGHTLIST=1 ENABLE_DEBUG=1 |
|||
#pragma kernel ShadeDeferred_Clustered_Debug SHADE_DEFERRED_ENTRY=ShadeDeferred_Clustered_Debug USE_CLUSTERED_LIGHTLIST=1 ENABLE_DEBUG=1 |
|||
|
|||
#define TILE_SIZE 8 |
|||
|
|||
|
|||
// Hacks to get the header to compile in compute |
|||
#define SHADER_TARGET 50 |
|||
#define UNITY_PBS_USE_BRDF1 |
|||
#define fixed4 float4 |
|||
#include "UnityLightingCommon.cginc" |
|||
#undef fixed4 |
|||
|
|||
float3 EvalMaterial(UnityLight light, UnityIndirect ind); |
|||
float3 EvalIndirectSpecular(UnityLight light, UnityIndirect ind); |
|||
|
|||
// uses the optimized single layered light list for opaques only |
|||
|
|||
#ifdef USE_FPTL_LIGHTLIST |
|||
#define OPAQUES_ONLY |
|||
#endif |
|||
|
|||
#include "TiledLightingTemplate.hlsl" |
|||
#include "TiledReflectionTemplate.hlsl" |
|||
|
|||
UNITY_DECLARE_TEX2D_FLOAT(_CameraDepthTexture); |
|||
Texture2D _CameraGBufferTexture0; |
|||
Texture2D _CameraGBufferTexture1; |
|||
Texture2D _CameraGBufferTexture2; |
|||
Texture2D _CameraGBufferTexture3; |
|||
|
|||
RWTexture2D<float4> uavOutput : register(u0); |
|||
|
|||
struct v2f { |
|||
float4 vertex : SV_POSITION; |
|||
float2 texcoord : TEXCOORD0; |
|||
}; |
|||
|
|||
v2f vert(float4 vertex : POSITION, float2 texcoord : TEXCOORD0) |
|||
{ |
|||
v2f o; |
|||
o.vertex = UnityObjectToClipPos(vertex); |
|||
o.texcoord = texcoord.xy; |
|||
return o; |
|||
} |
|||
|
|||
struct StandardData |
|||
{ |
|||
float3 specularColor; |
|||
float3 diffuseColor; |
|||
float3 normalWorld; |
|||
float smoothness; |
|||
float occlusion; |
|||
float3 emission; |
|||
}; |
|||
|
|||
struct LocalDataBRDF |
|||
{ |
|||
StandardData gbuf; |
|||
|
|||
// extras |
|||
float oneMinusReflectivity; |
|||
float3 Vworld; |
|||
}; |
|||
|
|||
static LocalDataBRDF g_localParams; |
|||
|
|||
StandardData UnityStandardDataFromGbufferAux(float4 gbuffer0, float4 gbuffer1, float4 gbuffer2, float4 gbuffer3) |
|||
{ |
|||
StandardData data; |
|||
|
|||
data.normalWorld = normalize(2 * gbuffer2.xyz - 1); |
|||
data.smoothness = gbuffer1.a; |
|||
data.diffuseColor = gbuffer0.xyz; data.specularColor = gbuffer1.xyz; |
|||
data.occlusion = gbuffer0.a; |
|||
data.emission = gbuffer3.xyz; |
|||
|
|||
return data; |
|||
} |
|||
|
|||
half3 BRDF3_Direct2(half3 diffColor, half3 specColor, half rlPow4, half smoothness) |
|||
{ |
|||
half LUT_RANGE = 16.0; // must match range in NHxRoughness() function in GeneratedTextures.cpp |
|||
// Lookup texture to save instructions |
|||
half specular = tex2Dlod(unity_NHxRoughness, half4(rlPow4, SmoothnessToPerceptualRoughness(smoothness), 0, 0)).UNITY_ATTEN_CHANNEL * LUT_RANGE; |
|||
#if defined(_SPECULARHIGHLIGHTS_OFF) |
|||
specular = 0.0; |
|||
#endif |
|||
|
|||
return diffColor + specular * specColor; |
|||
} |
|||
|
|||
|
|||
float3 EvalMaterial(UnityLight light, UnityIndirect ind) |
|||
{ |
|||
StandardData data = g_localParams.gbuf; |
|||
return UNITY_BRDF_PBS(data.diffuseColor, data.specularColor, g_localParams.oneMinusReflectivity, data.smoothness, data.normalWorld, g_localParams.Vworld, light, ind); |
|||
} |
|||
|
|||
float3 EvalIndirectSpecular(UnityLight light, UnityIndirect ind) |
|||
{ |
|||
StandardData data = g_localParams.gbuf; |
|||
|
|||
return data.occlusion * UNITY_BRDF_PBS(0, data.specularColor, g_localParams.oneMinusReflectivity, data.smoothness, data.normalWorld, g_localParams.Vworld, light, ind).rgb; |
|||
} |
|||
|
|||
[numthreads(TILE_SIZE, TILE_SIZE, 1)] |
|||
void SHADE_DEFERRED_ENTRY(uint2 dispatchThreadId : SV_DispatchThreadID, uint2 groupId : SV_GroupID) |
|||
{ |
|||
uint2 pixCoord = dispatchThreadId; |
|||
|
|||
float zbufDpth = FetchDepth(_CameraDepthTexture, pixCoord.xy).x; |
|||
float linDepth = GetLinearDepth(zbufDpth); |
|||
|
|||
float3 vP = GetViewPosFromLinDepth(pixCoord, linDepth); |
|||
float3 vPw = mul(g_mViewToWorld, float4(vP, 1)).xyz; |
|||
float3 Vworld = normalize(mul((float3x3) g_mViewToWorld, -vP).xyz); //unity_CameraToWorld |
|||
|
|||
float4 gbuffer0 = _CameraGBufferTexture0.Load(uint3(pixCoord.xy, 0)); |
|||
float4 gbuffer1 = _CameraGBufferTexture1.Load(uint3(pixCoord.xy, 0)); |
|||
float4 gbuffer2 = _CameraGBufferTexture2.Load(uint3(pixCoord.xy, 0)); |
|||
float4 gbuffer3 = _CameraGBufferTexture3.Load(uint3(pixCoord.xy, 0)); |
|||
|
|||
StandardData data = UnityStandardDataFromGbufferAux(gbuffer0, gbuffer1, gbuffer2, gbuffer3); |
|||
|
|||
g_localParams.gbuf = data; |
|||
g_localParams.oneMinusReflectivity = 1.0 - SpecularStrength(data.specularColor.rgb); |
|||
g_localParams.Vworld = Vworld; |
|||
|
|||
uint2 tileCoord = groupId >> 1; |
|||
|
|||
uint numLightsProcessed = 0; |
|||
float3 c = data.emission + ExecuteLightList(numLightsProcessed, tileCoord, vP, vPw, Vworld); |
|||
|
|||
uint numReflectionsProcessed = 0; |
|||
c += ExecuteReflectionList(numReflectionsProcessed, tileCoord, vP, data.normalWorld, Vworld, data.smoothness); |
|||
|
|||
#if ENABLE_DEBUG |
|||
c = OverlayHeatMap(pixCoord & 15, numLightsProcessed, c); |
|||
#endif |
|||
|
|||
uavOutput[pixCoord] = float4(c, 1.0); |
|||
} |
|||
|
|
|||
#ifndef __LIGHTINGCONVEXHULLUTILS_H__ |
|||
#define __LIGHTINGCONVEXHULLUTILS_H__ |
|||
|
|||
|
|||
#include "..\common\ShaderBase.h" |
|||
#include "LightDefinitions.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; // if len<=0.0001 then either |sphCen|<sphRadius or sphCen is very closely aligned with Z axis in which case little to no additional offs needed. |
|||
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: 6aaf534559faf7e499945c3d9eb97d9f |
|||
timeCreated: 1486895883 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
mainObjectFileID: 11400000 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!114 &11400000 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_PrefabParentObject: {fileID: 0} |
|||
m_PrefabInternal: {fileID: 0} |
|||
m_GameObject: {fileID: 0} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: ad5bf4f8e45bdd1429eadc3445df2c89, type: 3} |
|||
m_Name: FPTLRenderPipeline |
|||
m_EditorClassIdentifier: |
|||
m_ShadowSettings: |
|||
enabled: 1 |
|||
shadowAtlasWidth: 4096 |
|||
shadowAtlasHeight: 4096 |
|||
maxShadowDistance: 1000 |
|||
directionalLightCascadeCount: 4 |
|||
directionalLightCascades: {x: 0.05, y: 0.2, z: 0.3} |
|||
directionalLightNearPlaneOffset: 5 |
|||
m_TextureSettings: |
|||
spotCookieSize: 512 |
|||
pointCookieSize: 128 |
|||
reflectionCubemapSize: 128 |
|||
deferredShader: {fileID: 4800000, guid: 1c102a89f3460254a8c413dbdcd63a2a, type: 3} |
|||
deferredReflectionShader: {fileID: 4800000, guid: 3899e06d641c2cb4cbff794df0da536b, |
|||
type: 3} |
|||
deferredComputeShader: {fileID: 7200000, guid: 6994e4f8a80d87b428cca7242cb32a0e, |
|||
type: 3} |
|||
finalPassShader: {fileID: 4800000, guid: 5590f54ad211f594da4e687b698f2258, type: 3} |
|||
debugLightBoundsShader: {fileID: 4800000, guid: 33f2a444e9120d34396d41e40795d712, |
|||
type: 3} |
|||
buildScreenAABBShader: {fileID: 7200000, guid: e7a739144e735934b89a42a4b9d9e23c, |
|||
type: 3} |
|||
buildPerTileLightListShader: {fileID: 7200000, guid: f54ef7cb596a714488693ef9cdaf63fb, |
|||
type: 3} |
|||
buildPerBigTileLightListShader: {fileID: 7200000, guid: b5507a2ffdae8a84f94211c10d428920, |
|||
type: 3} |
|||
buildPerVoxelLightListShader: {fileID: 7200000, guid: 4c2d6eb0553e2514bba3ea9a85d8c53c, |
|||
type: 3} |
|||
enableClustered: 0 |
|||
disableFptlWhenClustered: 0 |
|||
enableBigTilePrepass: 1 |
|||
enableDrawLightBoundsDebug: 0 |
|||
enableDrawTileDebug: 0 |
|||
enableReflectionProbeDebug: 0 |
|||
enableComputeLightEvaluation: 0 |
|
|||
// 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 |
|||
|
|||
|
|||
#include "..\common\ShaderBase.h" |
|||
#include "LightDefinitions.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 |
|||
StructuredBuffer<uint> g_vBigTileLightList : register( t4 ); // don't support Buffer yet in unity |
|||
#endif |
|||
|
|||
#define NR_THREADS 64 |
|||
|
|||
// output buffer |
|||
RWStructuredBuffer<uint> g_vLightList : register( u0 ); // don't support RWBuffer yet in unity |
|||
|
|||
|
|||
#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) |
|||
{ |
|||
if(threadID==0) 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[prunedList[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 |
|
|||
#pragma kernel BigTileLightListGen |
|||
|
|||
#include "..\common\ShaderBase.h" |
|||
#include "LightDefinitions.cs.hlsl" |
|||
|
|||
#include "LightingConvexHullUtils.hlsl" |
|||
#include "SortingComputeUtils.hlsl" |
|||
|
|||
#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 |
|||
RWStructuredBuffer<uint> g_vLightList : register( u0 ); // don't support RWBuffer yet in unity |
|||
|
|||
|
|||
// 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); |
|||
|
|||
if(t==0) 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] = i==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 uint idxCoarse = lightsListLDS[l]; |
|||
|
|||
bool canEnter = idxCoarse<(uint) g_iNrVisibLights; |
|||
if(canEnter) canEnter = g_vLightData[idxCoarse].lightType!=SPHERE_LIGHT; // don't bother doing edge tests for sphere lights since these have camera aligned bboxes. |
|||
[branch]if(canEnter) |
|||
{ |
|||
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 |
|
|||
// Final compositing pass, just does gamma conversion for now. |
|||
|
|||
Shader "Hidden/LightBoundsDebug" |
|||
{ |
|||
Properties { } |
|||
SubShader { |
|||
Pass { |
|||
ZTest Always |
|||
Cull Off |
|||
ZWrite Off |
|||
Blend SrcAlpha One |
|||
|
|||
CGPROGRAM |
|||
#pragma vertex vert |
|||
#pragma fragment frag |
|||
#pragma target 4.5 |
|||
|
|||
#include "UnityCG.cginc" |
|||
#include "LightDefinitions.cs.hlsl" |
|||
|
|||
StructuredBuffer<SFiniteLightBound> g_data : register(t0); |
|||
|
|||
float4 vert(uint globalIndex : SV_VertexID) : SV_POSITION |
|||
{ |
|||
uint lightIndex = globalIndex / 36; |
|||
uint localIndex = globalIndex - lightIndex * 36; |
|||
uint faceIndex = localIndex / 6; |
|||
uint vertexIndex = localIndex - faceIndex * 6; |
|||
int remapTrisToQuad[6] = { 0,1,2,2,3,0 }; // Remap tri indices to quad indices: 012345->012230 |
|||
vertexIndex = remapTrisToQuad[vertexIndex]; |
|||
|
|||
uint faces[6][4] = { |
|||
{0, 2, 6, 4}, //-x |
|||
{1, 5, 7, 3}, //+x |
|||
{0, 4, 5, 1}, //-y |
|||
{2, 3, 7, 6}, //+y |
|||
{0, 1, 3, 2}, //-z |
|||
{4, 6, 7, 5}, //+z |
|||
}; |
|||
|
|||
SFiniteLightBound lightData = g_data[lightIndex]; |
|||
uint coordIndex = faces[faceIndex][vertexIndex]; |
|||
float3 coord = float3((coordIndex & 1) ? 1.0f : -1.0f, (coordIndex & 2) ? 1.0f : -1.0f, (coordIndex & 4) ? 1.0f : -1.0f); |
|||
coord.xy *= (coordIndex >= 4) ? lightData.scaleXY : float2(1, 1); |
|||
|
|||
float3 viewPos = lightData.center + coord.x * lightData.boxAxisX.xyz + coord.y * lightData.boxAxisY.xyz + coord.z * -lightData.boxAxisZ.xyz; |
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
// not completely sure why this is necessary since the old stuff pretends camera coordinate system is also left-hand. |
|||
// see: Camera::CalculateMatrixShaderProps() |
|||
viewPos.z = -viewPos.z; |
|||
#endif |
|||
return UnityViewToClipPos(viewPos); |
|||
} |
|||
|
|||
fixed4 frag() : SV_Target |
|||
{ |
|||
return float4(1.0f, 0.5f, 0.3f, 0.1f); |
|||
} |
|||
ENDCG |
|||
} |
|||
} |
|||
Fallback Off |
|||
} |
|
|||
Shader "Hidden/Internal-Obscurity" { |
|||
Properties { |
|||
_LightTexture0 ("", any) = "" {} |
|||
_ShadowMapTexture ("", any) = "" {} |
|||
_SrcBlend ("", Float) = 1 |
|||
_DstBlend ("", Float) = 1 |
|||
} |
|||
SubShader { |
|||
|
|||
|
|||
|
|||
|
|||
Pass |
|||
{ |
|||
ZWrite Off |
|||
ZTest Always |
|||
Cull Off |
|||
Blend Off |
|||
//Blend [_SrcBlend] [_DstBlend] |
|||
|
|||
|
|||
CGPROGRAM |
|||
#pragma target 4.5 |
|||
#pragma vertex vert |
|||
#pragma fragment frag |
|||
|
|||
#pragma multi_compile USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST |
|||
#pragma multi_compile __ ENABLE_DEBUG |
|||
|
|||
#include "UnityLightingCommon.cginc" |
|||
|
|||
float3 EvalMaterial(UnityLight light, UnityIndirect ind); |
|||
|
|||
// uses the optimized single layered light list for opaques only |
|||
|
|||
#ifdef USE_FPTL_LIGHTLIST |
|||
#define OPAQUES_ONLY |
|||
#endif |
|||
|
|||
#include "TiledLightingTemplate.hlsl" |
|||
|
|||
|
|||
UNITY_DECLARE_TEX2D_FLOAT(_CameraDepthTexture); |
|||
Texture2D _CameraGBufferTexture0; |
|||
Texture2D _CameraGBufferTexture1; |
|||
Texture2D _CameraGBufferTexture2; |
|||
Texture2D _CameraGBufferTexture3; |
|||
|
|||
|
|||
struct v2f { |
|||
float4 vertex : SV_POSITION; |
|||
float2 texcoord : TEXCOORD0; |
|||
}; |
|||
|
|||
v2f vert (float4 vertex : POSITION, float2 texcoord : TEXCOORD0) |
|||
{ |
|||
v2f o; |
|||
o.vertex = UnityObjectToClipPos(vertex); |
|||
o.texcoord = texcoord.xy; |
|||
return o; |
|||
} |
|||
|
|||
struct StandardData |
|||
{ |
|||
float3 specularColor; |
|||
float3 diffuseColor; |
|||
float3 normalWorld; |
|||
float smoothness; |
|||
float3 emission; |
|||
}; |
|||
|
|||
struct LocalDataBRDF |
|||
{ |
|||
StandardData gbuf; |
|||
|
|||
// extras |
|||
float oneMinusReflectivity; |
|||
float3 Vworld; |
|||
}; |
|||
|
|||
static LocalDataBRDF g_localParams; |
|||
|
|||
StandardData UnityStandardDataFromGbufferAux(float4 gbuffer0, float4 gbuffer1, float4 gbuffer2, float4 gbuffer3) |
|||
{ |
|||
StandardData data; |
|||
|
|||
data.normalWorld = normalize(2*gbuffer2.xyz-1); |
|||
data.smoothness = gbuffer1.a; |
|||
data.diffuseColor = gbuffer0.xyz; data.specularColor = gbuffer1.xyz; |
|||
float ao = gbuffer0.a; |
|||
data.emission = gbuffer3.xyz; |
|||
|
|||
return data; |
|||
} |
|||
|
|||
|
|||
float3 EvalMaterial(UnityLight light, UnityIndirect ind) |
|||
{ |
|||
StandardData data = g_localParams.gbuf; |
|||
return UNITY_BRDF_PBS(data.diffuseColor, data.specularColor, g_localParams.oneMinusReflectivity, data.smoothness, data.normalWorld, g_localParams.Vworld, light, ind); |
|||
} |
|||
|
|||
|
|||
half4 frag (v2f i) : SV_Target |
|||
{ |
|||
uint2 pixCoord = ((uint2) i.vertex.xy); |
|||
|
|||
float zbufDpth = FetchDepth(_CameraDepthTexture, pixCoord.xy).x; |
|||
float linDepth = GetLinearDepth(zbufDpth); |
|||
|
|||
float3 vP = GetViewPosFromLinDepth(i.vertex.xy, linDepth); |
|||
float3 vPw = mul(g_mViewToWorld, float4(vP, 1)).xyz; |
|||
float3 Vworld = normalize(mul((float3x3) g_mViewToWorld, -vP).xyz); //unity_CameraToWorld |
|||
|
|||
float4 gbuffer0 = _CameraGBufferTexture0.Load( uint3(pixCoord.xy, 0) ); |
|||
float4 gbuffer1 = _CameraGBufferTexture1.Load( uint3(pixCoord.xy, 0) ); |
|||
float4 gbuffer2 = _CameraGBufferTexture2.Load( uint3(pixCoord.xy, 0) ); |
|||
float4 gbuffer3 = _CameraGBufferTexture3.Load( uint3(pixCoord.xy, 0) ); |
|||
|
|||
StandardData data = UnityStandardDataFromGbufferAux(gbuffer0, gbuffer1, gbuffer2, gbuffer3); |
|||
|
|||
g_localParams.gbuf = data; |
|||
g_localParams.oneMinusReflectivity = 1.0 - SpecularStrength(data.specularColor.rgb); |
|||
g_localParams.Vworld = Vworld; |
|||
|
|||
uint numLightsProcessed = 0; |
|||
float3 c = data.emission + ExecuteLightList(numLightsProcessed, pixCoord, vP, vPw, Vworld); |
|||
|
|||
#if ENABLE_DEBUG |
|||
c = OverlayHeatMap(pixCoord & 15, numLightsProcessed, c); |
|||
#endif |
|||
return float4(c,1.0); |
|||
} |
|||
|
|||
ENDCG |
|||
} |
|||
|
|||
} |
|||
Fallback Off |
|||
} |
|
|||
Shader "Hidden/Internal-TiledReflections" { |
|||
Properties { |
|||
_LightTexture0 ("", any) = "" {} |
|||
_ShadowMapTexture ("", any) = "" {} |
|||
_SrcBlend ("", Float) = 1 |
|||
_DstBlend ("", Float) = 1 |
|||
} |
|||
SubShader { |
|||
|
|||
|
|||
|
|||
|
|||
Pass |
|||
{ |
|||
ZWrite Off |
|||
ZTest Always |
|||
Cull Off |
|||
//Blend Off |
|||
Blend [_SrcBlend] [_DstBlend] |
|||
|
|||
|
|||
CGPROGRAM |
|||
#pragma target 4.5 |
|||
#pragma vertex vert |
|||
#pragma fragment frag |
|||
|
|||
#pragma multi_compile USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST |
|||
#pragma multi_compile __ ENABLE_DEBUG |
|||
|
|||
#include "UnityLightingCommon.cginc" |
|||
|
|||
float3 EvalIndirectSpecular(UnityLight light, UnityIndirect ind); |
|||
|
|||
|
|||
// uses the optimized single layered light list for opaques only |
|||
|
|||
#ifdef USE_FPTL_LIGHTLIST |
|||
#define OPAQUES_ONLY |
|||
#endif |
|||
|
|||
#include "TiledReflectionTemplate.hlsl" |
|||
|
|||
|
|||
UNITY_DECLARE_TEX2D_FLOAT(_CameraDepthTexture); |
|||
Texture2D _CameraGBufferTexture0; |
|||
Texture2D _CameraGBufferTexture1; |
|||
Texture2D _CameraGBufferTexture2; |
|||
|
|||
|
|||
float3 ExecuteReflectionProbes(uint2 pixCoord, uint start, uint numLights, float linDepth); |
|||
|
|||
|
|||
struct v2f { |
|||
float4 vertex : SV_POSITION; |
|||
float2 texcoord : TEXCOORD0; |
|||
}; |
|||
|
|||
v2f vert (float4 vertex : POSITION, float2 texcoord : TEXCOORD0) |
|||
{ |
|||
v2f o; |
|||
o.vertex = UnityObjectToClipPos(vertex); |
|||
o.texcoord = texcoord.xy; |
|||
return o; |
|||
} |
|||
|
|||
|
|||
struct StandardData |
|||
{ |
|||
float3 specularColor; |
|||
float3 diffuseColor; |
|||
float3 normalWorld; |
|||
float smoothness; |
|||
float occlusion; |
|||
}; |
|||
|
|||
struct LocalDataBRDF |
|||
{ |
|||
StandardData gbuf; |
|||
|
|||
// extras |
|||
float oneMinusReflectivity; |
|||
float3 Vworld; |
|||
}; |
|||
|
|||
static LocalDataBRDF g_localParams; |
|||
|
|||
StandardData UnityStandardDataFromGbufferAux(float4 gbuffer0, float4 gbuffer1, float4 gbuffer2) |
|||
{ |
|||
StandardData data; |
|||
|
|||
data.normalWorld = normalize(2*gbuffer2.xyz-1); |
|||
data.smoothness = gbuffer1.a; |
|||
data.diffuseColor = gbuffer0.xyz; data.specularColor = gbuffer1.xyz; |
|||
data.occlusion = gbuffer0.a; |
|||
|
|||
return data; |
|||
} |
|||
|
|||
|
|||
float3 EvalIndirectSpecular(UnityLight light, UnityIndirect ind) |
|||
{ |
|||
StandardData data = g_localParams.gbuf; |
|||
|
|||
return data.occlusion * UNITY_BRDF_PBS(0, data.specularColor, g_localParams.oneMinusReflectivity, data.smoothness, data.normalWorld, g_localParams.Vworld, light, ind).rgb; |
|||
} |
|||
|
|||
|
|||
half4 frag (v2f i) : SV_Target |
|||
{ |
|||
uint2 pixCoord = ((uint2) i.vertex.xy); |
|||
|
|||
float zbufDpth = FetchDepth(_CameraDepthTexture, pixCoord.xy).x; |
|||
float linDepth = GetLinearDepth(zbufDpth); |
|||
|
|||
float3 vP = GetViewPosFromLinDepth(i.vertex.xy, linDepth); |
|||
float3 vPw = mul(g_mViewToWorld, float4(vP, 1)).xyz; |
|||
float3 Vworld = normalize(mul((float3x3) g_mViewToWorld, -vP).xyz); //unity_CameraToWorld |
|||
|
|||
float4 gbuffer0 = _CameraGBufferTexture0.Load( uint3(pixCoord.xy, 0) ); |
|||
float4 gbuffer1 = _CameraGBufferTexture1.Load( uint3(pixCoord.xy, 0) ); |
|||
float4 gbuffer2 = _CameraGBufferTexture2.Load( uint3(pixCoord.xy, 0) ); |
|||
|
|||
StandardData data = UnityStandardDataFromGbufferAux(gbuffer0, gbuffer1, gbuffer2); |
|||
|
|||
g_localParams.gbuf = data; |
|||
g_localParams.oneMinusReflectivity = 1.0 - SpecularStrength(data.specularColor.rgb); |
|||
g_localParams.Vworld = Vworld; |
|||
|
|||
uint numReflectionsProcessed = 0; |
|||
float3 c = ExecuteReflectionList(numReflectionsProcessed, pixCoord, vP, data.normalWorld, Vworld, data.smoothness); |
|||
|
|||
#if ENABLE_DEBUG |
|||
c = OverlayHeatMap(pixCoord & 15, numReflectionsProcessed, c); |
|||
#endif |
|||
|
|||
return float4(c,1.0); |
|||
} |
|||
|
|||
|
|||
|
|||
ENDCG |
|||
} |
|||
|
|||
} |
|||
Fallback Off |
|||
} |
|
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.Rendering; |
|||
|
|||
[GenerateHLSL] |
|||
public struct SFiniteLightData |
|||
{ |
|||
// setup constant buffer
|
|||
public float penumbra; |
|||
public int flags; |
|||
public uint lightType; |
|||
public uint lightModel; // DIRECT_LIGHT=0, REFLECTION_LIGHT=1
|
|||
|
|||
public Vector3 lightPos; |
|||
public float lightIntensity; |
|||
|
|||
public Vector3 lightAxisX; |
|||
public float recipRange; |
|||
|
|||
public Vector3 lightAxisY; |
|||
public float radiusSq; |
|||
|
|||
public Vector3 lightAxisZ; // spot +Z axis
|
|||
public float cotan; |
|||
|
|||
public Vector3 color; |
|||
public int sliceIndex; |
|||
|
|||
public Vector3 boxInnerDist; |
|||
public float decodeExp; |
|||
|
|||
public Vector3 boxInvRange; |
|||
public uint shadowLightIndex; |
|||
|
|||
public Vector3 localCubeCapturePoint; |
|||
public float probeBlendDistance; |
|||
}; |
|||
|
|||
[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 DirectionalLight |
|||
{ |
|||
public Vector3 color; |
|||
public float intensity; |
|||
|
|||
public Vector3 lightAxisX; |
|||
public uint shadowLightIndex; |
|||
|
|||
public Vector3 lightAxisY; |
|||
public float pad0; |
|||
|
|||
public Vector3 lightAxisZ; |
|||
public float pad1; |
|||
}; |
|||
|
|||
[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; |
|||
|
|||
// must be either 16, 32 or 64. Could go higher in principle but big tiles in the pre-pass are already 64x64
|
|||
public static int TILE_SIZE_CLUSTERED = 32; |
|||
|
|||
// 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; |
|||
} |
|
|||
// |
|||
// This file was automatically generated from Assets/ScriptableRenderPipeline/fptl/LightDefinitions.cs. Please don't edit by hand. |
|||
// |
|||
|
|||
#ifndef LIGHTDEFINITIONS_CS_HLSL |
|||
#define LIGHTDEFINITIONS_CS_HLSL |
|||
// |
|||
// LightDefinitions: static fields |
|||
// |
|||
#define MAX_NR_LIGHTS_PER_CAMERA (1024) |
|||
#define MAX_NR_BIGTILE_LIGHTS_PLUSONE (512) |
|||
#define VIEWPORT_SCALE_Z (1) |
|||
#define TILE_SIZE_CLUSTERED (32) |
|||
#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 SFiniteLightData |
|||
// PackingRules = Exact |
|||
struct SFiniteLightData |
|||
{ |
|||
float penumbra; |
|||
int flags; |
|||
uint lightType; |
|||
uint lightModel; |
|||
float3 lightPos; |
|||
float lightIntensity; |
|||
float3 lightAxisX; |
|||
float recipRange; |
|||
float3 lightAxisY; |
|||
float radiusSq; |
|||
float3 lightAxisZ; |
|||
float cotan; |
|||
float3 color; |
|||
int sliceIndex; |
|||
float3 boxInnerDist; |
|||
float decodeExp; |
|||
float3 boxInvRange; |
|||
uint shadowLightIndex; |
|||
float3 localCubeCapturePoint; |
|||
float probeBlendDistance; |
|||
}; |
|||
|
|||
// Generated from SFiniteLightBound |
|||
// PackingRules = Exact |
|||
struct SFiniteLightBound |
|||
{ |
|||
float3 boxAxisX; |
|||
float3 boxAxisY; |
|||
float3 boxAxisZ; |
|||
float3 center; |
|||
float2 scaleXY; |
|||
float radius; |
|||
}; |
|||
|
|||
// Generated from DirectionalLight |
|||
// PackingRules = Exact |
|||
struct DirectionalLight |
|||
{ |
|||
float3 color; |
|||
float intensity; |
|||
float3 lightAxisX; |
|||
uint shadowLightIndex; |
|||
float3 lightAxisY; |
|||
float pad0; |
|||
float3 lightAxisZ; |
|||
float pad1; |
|||
}; |
|||
|
|||
// |
|||
// Accessors for SFiniteLightData |
|||
// |
|||
float GetPenumbra(SFiniteLightData value) |
|||
{ |
|||
return value.penumbra; |
|||
} |
|||
int GetFlags(SFiniteLightData value) |
|||
{ |
|||
return value.flags; |
|||
} |
|||
uint GetLightType(SFiniteLightData value) |
|||
{ |
|||
return value.lightType; |
|||
} |
|||
uint GetLightModel(SFiniteLightData value) |
|||
{ |
|||
return value.lightModel; |
|||
} |
|||
float3 GetLightPos(SFiniteLightData value) |
|||
{ |
|||
return value.lightPos; |
|||
} |
|||
float GetLightIntensity(SFiniteLightData value) |
|||
{ |
|||
return value.lightIntensity; |
|||
} |
|||
float3 GetLightAxisX(SFiniteLightData value) |
|||
{ |
|||
return value.lightAxisX; |
|||
} |
|||
float GetRecipRange(SFiniteLightData value) |
|||
{ |
|||
return value.recipRange; |
|||
} |
|||
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; |
|||
} |
|||
int GetSliceIndex(SFiniteLightData value) |
|||
{ |
|||
return value.sliceIndex; |
|||
} |
|||
float3 GetBoxInnerDist(SFiniteLightData value) |
|||
{ |
|||
return value.boxInnerDist; |
|||
} |
|||
float GetDecodeExp(SFiniteLightData value) |
|||
{ |
|||
return value.decodeExp; |
|||
} |
|||
float3 GetBoxInvRange(SFiniteLightData value) |
|||
{ |
|||
return value.boxInvRange; |
|||
} |
|||
uint GetShadowLightIndex(SFiniteLightData value) |
|||
{ |
|||
return value.shadowLightIndex; |
|||
} |
|||
float3 GetLocalCubeCapturePoint(SFiniteLightData value) |
|||
{ |
|||
return value.localCubeCapturePoint; |
|||
} |
|||
float GetProbeBlendDistance(SFiniteLightData value) |
|||
{ |
|||
return value.probeBlendDistance; |
|||
} |
|||
|
|||
// |
|||
// Accessors for 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 DirectionalLight |
|||
// |
|||
float3 GetColor(DirectionalLight value) |
|||
{ |
|||
return value.color; |
|||
} |
|||
float GetIntensity(DirectionalLight value) |
|||
{ |
|||
return value.intensity; |
|||
} |
|||
float3 GetLightAxisX(DirectionalLight value) |
|||
{ |
|||
return value.lightAxisX; |
|||
} |
|||
uint GetShadowLightIndex(DirectionalLight value) |
|||
{ |
|||
return value.shadowLightIndex; |
|||
} |
|||
float3 GetLightAxisY(DirectionalLight value) |
|||
{ |
|||
return value.lightAxisY; |
|||
} |
|||
float GetPad0(DirectionalLight value) |
|||
{ |
|||
return value.pad0; |
|||
} |
|||
float3 GetLightAxisZ(DirectionalLight value) |
|||
{ |
|||
return value.lightAxisZ; |
|||
} |
|||
float GetPad1(DirectionalLight value) |
|||
{ |
|||
return value.pad1; |
|||
} |
|||
|
|||
|
|||
#endif |
|
|||
#ifndef __TILEDLIGHTINGTEMPLATE_H__ |
|||
#define __TILEDLIGHTINGTEMPLATE_H__ |
|||
|
|||
|
|||
#include "TiledLightingUtils.hlsl" |
|||
#include "LightingTemplate.hlsl" |
|||
|
|||
|
|||
|
|||
float3 ExecuteLightList(out uint numLightsProcessed, uint2 pixCoord, float3 vP, float3 vPw, float3 Vworld) |
|||
{ |
|||
uint start = 0, numLights = 0; |
|||
GetCountAndStart(start, numLights, pixCoord, vP.z, DIRECT_LIGHT); |
|||
|
|||
numLightsProcessed = numLights; // mainly for debugging/heat maps |
|||
return ExecuteLightList(start, numLights, vP, vPw, Vworld); |
|||
} |
|||
|
|||
#endif |
|
|||
#ifndef __TILEDLIGHTINGUTILS_H__ |
|||
#define __TILEDLIGHTINGUTILS_H__ |
|||
|
|||
|
|||
#include "LightingUtils.hlsl" |
|||
|
|||
// these uniforms are only needed for when OPAQUES_ONLY is NOT defined |
|||
// but there's a problem with our front-end compilation of compute shaders with multiple kernels causing it to error |
|||
//#ifndef OPAQUES_ONLY |
|||
uniform float g_fClustScale; |
|||
uniform float g_fClustBase; |
|||
uniform float g_fNearPlane; |
|||
uniform float g_fFarPlane; |
|||
uniform int g_iLog2NumClusters; // We need to always define these to keep constant buffer layouts compatible |
|||
|
|||
uniform uint g_isLogBaseBufferEnabled; |
|||
uniform uint g_isOpaquesOnlyEnabled; |
|||
//#endif |
|||
|
|||
|
|||
StructuredBuffer<SFiniteLightData> g_vLightData; |
|||
StructuredBuffer<uint> g_vLightListGlobal; // don't support Buffer yet in unity |
|||
|
|||
|
|||
void GetCountAndStartOpaque(out uint uStart, out uint uNrLights, uint2 pixCoord, float linDepth, uint model) |
|||
{ |
|||
uint tileSize = 16; |
|||
uint nrTilesX = ((uint) (g_widthRT+(tileSize-1)))/tileSize; uint nrTilesY = ((uint) (g_heightRT+(tileSize-1)))/tileSize; |
|||
uint2 tileIDX = pixCoord / tileSize; |
|||
const int tileOffs = (tileIDX.y+model*nrTilesY)*nrTilesX+tileIDX.x; |
|||
|
|||
uNrLights = g_vLightListGlobal[ 16*tileOffs + 0]&0xffff; |
|||
uStart = tileOffs; |
|||
} |
|||
|
|||
uint FetchIndexOpaque(const uint tileOffs, const uint l) |
|||
{ |
|||
const uint l1 = l+1; |
|||
return (g_vLightListGlobal[ 16*tileOffs + (l1>>1)]>>((l1&1)*16))&0xffff; |
|||
} |
|||
|
|||
#ifdef OPAQUES_ONLY |
|||
|
|||
void GetCountAndStart(out uint uStart, out uint uNrLights, uint2 pixCoord, float linDepth, uint model) |
|||
{ |
|||
GetCountAndStartOpaque(uStart, uNrLights, pixCoord, linDepth, model); |
|||
} |
|||
|
|||
uint FetchIndex(const uint tileOffs, const uint l) |
|||
{ |
|||
return FetchIndexOpaque(tileOffs, l); |
|||
} |
|||
|
|||
#else |
|||
|
|||
#include "ClusteredUtils.h" |
|||
|
|||
StructuredBuffer<uint> g_vLayeredOffsetsBuffer; // don't support Buffer yet in unity |
|||
StructuredBuffer<float> g_logBaseBuffer; // don't support Buffer yet in unity |
|||
|
|||
|
|||
void GetCountAndStart(out uint uStart, out uint uNrLights, uint2 pixCoord, float linDepth, uint model) |
|||
{ |
|||
if(g_isOpaquesOnlyEnabled) |
|||
{ |
|||
GetCountAndStartOpaque(uStart, uNrLights, pixCoord, linDepth, model); |
|||
} |
|||
else |
|||
{ |
|||
uint nrTilesX = ((uint) (g_widthRT+(TILE_SIZE_CLUSTERED-1))) / ((uint) TILE_SIZE_CLUSTERED); |
|||
uint nrTilesY = ((uint) (g_heightRT+(TILE_SIZE_CLUSTERED-1))) / ((uint) TILE_SIZE_CLUSTERED); |
|||
uint2 tileIDX = pixCoord / ((uint) TILE_SIZE_CLUSTERED); |
|||
|
|||
float logBase = g_fClustBase; |
|||
if(g_isLogBaseBufferEnabled) |
|||
logBase = g_logBaseBuffer[tileIDX.y*nrTilesX + tileIDX.x]; |
|||
|
|||
int clustIdx = SnapToClusterIdxFlex(linDepth, logBase, g_isLogBaseBufferEnabled!=0); |
|||
|
|||
int nrClusters = (1<<g_iLog2NumClusters); |
|||
const int idx = ((model*nrClusters + clustIdx)*nrTilesY + tileIDX.y)*nrTilesX + tileIDX.x; |
|||
uint dataPair = g_vLayeredOffsetsBuffer[idx]; |
|||
uStart = dataPair&0x7ffffff; |
|||
uNrLights = (dataPair>>27)&31; |
|||
} |
|||
} |
|||
|
|||
uint FetchIndex(const uint tileOffs, const uint l) |
|||
{ |
|||
if(g_isOpaquesOnlyEnabled) |
|||
return FetchIndexOpaque(tileOffs, l); |
|||
else |
|||
return g_vLightListGlobal[ tileOffs+l ]; |
|||
} |
|||
|
|||
#endif |
|||
|
|||
|
|||
|
|||
#endif |
|
|||
#ifndef __TILEDREFLECTIONTEMPLATE_H__ |
|||
#define __TILEDREFLECTIONTEMPLATE_H__ |
|||
|
|||
|
|||
#include "TiledLightingUtils.hlsl" |
|||
#include "ReflectionTemplate.hlsl" |
|||
|
|||
|
|||
|
|||
float3 ExecuteReflectionList(out uint numReflectionProbesProcessed, uint2 pixCoord, float3 vP, float3 vNw, float3 Vworld, float smoothness) |
|||
{ |
|||
uint start = 0, numReflectionProbes = 0; |
|||
GetCountAndStart(start, numReflectionProbes, pixCoord, vP.z, REFLECTION_LIGHT); |
|||
|
|||
numReflectionProbesProcessed = numReflectionProbes; // mainly for debugging/heat maps |
|||
return ExecuteReflectionList(start, numReflectionProbes, vP, vNw, Vworld, smoothness); |
|||
} |
|||
|
|||
|
|||
#endif |
|
|||
#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 "..\common\ShaderBase.h" |
|||
#include "LightDefinitions.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.h" |
|||
|
|||
|
|||
#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 |
|||
StructuredBuffer<uint> g_vBigTileLightList : register( t4 ); // don't support Buffer yet in unity |
|||
#endif |
|||
|
|||
|
|||
#define NR_THREADS 64 |
|||
|
|||
// output buffer |
|||
RWStructuredBuffer<uint> g_vLayeredLightList : register( u0 ); // don't support RWBuffer yet in unity |
|||
RWStructuredBuffer<uint> g_LayeredOffset : register( u1 ); // don't support RWBuffer yet in unity |
|||
RWStructuredBuffer<uint> g_LayeredSingleIdxBuffer : register( u2 ); // don't support RWBuffer yet in unity |
|||
|
|||
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE |
|||
RWStructuredBuffer<float> g_logBaseBuffer : register( u3 ); // don't support RWBuffer yet in unity |
|||
#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 |
|||
const uint log2TileSize = firstbithigh(TILE_SIZE_CLUSTERED); |
|||
uint nrTilesX = (iWidth+(TILE_SIZE_CLUSTERED-1))>>log2TileSize; |
|||
uint nrTilesY = (iHeight+(TILE_SIZE_CLUSTERED-1))>>log2TileSize; |
|||
|
|||
uint2 viTilLL = TILE_SIZE_CLUSTERED*tileIDX; |
|||
uint2 viTilUR = min( viTilLL+uint2(TILE_SIZE_CLUSTERED,TILE_SIZE_CLUSTERED), 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<(TILE_SIZE_CLUSTERED*TILE_SIZE_CLUSTERED); idx+=NR_THREADS) |
|||
{ |
|||
uint2 uPixCrd = min( uint2(viTilLL.x+(idx&(TILE_SIZE_CLUSTERED-1)), viTilLL.y+(idx>>log2TileSize)), 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 |
|||
const uint log2BigTileToClustTileRatio = firstbithigh(64) - log2TileSize; |
|||
|
|||
int NrBigTilesX = (nrTilesX+((1<<log2BigTileToClustTileRatio)-1))>>log2BigTileToClustTileRatio; |
|||
const int bigTileIdx = (tileIDX.y>>log2BigTileToClustTileRatio)*NrBigTilesX + (tileIDX.x>>log2BigTileToClustTileRatio); // 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(TILE_SIZE_CLUSTERED/2,TILE_SIZE_CLUSTERED/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 |
|||
if(threadID==0) 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 = (TILE_SIZE_CLUSTERED/2)*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; |
|||
} |
1001
Assets/ScriptableRenderPipeline/fptl/FptlLighting.cs
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: 9d1c12c0e8e265a47b31bdd5728a079b |
|||
folderAsset: yes |
|||
timeCreated: 1473161971 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: ac502c5271c0a254b8a18fbe4b8a3bf1 |
|||
timeCreated: 1473161518 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 5696f1f3528fdab49bccea664827108c |
|||
folderAsset: yes |
|||
timeCreated: 1473161495 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
1001
Assets/TestScenes/FPTL/FPTL.unity
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
7
Assets/TestScenes/FPTL/FPTL/LightingData.asset
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: 69881ce3df6a158419708b1cb7429d87 |
|||
timeCreated: 1473174122 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
v/1 channels chlist 7 B G R compression compression dataWindow box2i � displayWindow box2i � lineOrder lineOrder pixelAspectRatio float �?screenWindowCenter v2f screenWindowWidth float �? Y �� \� �� a� �@��]����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������۽�������ۿ��L�2�Da�� � � 1�q�q�q� � $�I(�I(��,��,�0�0��0�0��0�M8�M8Ӎ4�L4�
0�M0��<�N<��4�M8��<��8�M4��<� @�;@��@��8�<� <���A�� �� �@;A;<C��� �M�������A��Q�5�PC��?KC��?C�t?C�d? C�?)C�=C��;C�t>C�d<C�D<C��?C�?5C�?
C��?9C�?C�4?C�����!ؐ�Đ���ܐ���!�P�
�P�Ɛ�)�P�����ڐ�M��0C�?��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<C�?#<?C�$?@;C�D? C�>C���C� C�?A=?��C�A ����<���A @�O<�<�<A@�C� �@<�= <�A� �<�@���<��<��@���<�<��4��<��8�8��8�M<Ӎ4�
8Î4�N4�M0�0�L4�0�
0�0�0�,��,��,��,��,��,��(��$�I$�I$�I$�I � �q�q�q�a�a�q�q [T�*�%K*IU�&���VeBvS@���� `J�S�^J&J�S��Q��"F�Q��B ����n�x
xH���D�}�<�(@,� ���EA=�&���Ç�qе�/��P�������Xh�5.6d |
|||
�@�l�T��¢k T&�3D�$
��H�"���US����RI�(R ����W�<^<�������'���aA4 �&�0hS�u0+D}�+�]$���W����|P��i*URJ���ʒ�U$��t�&�2D�% UJ�S�^J'J�S�]J )]��n�F�dQ���^<y�\x��W��Q��� G.d(� d�$"�RBaI�Î �t㡛�]��#x���!�����{���hsA �� ����9�C���O��� ��ঊk��j���� �\)� K�^�w�@I�뺽�wW��������-0`�� `)0�� ]&`�5(\��2�e�"�� |
|||
X` %���60�A���;0`YRjP�B�(}Be |
|||
&P����%P��� �&P}D*$���>�'��蛌/���cr0���X
�#Q�82 2 |
|||
d@dL�L@�t�. �\l��
�yp�p7`>� ����v`)`� �����%A�S%A���*����QSA�V |
|||
�ʘ* �Q��E(&KUJ�!�*�R�JU*�R�L<3��D|V+��c���xf+������x�������������������乣X�=��S��?O��)^��������,�fO��oWwwwwwwwwwww������)E��h�
CP�t5��A��_�,���X���j AP�t:����l����e�l��.������z���ƾƾ�_^W��|�0��1�����1,llllJ����|�_]H�k5���s9�c1��l��l�����f͛6����ٳ�������Ͷlٳf��f��{6{{�C��t�A(jAO��~�_�߰o����"U��t:�P�5$N�n�%�v��.K��wswr]���K%��I�ٯ����a��ޖJ�������g��z���������ܷ-˕�������\�w�Aa�f�����a���qqqئ)��W�f�0�3�^�VԊ�Q�TJ��ԩi:�ͥҴ��i6���+1I8���Rooz]#{x�����pp��E���K6$iVĎn �;^C |
|||
S�S�H[,�l�B�tE�qq���S)�",���y#��g �G Rf�d��%�8K$9& |
|||
�P���xR�xR�����J�2�d)�d)��SxN�'D�K����C���K��³Fn�²�ժ��sR�@q:��䲔<�JKR�R�C�la��P�](v>0�v �)� |
|||
��/W��oޯ�������9n�T�!�3�7D���/*���}[{�����o�����;����������߷�������CO�����)_\P��'b�(b��� �(2q�ɠ'�@NJ )%�]a9�0(1��� |
|||
�ʽH�U�j��
��S*
���j
���+k 7ů'd�0D�.6c�����BE�K� �Dfi��4��|� z\��\���ll��#1�6b�>�bȖʣ+�HVJ�VVd��d��h�U��VJ$}[Qj%�Q�ԣS2�u0���L<��oo�|V+������`��;����\���ۭ�76�6���䷞$w=N�����g�i^�ް������XwT�@�����wwr]��K�������!d |
|||
�Z�C��)}C������/�I�� A��h4�A($����e��z[-%jԵ-,lllllllllk������]R�zaA��g1Lf%�ccb��,K��_/����5Mf�Y��g1Lw��{=�of͛6lٳf͛?��{�����������ٳf���������=���t A��g��� |
|||
w����������҈4
�PT |
|||
����v�.n�7%�����sv�.n�jG���)8&��풇����w=N�$������+rܷ-�V��r��.nnnn������3����0��qqqqqo*�wz`���f���*I[I*-���UD��)R�Z�2��y+�jWR��y-���ѹ���4������^<�\�Ǟ�>��� �,�t:��@hh��t��Zq�@�a�W���������V-K�EL.6�D\6���$�%�X�`L�,�RA�"��EIRJ�I^JO�};��� z��4J�g�@�N��4 �Zdp�]8�^</{}�����0JIY�����$�W3$�RT%Q |
|||
xR��W�ԯ%��K)]�F�v7chی�m�P�O�t^<��x�}����"���p#�
�f�I<p늺m�?t몼y৴��h���5���1XA �������p�B^���~�}0+"S@���m�����9�M߷g��4`{����സq}�� ��y��y�4�`��(Ȁ���d��˓�&%(�E�0T �2\`�p�+��(�u�a*`��I��&Q�J�/P�F�*��Je��B�R� E /����<�[Q(����7��a�F |
|||
�U���T�q�� �d@f��� �e�p���|�l�Z�m}�����|���V��X���Qb�J�X�QqSKJ� |
|||
��0VJ�*,*\�rE*J��)R�T��r�*eJ����`��p�7�e�z]�fqqqqqp��<<6 ��x�������������ܷ�����Q�;Ngd�;���tQ�/ooop�l<6�^�������77k���sv��������.~�����Ph4u;���������e�g����?�������J�[-��Iz[-�J�]l�Z��ı��cc1X�������� |
|||
ɜ�g1Lf3ė��|�_/���3Mf�9��b�������f͛6lٳ�f͛6lٳf��m���g���߶lٳ��{f�����Ph4
�����zOI��wj��z��_�����*�Ph$�������'76���ssr�������,v����H��0�8f���콲T�w;��Ӕ�sE{{R�n�����-�V���������ppppX,<<<<S 'wk������a�,:;�w�����=6N����*'i.���+)x�GƎ>4Q��BQ�7��n��#z�D����/��` ��)l�!�;A���������9��%ҞK)Q���mde�ȋ*T�ZTp� $��w����ɑ��������ԙJ��CW��ϩxR�xM�J��])��c���Jas�];�${xJ�����3��w��;��²�͕F��Ҫ�g�<� |
|||
5� Ӈ��C�jP�YJ��=z>0�V �\A�xC�&|@��T��R��R��=�;�7�n�xCp�"S��];�;� mu�8)sAJ� |
|||
<���=�\:�0ހ^���"`,��� |
|||
]�N�)� |
|||
��@\Y��Q�@�����$PT�[�U�[h�� ��(���Q���'_\N��j�`J�������d\e��ɟ'�>S(|�T�UJ���\J�&��R�TZU�H�j�UJ5J*�5�5�U��Ep�T鐥Q8���Ď.3�2��R� |
|||
�***�q��fg2�Ȝe���\��\�������&)�`��s˥.�i*�iY\�B�U���Ed�E %$�^��P�T��J9��`�& �`��o�e���z�.�)���������`���$��sr���-�V�����{{[r�t��7'3��읔1�]��������`�l<2�wwwuTEgs��ܮnm˛�����2����?Oh%�W�����{z_�=��g���{?�����?()�-��I|�/��֥d��[-��R�1��f3b��)�įW������(5L�s4�c1������������|�]I�f��fsg ŀd�����<x&:Lj����@�@�@��W�\ |
|||
� |
|||
� |
|||
��o"�1�K�2�%�� �@�A.A60(�����R�O��< |
|||
{� �A3� ��e�A1PL�7� |
|||
X�)`R�c�R�� R��
~�����{?��S��;��'{z�/oo����W�J�����{=���ܷ��\��{��or�O;������w{��`�X,3���z����P�s9���y��v����jZ�ږ�[R��ooosr[�'�~���a�f)��]��ݮ��W���%I�U.�����O�2�T�e �<�*���$�F�Xһ�܌�r1tH� |
|||
�@�������CGN�M㮈�:�|J��0�&�<� G� |
|||
,�4���>�P0F�S�^Ju+�O�}(/�0�1X`�r�����F |
|||
�ʘ*(�@�c+�J�%B�K����� ,H!"��P�%y*4�� �}�p9�+�O%y(�_Lu4 ��g a8��
��q�x5|��$_@����}��@j�T¤ժ�V� G�g��Be
�J���i+�aJ�S�]Ju+����ebn!����RB.�$-���C�^}�ω�A�!|N� �0!�XRB.�$ �I�î���C7N:An��,�N���W�
X #��|/���=D@��i+���D� �cպ�ƭ�� < !;"����}�[�p���{� �k��Ë�\:�.\s���0 2�D@�d).�&@Qr�QEʀ�T�P�S ࡂ�SL �T�P�S%E��PQBU \P�K�(aL*O�j ,@�HS@�WҡL�`_L�T9�NF��`�|�C�L,D�����t�R2�Ad��f@�\<\�p��t�|�L& |