-
-
Save httpdigest/15399efe2b60a2b31d1c2cbe414ce5cf to your computer and use it in GitHub Desktop.
Hierarchical GPU Frustum Culling and MultiDrawArraysIndirectCount Buffer Generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 430 core | |
#ifdef GL_NV_gpu_shader5 | |
#extension GL_NV_gpu_shader5 : enable | |
#elif GL_AMD_gpu_shader_int16 | |
#extension GL_AMD_gpu_shader_int16 : enable | |
#endif | |
#ifdef GL_ARB_shader_atomic_counter_ops | |
#extension GL_ARB_shader_atomic_counter_ops : enable | |
#endif | |
struct nodegeom { | |
u8vec3 min; | |
u8vec3 max; | |
uint16_t left, right; | |
}; | |
layout(binding = 0) uniform atomic_uint counter; | |
layout(std430, binding = 1) readonly restrict buffer NodeGeometries { nodegeom[] nodeGeomtries; }; | |
layout(std430, binding = 2) readonly restrict buffer InputNodes { uint16_t[] inputNodes; }; | |
layout(std430, binding = 3) writeonly restrict buffer OutputNodes { uint16_t[] outputNodes; }; | |
layout(std430, binding = 4) readonly buffer Counts { uint[] counts; }; | |
struct node { | |
u8vec3 min; | |
u8vec3 max; | |
uint16_t left, right; | |
uint firstVoxel; | |
uint numVoxels; | |
uint8_t splitAxis; uint8_t splitPos; | |
uint16_t ropes[6]; | |
}; | |
layout(std430, binding = 5) readonly restrict buffer Nodes { node[] nodes; }; | |
struct DrawArraysIndirectCommand { | |
uint count; | |
uint instanceCount; | |
uint first; | |
uint baseInstance; | |
}; | |
layout(std430, binding = 6) writeonly restrict buffer DrawCommands { DrawArraysIndirectCommand[] drawCommands; }; | |
#define MODE_CULL 0u | |
#define MODE_NODES_TO_DRAWCALLS 1u | |
uniform mat4 vpt; | |
uniform uint mode = MODE_CULL; | |
uniform vec3 cameraPosition = vec3(0.0, 0.0, 0.0); | |
bool frustumCull(const in nodegeom n, const in vec4[6] p) { | |
#define CMP(N) (dot(p[N].xyz, mix(vec3(n.min), vec3(n.max)+1.0, greaterThan(p[N].xyz, vec3(0.0)))) >= -p[N].w) | |
return CMP(0) && CMP(1) && CMP(2) && CMP(3) && CMP(4) && CMP(5); | |
#undef CMP | |
} | |
bool largeEnough(const in nodegeom n) { | |
float diag = length(vec3(n.max) + vec3(1.0) - vec3(n.min)); | |
vec3 cent = (vec3(n.max) + vec3(1.0) + vec3(n.min)) * 0.5; | |
float camDist = distance(cent, cameraPosition); | |
return diag / camDist > 0.5; | |
} | |
#define NO_NODE uint16_t(-1u) | |
layout (local_size_x = 8, local_size_y = 8) in; | |
void cull(void) { | |
const uint nindex = gl_GlobalInvocationID.y * gl_NumWorkGroups.x * gl_WorkGroupSize.x + gl_GlobalInvocationID.x; | |
if (nindex >= counts[0] || nindex >= inputNodes.length()) | |
return; | |
const vec4 p[6] = vec4[6](vpt[3] + vpt[0], vpt[3] - vpt[0], | |
vpt[3] + vpt[1], vpt[3] - vpt[1], | |
vpt[3] + vpt[2], vpt[3] - vpt[2]); | |
const uint16_t nidx = inputNodes[nindex]; | |
const nodegeom n = nodeGeomtries[nidx]; | |
const bool pred = frustumCull(n, p); | |
if (pred) { | |
if (largeEnough(n) && n.left != NO_NODE) { | |
#ifdef GL_ARB_shader_atomic_counter_ops | |
uint idx = atomicCounterAddARB(counter, 2u); | |
outputNodes[idx] = n.left; | |
outputNodes[idx+1u] = n.right; | |
#else | |
outputNodes[atomicCounterIncrement(counter)] = n.left; | |
outputNodes[atomicCounterIncrement(counter)] = n.right; | |
#endif | |
} else { | |
outputNodes[atomicCounterIncrement(counter)] = nidx; | |
} | |
} | |
} | |
void producedraws(void) { | |
const uint nindex = gl_GlobalInvocationID.y * gl_NumWorkGroups.x * gl_WorkGroupSize.x + gl_GlobalInvocationID.x; | |
if (nindex >= counts[0] || nindex >= inputNodes.length()) | |
return; | |
const uint16_t nidx = inputNodes[nindex]; | |
const node n = nodes[nidx]; | |
DrawArraysIndirectCommand cmd; | |
cmd.count = n.numVoxels; | |
cmd.instanceCount = 1u; | |
cmd.first = n.firstVoxel; | |
cmd.baseInstance = 0u; | |
drawCommands[atomicCounterIncrement(counter)] = cmd; | |
} | |
void main(void) { | |
switch (mode) { | |
case MODE_CULL: | |
cull(); | |
break; | |
case MODE_NODES_TO_DRAWCALLS: | |
producedraws(); | |
break; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment