implement tiled lighting part2
This commit is contained in:
@@ -52,7 +52,7 @@ struct Frustum
|
||||
float4 ClipToView(float4 clip)
|
||||
{
|
||||
// View space position.
|
||||
float4 view = mul(g_xCamera_InvP, clip);
|
||||
float4 view = mul(clip, g_xCamera_InvP);
|
||||
// Perspective projection.
|
||||
view = view / view.w;
|
||||
|
||||
|
||||
@@ -133,6 +133,14 @@ inline float2 GetScreenResolution() { return g_xWorld_ScreenWidthHeight; }
|
||||
inline float GetScreenWidth() { return g_xWorld_ScreenWidthHeight.x; }
|
||||
inline float GetScreenHeight() { return g_xWorld_ScreenWidthHeight.y; }
|
||||
inline float GetTime() { return g_xFrame_WindTime; }
|
||||
inline float GetEmissive(float emissive) { return emissive * 10.0f; };
|
||||
inline float GetEmissive(float emissive) { return emissive * 10.0f; }
|
||||
|
||||
struct ComputeShaderInput
|
||||
{
|
||||
uint3 groupID : SV_GroupID; // 3D index of the thread group in the dispatch.
|
||||
uint3 groupThreadID : SV_GroupThreadID; // 3D index of local thread ID in a thread group.
|
||||
uint3 dispatchThreadID : SV_DispatchThreadID; // 3D index of global thread ID in the dispatch.
|
||||
uint groupIndex : SV_GroupIndex; // Flattened local index of the thread within a thread group.
|
||||
};
|
||||
|
||||
#endif // _SHADER_GLOBALS_
|
||||
@@ -1,13 +1,9 @@
|
||||
#include "globals.hlsli"
|
||||
#include "cullingShaderHF.hlsli"
|
||||
|
||||
groupshared uint minDepthInt;
|
||||
groupshared uint maxDepthInt;
|
||||
|
||||
RWTexture2D<float4> tex : register(u0);
|
||||
RWTEXTURE2D(DebugTexture, float4, 0);
|
||||
|
||||
STRUCTUREDBUFFER(in_Frustums, Frustum, SBSLOT_TILEFRUSTUMS);
|
||||
groupshared Frustum frustum;
|
||||
|
||||
struct LightArrayType
|
||||
{
|
||||
@@ -18,6 +14,12 @@ struct LightArrayType
|
||||
RWSTRUCTUREDBUFFER(lightArray, LightArrayType, SBSLOT_LIGHTARRAY);
|
||||
#define lightCount ((int)g_xColor.x)
|
||||
|
||||
|
||||
groupshared uint uMinDepth;
|
||||
groupshared uint uMaxDepth;
|
||||
groupshared Frustum GroupFrustum;
|
||||
|
||||
|
||||
bool intersects(LightArrayType light, Frustum frustum, float minZ, float maxZ)
|
||||
{
|
||||
Sphere sphere;
|
||||
@@ -31,70 +33,146 @@ groupshared uint visibleLightIndices[1024];
|
||||
|
||||
#define BLOCK_SIZE 16
|
||||
[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)]
|
||||
void main(
|
||||
uint3 groupId : SV_GroupID,
|
||||
uint3 groupThreadId : SV_GroupThreadID,
|
||||
uint3 dispatchThreadId : SV_DispatchThreadID, //
|
||||
uint groupIndex : SV_GroupIndex)
|
||||
void main(ComputeShaderInput IN)
|
||||
{
|
||||
float depth = texture_lineardepth.Load(uint3(dispatchThreadId.xy, 0)).r / g_xCamera_ZFarP;
|
||||
uint depthInt = asuint(depth);
|
||||
// Calculate min & max depth in threadgroup / tile.
|
||||
int2 texCoord = IN.dispatchThreadID.xy;
|
||||
float fDepth = texture_depth.Load(int3(texCoord, 0)).r;
|
||||
|
||||
if (groupIndex == 0) // Avoid contention by other threads in the group.
|
||||
uint uDepth = asuint(fDepth);
|
||||
|
||||
if (IN.groupIndex == 0) // Avoid contention by other threads in the group.
|
||||
{
|
||||
minDepthInt = 0xffffffff;
|
||||
maxDepthInt = 0;
|
||||
uMinDepth = 0xffffffff;
|
||||
uMaxDepth = 0;
|
||||
//o_LightCount = 0;
|
||||
//t_LightCount = 0;
|
||||
frustum = in_Frustums[groupId.x + (groupId.y * numThreadGroups.x)];
|
||||
}
|
||||
|
||||
//minDepthInt = 0xFFFFFFFF;
|
||||
//maxDepthInt = 0;
|
||||
|
||||
GroupMemoryBarrierWithGroupSync();
|
||||
|
||||
InterlockedMin(minDepthInt, depthInt);
|
||||
InterlockedMax(maxDepthInt, depthInt);
|
||||
|
||||
GroupMemoryBarrierWithGroupSync();
|
||||
|
||||
float minGroupDepth = asfloat(minDepthInt);
|
||||
float maxGroupDepth = asfloat(maxDepthInt);
|
||||
|
||||
//tex[dispatchThreadId.xy] = minGroupDepth;
|
||||
|
||||
uint threadCount = BLOCK_SIZE*BLOCK_SIZE;
|
||||
uint passCount = (lightCount + threadCount - 1) / threadCount;
|
||||
|
||||
for (uint passIt = 0; passIt < passCount; ++passIt)
|
||||
{
|
||||
uint lightIndex = passIt*threadCount + groupIndex;
|
||||
|
||||
// prevent overrun by clamping to last "null" light
|
||||
lightIndex = min(lightIndex, lightCount);
|
||||
|
||||
if (intersects(lightArray[lightIndex], frustum, minGroupDepth, maxGroupDepth))
|
||||
{
|
||||
uint offset;
|
||||
InterlockedAdd(visibleLightCount, 1, offset);
|
||||
visibleLightIndices[offset] = lightIndex;
|
||||
}
|
||||
GroupFrustum = in_Frustums[IN.groupID.x + (IN.groupID.y * numThreadGroups.x)];
|
||||
}
|
||||
|
||||
GroupMemoryBarrierWithGroupSync();
|
||||
|
||||
float4 color = 0;
|
||||
for (uint lightIt = 0; lightIt < visibleLightCount; ++lightIt)
|
||||
{
|
||||
uint lightIndex = visibleLightIndices[lightIt];
|
||||
LightArrayType light = lightArray[lightIndex];
|
||||
InterlockedMin(uMinDepth, uDepth);
|
||||
InterlockedMax(uMaxDepth, uDepth);
|
||||
|
||||
color += light.col;
|
||||
}
|
||||
color.a = 1;
|
||||
GroupMemoryBarrierWithGroupSync();
|
||||
|
||||
color.rgb = frustum.planes[0].N;
|
||||
float fMinDepth = asfloat(uMinDepth);
|
||||
float fMaxDepth = asfloat(uMaxDepth);
|
||||
|
||||
tex[dispatchThreadId.xy] = color;
|
||||
// Convert depth values to view space.
|
||||
float minDepthVS = ScreenToView(float4(0, 0, fMinDepth, 1)).z;
|
||||
float maxDepthVS = ScreenToView(float4(0, 0, fMaxDepth, 1)).z;
|
||||
float nearClipVS = ScreenToView(float4(0, 0, 0, 1)).z;
|
||||
|
||||
// Clipping plane for minimum depth value
|
||||
// (used for testing lights within the bounds of opaque geometry).
|
||||
Plane minPlane = { float3(0, 0, -1), -minDepthVS };
|
||||
|
||||
//// Cull lights
|
||||
//// Each thread in a group will cull 1 light until all lights have been culled.
|
||||
//for (uint i = IN.groupIndex; i < NUM_LIGHTS; i += BLOCK_SIZE * BLOCK_SIZE)
|
||||
//{
|
||||
// if (Lights[i].Enabled)
|
||||
// {
|
||||
// Light light = Lights[i];
|
||||
|
||||
// switch (light.Type)
|
||||
// {
|
||||
// case POINT_LIGHT:
|
||||
// {
|
||||
// Sphere sphere = { light.PositionVS.xyz, light.Range };
|
||||
// if (SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS))
|
||||
// {
|
||||
// // Add light to light list for transparent geometry.
|
||||
// t_AppendLight(i);
|
||||
|
||||
// if (!SphereInsidePlane(sphere, minPlane))
|
||||
// {
|
||||
// // Add light to light list for opaque geometry.
|
||||
// o_AppendLight(i);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// case SPOT_LIGHT:
|
||||
// {
|
||||
// float coneRadius = tan(radians(light.SpotlightAngle)) * light.Range;
|
||||
// Cone cone = { light.PositionVS.xyz, light.Range, light.DirectionVS.xyz, coneRadius };
|
||||
// if (ConeInsideFrustum(cone, GroupFrustum, nearClipVS, maxDepthVS))
|
||||
// {
|
||||
// // Add light to light list for transparent geometry.
|
||||
// t_AppendLight(i);
|
||||
|
||||
// if (!ConeInsidePlane(cone, minPlane))
|
||||
// {
|
||||
// // Add light to light list for opaque geometry.
|
||||
// o_AppendLight(i);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// case DIRECTIONAL_LIGHT:
|
||||
// {
|
||||
// // Directional lights always get added to our light list.
|
||||
// // (Hopefully there are not too many directional lights!)
|
||||
// t_AppendLight(i);
|
||||
// o_AppendLight(i);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//// Wait till all threads in group have caught up.
|
||||
//GroupMemoryBarrierWithGroupSync();
|
||||
|
||||
//// Update global memory with visible light buffer.
|
||||
//// First update the light grid (only thread 0 in group needs to do this)
|
||||
//if (IN.groupIndex == 0)
|
||||
//{
|
||||
// // Update light grid for opaque geometry.
|
||||
// InterlockedAdd(o_LightIndexCounter[0], o_LightCount, o_LightIndexStartOffset);
|
||||
// o_LightGrid[IN.groupID.xy] = uint2(o_LightIndexStartOffset, o_LightCount);
|
||||
|
||||
// // Update light grid for transparent geometry.
|
||||
// InterlockedAdd(t_LightIndexCounter[0], t_LightCount, t_LightIndexStartOffset);
|
||||
// t_LightGrid[IN.groupID.xy] = uint2(t_LightIndexStartOffset, t_LightCount);
|
||||
//}
|
||||
|
||||
//GroupMemoryBarrierWithGroupSync();
|
||||
|
||||
//// Now update the light index list (all threads).
|
||||
//// For opaque goemetry.
|
||||
//for (i = IN.groupIndex; i < o_LightCount; i += BLOCK_SIZE * BLOCK_SIZE)
|
||||
//{
|
||||
// o_LightIndexList[o_LightIndexStartOffset + i] = o_LightList[i];
|
||||
//}
|
||||
//// For transparent geometry.
|
||||
//for (i = IN.groupIndex; i < t_LightCount; i += BLOCK_SIZE * BLOCK_SIZE)
|
||||
//{
|
||||
// t_LightIndexList[t_LightIndexStartOffset + i] = t_LightList[i];
|
||||
//}
|
||||
|
||||
//// Update the debug texture output.
|
||||
//if (IN.groupThreadID.x == 0 || IN.groupThreadID.y == 0)
|
||||
//{
|
||||
// DebugTexture[texCoord] = float4(0, 0, 0, 0.9f);
|
||||
//}
|
||||
//else if (IN.groupThreadID.x == 1 || IN.groupThreadID.y == 1)
|
||||
//{
|
||||
// DebugTexture[texCoord] = float4(1, 1, 1, 0.5f);
|
||||
//}
|
||||
//else if (o_LightCount > 0)
|
||||
//{
|
||||
// float normalizedLightCount = o_LightCount / 50.0f;
|
||||
// float4 lightCountHeatMapColor = LightCountHeatMap.SampleLevel(LinearClampSampler, float2(normalizedLightCount, 0), 0);
|
||||
// DebugTexture[texCoord] = lightCountHeatMapColor;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// DebugTexture[texCoord] = float4(0, 0, 0, 1);
|
||||
//}
|
||||
|
||||
//DebugTexture[texCoord] = float4(GroupFrustum.planes[0].N,1);
|
||||
}
|
||||
@@ -6,26 +6,22 @@ RWSTRUCTUREDBUFFER(out_Frustums, Frustum, SBSLOT_TILEFRUSTUMS);
|
||||
|
||||
#define BLOCK_SIZE 16
|
||||
[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)]
|
||||
void main(
|
||||
uint3 groupId : SV_GroupID,
|
||||
uint3 groupThreadId : SV_GroupThreadID,
|
||||
uint3 dispatchThreadId : SV_DispatchThreadID, //
|
||||
uint groupIndex : SV_GroupIndex)
|
||||
void main(ComputeShaderInput IN)
|
||||
{
|
||||
// View space eye position is always at the origin.
|
||||
const float3 eyePos = float3(0, 0, 0);
|
||||
|
||||
// Compute the 4 corner points on the far clipping plane to use as the
|
||||
// Compute 4 points on the far clipping plane to use as the
|
||||
// frustum vertices.
|
||||
float4 screenSpace[4];
|
||||
// Top left point
|
||||
screenSpace[0] = float4(dispatchThreadId.xy * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
screenSpace[0] = float4(IN.dispatchThreadID.xy * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
// Top right point
|
||||
screenSpace[1] = float4(float2(dispatchThreadId.x + 1, dispatchThreadId.y) * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
screenSpace[1] = float4(float2(IN.dispatchThreadID.x + 1, IN.dispatchThreadID.y) * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
// Bottom left point
|
||||
screenSpace[2] = float4(float2(dispatchThreadId.x, dispatchThreadId.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
screenSpace[2] = float4(float2(IN.dispatchThreadID.x, IN.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
// Bottom right point
|
||||
screenSpace[3] = float4(float2(dispatchThreadId.x + 1, dispatchThreadId.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
screenSpace[3] = float4(float2(IN.dispatchThreadID.x + 1, IN.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
|
||||
|
||||
float3 viewSpace[4];
|
||||
// Now convert the screen space points to view space
|
||||
@@ -47,9 +43,10 @@ void main(
|
||||
frustum.planes[3] = ComputePlane(eyePos, viewSpace[3], viewSpace[2]);
|
||||
|
||||
// Store the computed frustum in global memory (if our thread ID is in bounds of the grid).
|
||||
if (dispatchThreadId.x < numThreads.x && dispatchThreadId.y < numThreads.y)
|
||||
if (IN.dispatchThreadID.x < numThreads.x && IN.dispatchThreadID.y < numThreads.y)
|
||||
{
|
||||
uint index = dispatchThreadId.x + (dispatchThreadId.y * numThreads.x);
|
||||
uint index = IN.dispatchThreadID.x + (IN.dispatchThreadID.y * numThreads.x);
|
||||
out_Frustums[index] = frustum;
|
||||
}
|
||||
//out_Frustums[0].planes[0].N = float3(1, 0, 1);
|
||||
}
|
||||
+23
-19
@@ -246,6 +246,7 @@ void wiRenderer::SetUpStaticComponents()
|
||||
|
||||
GetDevice()->LOCK();
|
||||
BindPersistentState(GRAPHICSTHREAD_IMMEDIATE);
|
||||
UpdateWorldCB(GRAPHICSTHREAD_IMMEDIATE);
|
||||
GetDevice()->UNLOCK();
|
||||
|
||||
//t1.join();
|
||||
@@ -1426,13 +1427,16 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
|
||||
static ShaderBoneType *bonebuf[GRAPHICSTHREAD_COUNT] = { 0 };
|
||||
if (bonebuf[threadID] == nullptr)
|
||||
{
|
||||
bonebuf[threadID] = new ShaderBoneType[maxBoneCount];
|
||||
bonebuf[threadID] = (ShaderBoneType*)_mm_malloc(sizeof(ShaderBoneType)*maxBoneCount, 16);
|
||||
}
|
||||
if (mesh->armature->boneCollection.size() > maxBoneCount)
|
||||
{
|
||||
maxBoneCount = (int)mesh->armature->boneCollection.size() * 2;
|
||||
SAFE_DELETE_ARRAY(bonebuf[threadID]);
|
||||
bonebuf[threadID] = new ShaderBoneType[maxBoneCount];
|
||||
if (bonebuf[threadID] != nullptr)
|
||||
{
|
||||
_mm_free(bonebuf[threadID]);
|
||||
}
|
||||
bonebuf[threadID] = (ShaderBoneType*)_mm_malloc(sizeof(ShaderBoneType)*maxBoneCount, 16);
|
||||
}
|
||||
for (unsigned int k = 0; k < mesh->armature->boneCollection.size(); k++) {
|
||||
bonebuf[threadID][k].pose = mesh->armature->boneCollection[k]->boneRelativity;
|
||||
@@ -3309,10 +3313,22 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
|
||||
|
||||
int _width = device->GetScreenWidth();
|
||||
int _height = device->GetScreenHeight();
|
||||
int tileCount = (int)(ceilf((float)_width / 16.f) * ceilf((float)_height / 16.f));
|
||||
|
||||
|
||||
// Calc dispatchparams
|
||||
int _B = 16;
|
||||
DispatchParamsCB dispatchParams;
|
||||
dispatchParams.numThreads[0] = (UINT)ceilf((float)_width / _B);
|
||||
dispatchParams.numThreads[1] = (UINT)ceilf((float)_height / _B);
|
||||
dispatchParams.numThreads[2] = 1;
|
||||
dispatchParams.numThreadGroups[0] = (UINT)ceilf((float)dispatchParams.numThreads[0] / _B);
|
||||
dispatchParams.numThreadGroups[1] = (UINT)ceilf((float)dispatchParams.numThreads[1] / _B);
|
||||
dispatchParams.numThreadGroups[2] = 1;
|
||||
device->UpdateBuffer(constantBuffers[CBTYPE_DISPATCHPARAMS], &dispatchParams, threadID);
|
||||
device->BindConstantBufferCS(constantBuffers[CBTYPE_DISPATCHPARAMS], CB_GETBINDSLOT(DispatchParamsCB), threadID);
|
||||
|
||||
static GPUBuffer* frustumBuffer = nullptr;
|
||||
if(frustumBuffer == nullptr)
|
||||
if (frustumBuffer == nullptr)
|
||||
{
|
||||
frustumBuffer = new GPUBuffer;
|
||||
|
||||
@@ -3320,7 +3336,7 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
|
||||
|
||||
GPUBufferDesc bd;
|
||||
ZeroMemory(&bd, sizeof(bd));
|
||||
bd.ByteWidth = _stride * tileCount; // storing 4 planes for every tile
|
||||
bd.ByteWidth = _stride * dispatchParams.numThreads[0] * dispatchParams.numThreads[1] * dispatchParams.numThreads[2]; // storing 4 planes for every tile
|
||||
bd.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
|
||||
bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
|
||||
bd.Usage = USAGE_DEFAULT;
|
||||
@@ -3330,18 +3346,6 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
|
||||
|
||||
}
|
||||
|
||||
// Calc dispatchparams
|
||||
int _B = 16;
|
||||
DispatchParamsCB dispatchParams;
|
||||
dispatchParams.numThreads[0] = (uint32_t)ceilf((float)_width / _B);
|
||||
dispatchParams.numThreads[1] = (uint32_t)ceilf((float)_height / _B);
|
||||
dispatchParams.numThreads[2] = 1;
|
||||
dispatchParams.numThreadGroups[0] = (uint32_t)ceilf((float)dispatchParams.numThreads[0] / _B);
|
||||
dispatchParams.numThreadGroups[1] = (uint32_t)ceilf((float)dispatchParams.numThreads[1] / _B);
|
||||
dispatchParams.numThreadGroups[0] = 1;
|
||||
device->UpdateBuffer(constantBuffers[CBTYPE_DISPATCHPARAMS], &dispatchParams, threadID);
|
||||
device->BindConstantBufferCS(constantBuffers[CBTYPE_DISPATCHPARAMS], CB_GETBINDSLOT(DispatchParamsCB), threadID);
|
||||
|
||||
// calculate the per-tile frustums once:
|
||||
static bool frustumsComplete = false;
|
||||
if(!frustumsComplete)
|
||||
@@ -3349,7 +3353,7 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
|
||||
frustumsComplete = true;
|
||||
device->BindUnorderedAccessResourceCS(frustumBuffer, SBSLOT_TILEFRUSTUMS, threadID);
|
||||
device->BindCS(computeShaders[CSTYPE_TILEFRUSTUMS], threadID);
|
||||
device->Dispatch(dispatchParams.numThreads[0], dispatchParams.numThreads[1], dispatchParams.numThreads[2], threadID);
|
||||
device->Dispatch(dispatchParams.numThreadGroups[0], dispatchParams.numThreadGroups[1], dispatchParams.numThreadGroups[2], threadID);
|
||||
device->UnBindUnorderedAccessResources(SBSLOT_TILEFRUSTUMS, 1, threadID);
|
||||
}
|
||||
|
||||
|
||||
@@ -257,8 +257,8 @@ public:
|
||||
};
|
||||
GFX_STRUCT DispatchParamsCB
|
||||
{
|
||||
uint32_t numThreadGroups[3]; uint32_t pad0;
|
||||
uint32_t numThreads[3]; uint32_t pad1;
|
||||
UINT numThreadGroups[3]; UINT pad0;
|
||||
UINT numThreads[3]; UINT pad1;
|
||||
|
||||
CB_SETBINDSLOT(CBSLOT_RENDERER_DISPATCHPARAMS)
|
||||
|
||||
@@ -271,6 +271,8 @@ public:
|
||||
XMFLOAT4X4 pose, prev;
|
||||
|
||||
STRUCTUREDBUFFER_SETBINDSLOT(SBSLOT_BONE)
|
||||
|
||||
ALIGN_16
|
||||
};
|
||||
|
||||
GFX_STRUCT LightArrayType
|
||||
@@ -280,6 +282,8 @@ public:
|
||||
XMFLOAT4 col;
|
||||
|
||||
STRUCTUREDBUFFER_SETBINDSLOT(SBSLOT_LIGHTARRAY)
|
||||
|
||||
ALIGN_16
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user