-
Notifications
You must be signed in to change notification settings - Fork 131
/
cull_blocks.comp
112 lines (95 loc) · 3.21 KB
/
cull_blocks.comp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#version 450
layout(local_size_x = 8, local_size_y = 8) in;
#include "ocean.inc"
layout(std140, set = 1, binding = 0) uniform Registers
{
vec3 world_offset;
ivec2 image_offset;
uvec2 num_threads;
vec2 inv_num_threads;
vec2 grid_base;
vec2 grid_size;
vec2 grid_resolution;
vec2 heightmap_range;
float guard_band;
uint lod_stride;
float max_lod;
int handle_edge_lods;
} registers;
layout(std140, set = 1, binding = 1) uniform Frustum
{
vec4 frustum[6];
};
layout(std430, set = 0, binding = 0) writeonly buffer LODOutput
{
PatchData patches[];
};
layout(std430, set = 0, binding = 1) buffer LODCounters
{
IndirectDraw draws[];
};
layout(set = 0, binding = 2) uniform sampler2D uLODs;
int compute_lod(vec4 lods, float inner_lod)
{
vec2 xy = min(lods.xy, lods.zw);
return int(min(inner_lod, min(xy.x, xy.y)));
}
bool is_inside_plane(vec3 lo, vec3 hi)
{
bool ret = true;
for (int i = 0; i < 6; i++)
{
vec4 p = frustum[i];
bvec3 high_mask = greaterThan(p.xyz, vec3(0.0));
vec3 max_coord = mix(lo, hi, high_mask);
if (dot(vec4(max_coord, 1.0), p) < 0.0)
{
ret = false;
break;
}
}
return ret;
}
bool frustum_cull()
{
vec2 min_xz = registers.grid_base + vec2(gl_GlobalInvocationID.xy) * registers.grid_size;
vec2 max_xz = min_xz + registers.grid_size;
vec3 lo = vec3(min_xz.x - registers.guard_band, registers.heightmap_range.x, min_xz.y - registers.guard_band);
vec3 hi = vec3(max_xz.x + registers.guard_band, registers.heightmap_range.y, max_xz.y + registers.guard_band);
lo += registers.world_offset;
hi += registers.world_offset;
return is_inside_plane(lo, hi);
}
void main()
{
if (all(lessThan(gl_GlobalInvocationID.xy, registers.num_threads)))
{
if (frustum_cull())
{
ivec2 coord = ivec2(gl_GlobalInvocationID.xy) + registers.image_offset;
vec2 uv = (vec2(coord) + 0.5) * registers.inv_num_threads;
float lod_center = textureLod(uLODs, uv, 0.0).x;
vec4 lods = vec4(
textureLodOffset(uLODs, uv, 0.0, ivec2(-1, 0)).x,
textureLodOffset(uLODs, uv, 0.0, ivec2(+1, 0)).x,
textureLodOffset(uLODs, uv, 0.0, ivec2(0, -1)).x,
textureLodOffset(uLODs, uv, 0.0, ivec2(0, +1)).x);
lods = max(lods, vec4(lod_center));
// If we need to render border mesh, need to ensure we get a fixed LOD when rendering that edge.
if (registers.handle_edge_lods != 0)
{
lods = mix(lods, vec4(registers.max_lod),
equal(gl_GlobalInvocationID.xxyy,
uvec4(0u, registers.num_threads.x - 1u,
0u, registers.num_threads.y - 1u)));
}
float inner_lod = lod_center;
int lod = compute_lod(lods, lod_center);
uint offset = atomicAdd(draws[lod].instance_count, 1u);
offset += registers.lod_stride * lod;
vec2 offsets = vec2(coord) * registers.grid_resolution;
PatchData block = PatchData(offsets, inner_lod, 0.0, lods);
patches[offset] = block;
}
}
}