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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
#[vertex]
#version 450
#VERSION_DEFINES
#define MAX_CASCADES 8
layout(push_constant, binding = 0, std430) uniform Params {
mat4 projection;
uint band_power;
uint sections_in_band;
uint band_mask;
float section_arc;
vec3 grid_size;
uint cascade;
uint pad;
float y_mult;
uint probe_debug_index;
int probe_axis_size;
}
params;
// http://in4k.untergrund.net/html_articles/hugi_27_-_coding_corner_polaris_sphere_tessellation_101.htm
vec3 get_sphere_vertex(uint p_vertex_id) {
float x_angle = float(p_vertex_id & 1u) + (p_vertex_id >> params.band_power);
float y_angle =
float((p_vertex_id & params.band_mask) >> 1) + ((p_vertex_id >> params.band_power) * params.sections_in_band);
x_angle *= params.section_arc * 0.5f; // remember - 180AA x rot not 360
y_angle *= -params.section_arc;
vec3 point = vec3(sin(x_angle) * sin(y_angle), cos(x_angle), sin(x_angle) * cos(y_angle));
return point;
}
#ifdef MODE_PROBES
layout(location = 0) out vec3 normal_interp;
layout(location = 1) out flat uint probe_index;
#endif
#ifdef MODE_VISIBILITY
layout(location = 0) out float visibility;
#endif
struct CascadeData {
vec3 offset; //offset of (0,0,0) in world coordinates
float to_cell; // 1/bounds * grid_size
ivec3 probe_world_offset;
uint pad;
};
layout(set = 0, binding = 1, std140) uniform Cascades {
CascadeData data[MAX_CASCADES];
}
cascades;
layout(set = 0, binding = 4) uniform texture3D occlusion_texture;
layout(set = 0, binding = 3) uniform sampler linear_sampler;
void main() {
#ifdef MODE_PROBES
probe_index = gl_InstanceIndex;
normal_interp = get_sphere_vertex(gl_VertexIndex);
vec3 vertex = normal_interp * 0.2;
float probe_cell_size = float(params.grid_size / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell;
ivec3 probe_cell;
probe_cell.x = int(probe_index % params.probe_axis_size);
probe_cell.y = int(probe_index / (params.probe_axis_size * params.probe_axis_size));
probe_cell.z = int((probe_index / params.probe_axis_size) % params.probe_axis_size);
vertex += (cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size) / vec3(1.0, params.y_mult, 1.0);
gl_Position = params.projection * vec4(vertex, 1.0);
#endif
#ifdef MODE_VISIBILITY
int probe_index = int(params.probe_debug_index);
vec3 vertex = get_sphere_vertex(gl_VertexIndex) * 0.01;
float probe_cell_size = float(params.grid_size / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell;
ivec3 probe_cell;
probe_cell.x = int(probe_index % params.probe_axis_size);
probe_cell.y = int((probe_index % (params.probe_axis_size * params.probe_axis_size)) / params.probe_axis_size);
probe_cell.z = int(probe_index / (params.probe_axis_size * params.probe_axis_size));
vertex += (cascades.data[params.cascade].offset + vec3(probe_cell) * probe_cell_size) / vec3(1.0, params.y_mult, 1.0);
int probe_voxels = int(params.grid_size.x) / int(params.probe_axis_size - 1);
int occluder_index = int(gl_InstanceIndex);
int diameter = probe_voxels * 2;
ivec3 occluder_pos;
occluder_pos.x = int(occluder_index % diameter);
occluder_pos.y = int(occluder_index / (diameter * diameter));
occluder_pos.z = int((occluder_index / diameter) % diameter);
float cell_size = 1.0 / cascades.data[params.cascade].to_cell;
ivec3 occluder_offset = occluder_pos - ivec3(diameter / 2);
vertex += ((vec3(occluder_offset) + vec3(0.5)) * cell_size) / vec3(1.0, params.y_mult, 1.0);
ivec3 global_cell = probe_cell + cascades.data[params.cascade].probe_world_offset;
uint occlusion_layer = 0;
if ((global_cell.x & 1) != 0) {
occlusion_layer |= 1;
}
if ((global_cell.y & 1) != 0) {
occlusion_layer |= 2;
}
if ((global_cell.z & 1) != 0) {
occlusion_layer |= 4;
}
ivec3 tex_pos = probe_cell * probe_voxels + occluder_offset;
const vec4 layer_axis[4] = vec4[](
vec4(1, 0, 0, 0),
vec4(0, 1, 0, 0),
vec4(0, 0, 1, 0),
vec4(0, 0, 0, 1));
tex_pos.z += int(params.cascade) * int(params.grid_size);
if (occlusion_layer >= 4) {
tex_pos.x += int(params.grid_size.x);
occlusion_layer &= 3;
}
visibility = dot(texelFetch(sampler3D(occlusion_texture, linear_sampler), tex_pos, 0), layer_axis[occlusion_layer]);
gl_Position = params.projection * vec4(vertex, 1.0);
#endif
}
#[fragment]
#version 450
#VERSION_DEFINES
layout(location = 0) out vec4 frag_color;
layout(set = 0, binding = 2) uniform texture2DArray lightprobe_texture;
layout(set = 0, binding = 3) uniform sampler linear_sampler;
layout(push_constant, binding = 0, std430) uniform Params {
mat4 projection;
uint band_power;
uint sections_in_band;
uint band_mask;
float section_arc;
vec3 grid_size;
uint cascade;
uint pad;
float y_mult;
uint probe_debug_index;
int probe_axis_size;
}
params;
#ifdef MODE_PROBES
layout(location = 0) in vec3 normal_interp;
layout(location = 1) in flat uint probe_index;
#endif
#ifdef MODE_VISIBILITY
layout(location = 0) in float visibility;
#endif
vec2 octahedron_wrap(vec2 v) {
vec2 signVal;
signVal.x = v.x >= 0.0 ? 1.0 : -1.0;
signVal.y = v.y >= 0.0 ? 1.0 : -1.0;
return (1.0 - abs(v.yx)) * signVal;
}
vec2 octahedron_encode(vec3 n) {
// https://twitter.com/Stubbesaurus/status/937994790553227264
n /= (abs(n.x) + abs(n.y) + abs(n.z));
n.xy = n.z >= 0.0 ? n.xy : octahedron_wrap(n.xy);
n.xy = n.xy * 0.5 + 0.5;
return n.xy;
}
void main() {
#ifdef MODE_PROBES
ivec3 tex_pos;
tex_pos.x = int(probe_index) % params.probe_axis_size; //x
tex_pos.y = int(probe_index) / (params.probe_axis_size * params.probe_axis_size);
tex_pos.x += params.probe_axis_size * ((int(probe_index) / params.probe_axis_size) % params.probe_axis_size); //z
tex_pos.z = int(params.cascade);
vec3 tex_pos_ofs = vec3(octahedron_encode(normal_interp) * float(OCT_SIZE), 0.0);
vec3 tex_posf = vec3(vec2(tex_pos.xy * (OCT_SIZE + 2) + ivec2(1)), float(tex_pos.z)) + tex_pos_ofs;
tex_posf.xy /= vec2(ivec2(params.probe_axis_size * params.probe_axis_size * (OCT_SIZE + 2), params.probe_axis_size * (OCT_SIZE + 2)));
vec4 indirect_light = textureLod(sampler2DArray(lightprobe_texture, linear_sampler), tex_posf, 0.0);
frag_color = indirect_light;
#endif
#ifdef MODE_VISIBILITY
frag_color = vec4(vec3(1, visibility, visibility), 1.0);
#endif
}
|