1 | /**************************************************************************/ |
2 | /* voxelizer.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "voxelizer.h" |
32 | |
33 | #include "core/config/project_settings.h" |
34 | |
35 | static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) { |
36 | if (p_pos.is_equal_approx(p_vtx[0])) { |
37 | r_uv = p_uv[0]; |
38 | r_normal = p_normal[0]; |
39 | return; |
40 | } |
41 | if (p_pos.is_equal_approx(p_vtx[1])) { |
42 | r_uv = p_uv[1]; |
43 | r_normal = p_normal[1]; |
44 | return; |
45 | } |
46 | if (p_pos.is_equal_approx(p_vtx[2])) { |
47 | r_uv = p_uv[2]; |
48 | r_normal = p_normal[2]; |
49 | return; |
50 | } |
51 | |
52 | Vector3 v0 = p_vtx[1] - p_vtx[0]; |
53 | Vector3 v1 = p_vtx[2] - p_vtx[0]; |
54 | Vector3 v2 = p_pos - p_vtx[0]; |
55 | |
56 | real_t d00 = v0.dot(v0); |
57 | real_t d01 = v0.dot(v1); |
58 | real_t d11 = v1.dot(v1); |
59 | real_t d20 = v2.dot(v0); |
60 | real_t d21 = v2.dot(v1); |
61 | real_t denom = (d00 * d11 - d01 * d01); |
62 | if (denom == 0) { |
63 | r_uv = p_uv[0]; |
64 | r_normal = p_normal[0]; |
65 | return; |
66 | } |
67 | real_t v = (d11 * d20 - d01 * d21) / denom; |
68 | real_t w = (d00 * d21 - d01 * d20) / denom; |
69 | real_t u = 1.0f - v - w; |
70 | |
71 | r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; |
72 | r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized(); |
73 | } |
74 | |
75 | void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { |
76 | if (p_level == cell_subdiv) { |
77 | //plot the face by guessing its albedo and emission value |
78 | |
79 | //find best axis to map to, for scanning values |
80 | int closest_axis = 0; |
81 | real_t closest_dot = 0; |
82 | |
83 | Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]); |
84 | Vector3 normal = plane.normal; |
85 | |
86 | for (int i = 0; i < 3; i++) { |
87 | Vector3 axis; |
88 | axis[i] = 1.0; |
89 | real_t dot = ABS(normal.dot(axis)); |
90 | if (i == 0 || dot > closest_dot) { |
91 | closest_axis = i; |
92 | closest_dot = dot; |
93 | } |
94 | } |
95 | |
96 | Vector3 axis; |
97 | axis[closest_axis] = 1.0; |
98 | Vector3 t1; |
99 | t1[(closest_axis + 1) % 3] = 1.0; |
100 | Vector3 t2; |
101 | t2[(closest_axis + 2) % 3] = 1.0; |
102 | |
103 | t1 *= p_aabb.size[(closest_axis + 1) % 3] / real_t(color_scan_cell_width); |
104 | t2 *= p_aabb.size[(closest_axis + 2) % 3] / real_t(color_scan_cell_width); |
105 | |
106 | Color albedo_accum; |
107 | Color emission_accum; |
108 | Vector3 normal_accum; |
109 | |
110 | float alpha = 0.0; |
111 | |
112 | //map to a grid average in the best axis for this face |
113 | for (int i = 0; i < color_scan_cell_width; i++) { |
114 | Vector3 ofs_i = real_t(i) * t1; |
115 | |
116 | for (int j = 0; j < color_scan_cell_width; j++) { |
117 | Vector3 ofs_j = real_t(j) * t2; |
118 | |
119 | Vector3 from = p_aabb.position + ofs_i + ofs_j; |
120 | Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis]; |
121 | Vector3 half = (to - from) * 0.5; |
122 | |
123 | //is in this cell? |
124 | if (!Geometry3D::triangle_box_overlap(from + half, half, p_vtx)) { |
125 | continue; //face does not span this cell |
126 | } |
127 | |
128 | //go from -size to +size*2 to avoid skipping collisions |
129 | Vector3 ray_from = from + (t1 + t2) * 0.5 - axis * p_aabb.size[closest_axis]; |
130 | Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis] * 2; |
131 | |
132 | if (normal.dot(ray_from - ray_to) < 0) { |
133 | SWAP(ray_from, ray_to); |
134 | } |
135 | |
136 | Vector3 intersection; |
137 | |
138 | if (!plane.intersects_segment(ray_from, ray_to, &intersection)) { |
139 | if (ABS(plane.distance_to(ray_from)) < ABS(plane.distance_to(ray_to))) { |
140 | intersection = plane.project(ray_from); |
141 | } else { |
142 | intersection = plane.project(ray_to); |
143 | } |
144 | } |
145 | |
146 | intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection); |
147 | |
148 | Vector2 uv; |
149 | Vector3 lnormal; |
150 | get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal); |
151 | if (lnormal == Vector3()) { //just in case normal is not provided |
152 | lnormal = normal; |
153 | } |
154 | |
155 | int uv_x = CLAMP(int(Math::fposmod(uv.x, (real_t)1.0) * bake_texture_size), 0, bake_texture_size - 1); |
156 | int uv_y = CLAMP(int(Math::fposmod(uv.y, (real_t)1.0) * bake_texture_size), 0, bake_texture_size - 1); |
157 | |
158 | int ofs = uv_y * bake_texture_size + uv_x; |
159 | albedo_accum.r += p_material.albedo[ofs].r; |
160 | albedo_accum.g += p_material.albedo[ofs].g; |
161 | albedo_accum.b += p_material.albedo[ofs].b; |
162 | albedo_accum.a += p_material.albedo[ofs].a; |
163 | |
164 | emission_accum.r += p_material.emission[ofs].r; |
165 | emission_accum.g += p_material.emission[ofs].g; |
166 | emission_accum.b += p_material.emission[ofs].b; |
167 | |
168 | normal_accum += lnormal; |
169 | |
170 | alpha += 1.0; |
171 | } |
172 | } |
173 | |
174 | if (alpha == 0) { |
175 | //could not in any way get texture information.. so use closest point to center |
176 | |
177 | Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]); |
178 | Vector3 inters = f.get_closest_point_to(p_aabb.get_center()); |
179 | |
180 | Vector3 lnormal; |
181 | Vector2 uv; |
182 | get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal); |
183 | if (lnormal == Vector3()) { //just in case normal is not provided |
184 | lnormal = normal; |
185 | } |
186 | |
187 | int uv_x = CLAMP(Math::fposmod(uv.x, (real_t)1.0) * bake_texture_size, 0, bake_texture_size - 1); |
188 | int uv_y = CLAMP(Math::fposmod(uv.y, (real_t)1.0) * bake_texture_size, 0, bake_texture_size - 1); |
189 | |
190 | int ofs = uv_y * bake_texture_size + uv_x; |
191 | |
192 | alpha = 1.0 / (color_scan_cell_width * color_scan_cell_width); |
193 | |
194 | albedo_accum.r = p_material.albedo[ofs].r * alpha; |
195 | albedo_accum.g = p_material.albedo[ofs].g * alpha; |
196 | albedo_accum.b = p_material.albedo[ofs].b * alpha; |
197 | albedo_accum.a = p_material.albedo[ofs].a * alpha; |
198 | |
199 | emission_accum.r = p_material.emission[ofs].r * alpha; |
200 | emission_accum.g = p_material.emission[ofs].g * alpha; |
201 | emission_accum.b = p_material.emission[ofs].b * alpha; |
202 | |
203 | normal_accum = lnormal * alpha; |
204 | |
205 | } else { |
206 | float accdiv = 1.0 / (color_scan_cell_width * color_scan_cell_width); |
207 | alpha *= accdiv; |
208 | |
209 | albedo_accum.r *= accdiv; |
210 | albedo_accum.g *= accdiv; |
211 | albedo_accum.b *= accdiv; |
212 | albedo_accum.a *= accdiv; |
213 | |
214 | emission_accum.r *= accdiv; |
215 | emission_accum.g *= accdiv; |
216 | emission_accum.b *= accdiv; |
217 | |
218 | normal_accum *= accdiv; |
219 | } |
220 | |
221 | //put this temporarily here, corrected in a later step |
222 | bake_cells.write[p_idx].albedo[0] += albedo_accum.r; |
223 | bake_cells.write[p_idx].albedo[1] += albedo_accum.g; |
224 | bake_cells.write[p_idx].albedo[2] += albedo_accum.b; |
225 | bake_cells.write[p_idx].emission[0] += emission_accum.r; |
226 | bake_cells.write[p_idx].emission[1] += emission_accum.g; |
227 | bake_cells.write[p_idx].emission[2] += emission_accum.b; |
228 | bake_cells.write[p_idx].normal[0] += normal_accum.x; |
229 | bake_cells.write[p_idx].normal[1] += normal_accum.y; |
230 | bake_cells.write[p_idx].normal[2] += normal_accum.z; |
231 | bake_cells.write[p_idx].alpha += alpha; |
232 | |
233 | } else { |
234 | //go down |
235 | |
236 | int half = (1 << cell_subdiv) >> (p_level + 1); |
237 | for (int i = 0; i < 8; i++) { |
238 | AABB aabb = p_aabb; |
239 | aabb.size *= 0.5; |
240 | |
241 | int nx = p_x; |
242 | int ny = p_y; |
243 | int nz = p_z; |
244 | |
245 | if (i & 1) { |
246 | aabb.position.x += aabb.size.x; |
247 | nx += half; |
248 | } |
249 | if (i & 2) { |
250 | aabb.position.y += aabb.size.y; |
251 | ny += half; |
252 | } |
253 | if (i & 4) { |
254 | aabb.position.z += aabb.size.z; |
255 | nz += half; |
256 | } |
257 | //make sure to not plot beyond limits |
258 | if (nx < 0 || nx >= axis_cell_size[0] || ny < 0 || ny >= axis_cell_size[1] || nz < 0 || nz >= axis_cell_size[2]) { |
259 | continue; |
260 | } |
261 | |
262 | { |
263 | AABB test_aabb = aabb; |
264 | //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time |
265 | Vector3 qsize = test_aabb.size * 0.5; //quarter size, for fast aabb test |
266 | |
267 | if (!Geometry3D::triangle_box_overlap(test_aabb.position + qsize, qsize, p_vtx)) { |
268 | //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) { |
269 | //does not fit in child, go on |
270 | continue; |
271 | } |
272 | } |
273 | |
274 | if (bake_cells[p_idx].children[i] == CHILD_EMPTY) { |
275 | //sub cell must be created |
276 | |
277 | uint32_t child_idx = bake_cells.size(); |
278 | bake_cells.write[p_idx].children[i] = child_idx; |
279 | bake_cells.resize(bake_cells.size() + 1); |
280 | bake_cells.write[child_idx].level = p_level + 1; |
281 | bake_cells.write[child_idx].x = nx / half; |
282 | bake_cells.write[child_idx].y = ny / half; |
283 | bake_cells.write[child_idx].z = nz / half; |
284 | } |
285 | |
286 | _plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); |
287 | } |
288 | } |
289 | } |
290 | |
291 | Vector<Color> Voxelizer::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) { |
292 | Vector<Color> ret; |
293 | |
294 | if (p_image.is_null() || p_image->is_empty()) { |
295 | ret.resize(bake_texture_size * bake_texture_size); |
296 | for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { |
297 | ret.write[i] = p_color_add; |
298 | } |
299 | |
300 | return ret; |
301 | } |
302 | p_image = p_image->duplicate(); |
303 | |
304 | if (p_image->is_compressed()) { |
305 | p_image->decompress(); |
306 | } |
307 | p_image->convert(Image::FORMAT_RGBA8); |
308 | p_image->resize(bake_texture_size, bake_texture_size, Image::INTERPOLATE_CUBIC); |
309 | |
310 | const uint8_t *r = p_image->get_data().ptr(); |
311 | ret.resize(bake_texture_size * bake_texture_size); |
312 | |
313 | for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { |
314 | Color c; |
315 | c.r = (r[i * 4 + 0] / 255.0) * p_color_mul.r + p_color_add.r; |
316 | c.g = (r[i * 4 + 1] / 255.0) * p_color_mul.g + p_color_add.g; |
317 | c.b = (r[i * 4 + 2] / 255.0) * p_color_mul.b + p_color_add.b; |
318 | |
319 | c.a = r[i * 4 + 3] / 255.0; |
320 | |
321 | ret.write[i] = c; |
322 | } |
323 | |
324 | return ret; |
325 | } |
326 | |
327 | Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material) { |
328 | // This way of obtaining materials is inaccurate and also does not support some compressed formats very well. |
329 | Ref<BaseMaterial3D> mat = p_material; |
330 | |
331 | Ref<Material> material = mat; //hack for now |
332 | |
333 | if (material_cache.has(material)) { |
334 | return material_cache[material]; |
335 | } |
336 | |
337 | MaterialCache mc; |
338 | |
339 | if (mat.is_valid()) { |
340 | Ref<Texture2D> albedo_tex = mat->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); |
341 | |
342 | Ref<Image> img_albedo; |
343 | if (albedo_tex.is_valid()) { |
344 | img_albedo = albedo_tex->get_image(); |
345 | mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative |
346 | } else { |
347 | mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive |
348 | } |
349 | if (mat->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { |
350 | Ref<Texture2D> emission_tex = mat->get_texture(BaseMaterial3D::TEXTURE_EMISSION); |
351 | |
352 | Color emission_col = mat->get_emission(); |
353 | float emission_energy = mat->get_emission_energy_multiplier() * exposure_normalization; |
354 | if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units" )) { |
355 | emission_energy *= mat->get_emission_intensity(); |
356 | } |
357 | |
358 | Ref<Image> img_emission; |
359 | |
360 | if (emission_tex.is_valid()) { |
361 | img_emission = emission_tex->get_image(); |
362 | } |
363 | |
364 | if (mat->get_emission_operator() == BaseMaterial3D::EMISSION_OP_ADD) { |
365 | mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy); |
366 | } else { |
367 | mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0)); |
368 | } |
369 | } else { |
370 | Ref<Image> empty; |
371 | mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0)); |
372 | } |
373 | |
374 | } else { |
375 | Ref<Image> empty; |
376 | |
377 | mc.albedo = _get_bake_texture(empty, Color(0, 0, 0), Color(1, 1, 1)); |
378 | mc.emission = _get_bake_texture(empty, Color(0, 0, 0), Color(0, 0, 0)); |
379 | } |
380 | |
381 | material_cache[p_material] = mc; |
382 | return mc; |
383 | } |
384 | |
385 | void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) { |
386 | for (int i = 0; i < p_mesh->get_surface_count(); i++) { |
387 | if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { |
388 | continue; //only triangles |
389 | } |
390 | |
391 | Ref<Material> src_material; |
392 | |
393 | if (p_override_material.is_valid()) { |
394 | src_material = p_override_material; |
395 | } else if (i < p_materials.size() && p_materials[i].is_valid()) { |
396 | src_material = p_materials[i]; |
397 | } else { |
398 | src_material = p_mesh->surface_get_material(i); |
399 | } |
400 | MaterialCache material = _get_material_cache(src_material); |
401 | |
402 | Array a = p_mesh->surface_get_arrays(i); |
403 | |
404 | Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX]; |
405 | const Vector3 *vr = vertices.ptr(); |
406 | Vector<Vector2> uv = a[Mesh::ARRAY_TEX_UV]; |
407 | const Vector2 *uvr = nullptr; |
408 | Vector<Vector3> normals = a[Mesh::ARRAY_NORMAL]; |
409 | const Vector3 *nr = nullptr; |
410 | Vector<int> index = a[Mesh::ARRAY_INDEX]; |
411 | |
412 | if (uv.size()) { |
413 | uvr = uv.ptr(); |
414 | } |
415 | |
416 | if (normals.size()) { |
417 | nr = normals.ptr(); |
418 | } |
419 | |
420 | if (index.size()) { |
421 | int facecount = index.size() / 3; |
422 | const int *ir = index.ptr(); |
423 | |
424 | for (int j = 0; j < facecount; j++) { |
425 | Vector3 vtxs[3]; |
426 | Vector2 uvs[3]; |
427 | Vector3 normal[3]; |
428 | |
429 | for (int k = 0; k < 3; k++) { |
430 | vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); |
431 | } |
432 | |
433 | if (uvr) { |
434 | for (int k = 0; k < 3; k++) { |
435 | uvs[k] = uvr[ir[j * 3 + k]]; |
436 | } |
437 | } |
438 | |
439 | if (nr) { |
440 | for (int k = 0; k < 3; k++) { |
441 | normal[k] = nr[ir[j * 3 + k]]; |
442 | } |
443 | } |
444 | |
445 | //test against original bounds |
446 | if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) { |
447 | continue; |
448 | } |
449 | //plot |
450 | _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); |
451 | } |
452 | |
453 | } else { |
454 | int facecount = vertices.size() / 3; |
455 | |
456 | for (int j = 0; j < facecount; j++) { |
457 | Vector3 vtxs[3]; |
458 | Vector2 uvs[3]; |
459 | Vector3 normal[3]; |
460 | |
461 | for (int k = 0; k < 3; k++) { |
462 | vtxs[k] = p_xform.xform(vr[j * 3 + k]); |
463 | } |
464 | |
465 | if (uvr) { |
466 | for (int k = 0; k < 3; k++) { |
467 | uvs[k] = uvr[j * 3 + k]; |
468 | } |
469 | } |
470 | |
471 | if (nr) { |
472 | for (int k = 0; k < 3; k++) { |
473 | normal[k] = nr[j * 3 + k]; |
474 | } |
475 | } |
476 | |
477 | //test against original bounds |
478 | if (!Geometry3D::triangle_box_overlap(original_bounds.get_center(), original_bounds.size * 0.5, vtxs)) { |
479 | continue; |
480 | } |
481 | //plot face |
482 | _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); |
483 | } |
484 | } |
485 | } |
486 | |
487 | max_original_cells = bake_cells.size(); |
488 | } |
489 | |
490 | void Voxelizer::_sort() { |
491 | // cells need to be sorted by level and coordinates |
492 | // it is important that level has more priority (for compute), and that Z has the least, |
493 | // given it may aid older implementations plot using GPU |
494 | |
495 | Vector<CellSort> sorted_cells; |
496 | uint32_t cell_count = bake_cells.size(); |
497 | sorted_cells.resize(cell_count); |
498 | { |
499 | CellSort *sort_cellsp = sorted_cells.ptrw(); |
500 | const Cell *bake_cellsp = bake_cells.ptr(); |
501 | |
502 | for (uint32_t i = 0; i < cell_count; i++) { |
503 | sort_cellsp[i].x = bake_cellsp[i].x; |
504 | sort_cellsp[i].y = bake_cellsp[i].y; |
505 | sort_cellsp[i].z = bake_cellsp[i].z; |
506 | sort_cellsp[i].level = bake_cellsp[i].level; |
507 | sort_cellsp[i].index = i; |
508 | } |
509 | } |
510 | |
511 | sorted_cells.sort(); |
512 | |
513 | //verify just in case, index 0 must be level 0 |
514 | ERR_FAIL_COND(sorted_cells[0].level != 0); |
515 | |
516 | Vector<Cell> new_bake_cells; |
517 | new_bake_cells.resize(cell_count); |
518 | Vector<uint32_t> reverse_map; |
519 | |
520 | { |
521 | reverse_map.resize(cell_count); |
522 | const CellSort *sort_cellsp = sorted_cells.ptr(); |
523 | uint32_t *reverse_mapp = reverse_map.ptrw(); |
524 | |
525 | for (uint32_t i = 0; i < cell_count; i++) { |
526 | reverse_mapp[sort_cellsp[i].index] = i; |
527 | } |
528 | } |
529 | |
530 | { |
531 | const CellSort *sort_cellsp = sorted_cells.ptr(); |
532 | const Cell *bake_cellsp = bake_cells.ptr(); |
533 | const uint32_t *reverse_mapp = reverse_map.ptr(); |
534 | Cell *new_bake_cellsp = new_bake_cells.ptrw(); |
535 | |
536 | for (uint32_t i = 0; i < cell_count; i++) { |
537 | //copy to new cell |
538 | new_bake_cellsp[i] = bake_cellsp[sort_cellsp[i].index]; |
539 | //remap children |
540 | for (uint32_t j = 0; j < 8; j++) { |
541 | if (new_bake_cellsp[i].children[j] != CHILD_EMPTY) { |
542 | new_bake_cellsp[i].children[j] = reverse_mapp[new_bake_cellsp[i].children[j]]; |
543 | } |
544 | } |
545 | } |
546 | } |
547 | |
548 | bake_cells = new_bake_cells; |
549 | sorted = true; |
550 | } |
551 | |
552 | void Voxelizer::_fixup_plot(int p_idx, int p_level) { |
553 | if (p_level == cell_subdiv) { |
554 | leaf_voxel_count++; |
555 | float alpha = bake_cells[p_idx].alpha; |
556 | |
557 | bake_cells.write[p_idx].albedo[0] /= alpha; |
558 | bake_cells.write[p_idx].albedo[1] /= alpha; |
559 | bake_cells.write[p_idx].albedo[2] /= alpha; |
560 | |
561 | //transfer emission to light |
562 | bake_cells.write[p_idx].emission[0] /= alpha; |
563 | bake_cells.write[p_idx].emission[1] /= alpha; |
564 | bake_cells.write[p_idx].emission[2] /= alpha; |
565 | |
566 | bake_cells.write[p_idx].normal[0] /= alpha; |
567 | bake_cells.write[p_idx].normal[1] /= alpha; |
568 | bake_cells.write[p_idx].normal[2] /= alpha; |
569 | |
570 | Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]); |
571 | if (n.length() < 0.01) { |
572 | //too much fight over normal, zero it |
573 | bake_cells.write[p_idx].normal[0] = 0; |
574 | bake_cells.write[p_idx].normal[1] = 0; |
575 | bake_cells.write[p_idx].normal[2] = 0; |
576 | } else { |
577 | n.normalize(); |
578 | bake_cells.write[p_idx].normal[0] = n.x; |
579 | bake_cells.write[p_idx].normal[1] = n.y; |
580 | bake_cells.write[p_idx].normal[2] = n.z; |
581 | } |
582 | |
583 | bake_cells.write[p_idx].alpha = 1.0; |
584 | |
585 | /*if (bake_light.size()) { |
586 | for(int i=0;i<6;i++) { |
587 | } |
588 | }*/ |
589 | |
590 | } else { |
591 | //go down |
592 | |
593 | bake_cells.write[p_idx].emission[0] = 0; |
594 | bake_cells.write[p_idx].emission[1] = 0; |
595 | bake_cells.write[p_idx].emission[2] = 0; |
596 | bake_cells.write[p_idx].normal[0] = 0; |
597 | bake_cells.write[p_idx].normal[1] = 0; |
598 | bake_cells.write[p_idx].normal[2] = 0; |
599 | bake_cells.write[p_idx].albedo[0] = 0; |
600 | bake_cells.write[p_idx].albedo[1] = 0; |
601 | bake_cells.write[p_idx].albedo[2] = 0; |
602 | |
603 | float alpha_average = 0; |
604 | |
605 | for (int i = 0; i < 8; i++) { |
606 | uint32_t child = bake_cells[p_idx].children[i]; |
607 | |
608 | if (child == CHILD_EMPTY) { |
609 | continue; |
610 | } |
611 | |
612 | _fixup_plot(child, p_level + 1); |
613 | alpha_average += bake_cells[child].alpha; |
614 | } |
615 | |
616 | bake_cells.write[p_idx].alpha = alpha_average / 8.0; |
617 | } |
618 | } |
619 | |
620 | void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization) { |
621 | sorted = false; |
622 | original_bounds = p_bounds; |
623 | cell_subdiv = p_subdiv; |
624 | exposure_normalization = p_exposure_normalization; |
625 | bake_cells.resize(1); |
626 | material_cache.clear(); |
627 | |
628 | //find out the actual real bounds, power of 2, which gets the highest subdivision |
629 | po2_bounds = p_bounds; |
630 | int longest_axis = po2_bounds.get_longest_axis_index(); |
631 | axis_cell_size[longest_axis] = 1 << cell_subdiv; |
632 | leaf_voxel_count = 0; |
633 | |
634 | for (int i = 0; i < 3; i++) { |
635 | if (i == longest_axis) { |
636 | continue; |
637 | } |
638 | |
639 | axis_cell_size[i] = axis_cell_size[longest_axis]; |
640 | real_t axis_size = po2_bounds.size[longest_axis]; |
641 | |
642 | //shrink until fit subdiv |
643 | while (axis_size / 2.0 >= po2_bounds.size[i]) { |
644 | axis_size /= 2.0; |
645 | axis_cell_size[i] >>= 1; |
646 | } |
647 | |
648 | po2_bounds.size[i] = po2_bounds.size[longest_axis]; |
649 | } |
650 | |
651 | Transform3D to_bounds; |
652 | to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis])); |
653 | to_bounds.origin = po2_bounds.position; |
654 | |
655 | Transform3D to_grid; |
656 | to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis])); |
657 | |
658 | to_cell_space = to_grid * to_bounds.affine_inverse(); |
659 | |
660 | cell_size = po2_bounds.size[longest_axis] / axis_cell_size[longest_axis]; |
661 | } |
662 | |
663 | void Voxelizer::end_bake() { |
664 | if (!sorted) { |
665 | _sort(); |
666 | } |
667 | _fixup_plot(0, 0); |
668 | } |
669 | |
670 | //create the data for rendering server |
671 | |
672 | int Voxelizer::get_voxel_gi_octree_depth() const { |
673 | return cell_subdiv; |
674 | } |
675 | |
676 | Vector3i Voxelizer::get_voxel_gi_octree_size() const { |
677 | return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]); |
678 | } |
679 | |
680 | int Voxelizer::get_voxel_gi_cell_count() const { |
681 | return bake_cells.size(); |
682 | } |
683 | |
684 | Vector<uint8_t> Voxelizer::get_voxel_gi_octree_cells() const { |
685 | Vector<uint8_t> data; |
686 | data.resize((8 * 4) * bake_cells.size()); //8 uint32t values |
687 | { |
688 | uint8_t *w = data.ptrw(); |
689 | uint32_t *children_cells = (uint32_t *)w; |
690 | const Cell *cells = bake_cells.ptr(); |
691 | |
692 | uint32_t cell_count = bake_cells.size(); |
693 | |
694 | for (uint32_t i = 0; i < cell_count; i++) { |
695 | for (uint32_t j = 0; j < 8; j++) { |
696 | children_cells[i * 8 + j] = cells[i].children[j]; |
697 | } |
698 | } |
699 | } |
700 | |
701 | return data; |
702 | } |
703 | |
704 | Vector<uint8_t> Voxelizer::get_voxel_gi_data_cells() const { |
705 | Vector<uint8_t> data; |
706 | data.resize((4 * 4) * bake_cells.size()); //8 uint32t values |
707 | { |
708 | uint8_t *w = data.ptrw(); |
709 | uint32_t *dataptr = (uint32_t *)w; |
710 | const Cell *cells = bake_cells.ptr(); |
711 | |
712 | uint32_t cell_count = bake_cells.size(); |
713 | |
714 | for (uint32_t i = 0; i < cell_count; i++) { |
715 | { //position |
716 | |
717 | uint32_t x = cells[i].x; |
718 | uint32_t y = cells[i].y; |
719 | uint32_t z = cells[i].z; |
720 | |
721 | uint32_t position = x; |
722 | position |= y << 11; |
723 | position |= z << 21; |
724 | |
725 | dataptr[i * 4 + 0] = position; |
726 | } |
727 | |
728 | { //albedo + alpha |
729 | uint32_t rgba = uint32_t(CLAMP(cells[i].alpha * 255.0, 0, 255)) << 24; //a |
730 | rgba |= uint32_t(CLAMP(cells[i].albedo[2] * 255.0, 0, 255)) << 16; //b |
731 | rgba |= uint32_t(CLAMP(cells[i].albedo[1] * 255.0, 0, 255)) << 8; //g |
732 | rgba |= uint32_t(CLAMP(cells[i].albedo[0] * 255.0, 0, 255)); //r |
733 | |
734 | dataptr[i * 4 + 1] = rgba; |
735 | } |
736 | |
737 | { //emission, as rgbe9995 |
738 | Color emission = Color(cells[i].emission[0], cells[i].emission[1], cells[i].emission[2]); |
739 | dataptr[i * 4 + 2] = emission.to_rgbe9995(); |
740 | } |
741 | |
742 | { //normal |
743 | |
744 | Vector3 n(bake_cells[i].normal[0], bake_cells[i].normal[1], bake_cells[i].normal[2]); |
745 | n.normalize(); |
746 | |
747 | uint32_t normal = uint32_t(uint8_t(int8_t(CLAMP(n.x * 127.0, -128, 127)))); |
748 | normal |= uint32_t(uint8_t(int8_t(CLAMP(n.y * 127.0, -128, 127)))) << 8; |
749 | normal |= uint32_t(uint8_t(int8_t(CLAMP(n.z * 127.0, -128, 127)))) << 16; |
750 | |
751 | dataptr[i * 4 + 3] = normal; |
752 | } |
753 | } |
754 | } |
755 | |
756 | return data; |
757 | } |
758 | |
759 | Vector<int> Voxelizer::get_voxel_gi_level_cell_count() const { |
760 | uint32_t cell_count = bake_cells.size(); |
761 | const Cell *cells = bake_cells.ptr(); |
762 | Vector<int> level_count; |
763 | level_count.resize(cell_subdiv + 1); //remember, always x+1 levels for x subdivisions |
764 | { |
765 | int *w = level_count.ptrw(); |
766 | for (int i = 0; i < cell_subdiv + 1; i++) { |
767 | w[i] = 0; |
768 | } |
769 | |
770 | for (uint32_t i = 0; i < cell_count; i++) { |
771 | w[cells[i].level]++; |
772 | } |
773 | } |
774 | |
775 | return level_count; |
776 | } |
777 | |
778 | // euclidean distance computation based on: |
779 | // https://prideout.net/blog/distance_fields/ |
780 | |
781 | #define square(m_s) ((m_s) * (m_s)) |
782 | #define INF 1e20 |
783 | |
784 | /* dt of 1d function using squared distance */ |
785 | static void edt(float *f, int stride, int n) { |
786 | float *d = (float *)alloca(sizeof(float) * n + sizeof(int) * n + sizeof(float) * (n + 1)); |
787 | int *v = reinterpret_cast<int *>(&(d[n])); |
788 | float *z = reinterpret_cast<float *>(&v[n]); |
789 | |
790 | int k = 0; |
791 | v[0] = 0; |
792 | z[0] = -INF; |
793 | z[1] = +INF; |
794 | for (int q = 1; q <= n - 1; q++) { |
795 | float s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]); |
796 | while (s <= z[k]) { |
797 | k--; |
798 | s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]); |
799 | } |
800 | k++; |
801 | v[k] = q; |
802 | |
803 | z[k] = s; |
804 | z[k + 1] = +INF; |
805 | } |
806 | |
807 | k = 0; |
808 | for (int q = 0; q <= n - 1; q++) { |
809 | while (z[k + 1] < q) { |
810 | k++; |
811 | } |
812 | d[q] = square(q - v[k]) + f[v[k] * stride]; |
813 | } |
814 | |
815 | for (int i = 0; i < n; i++) { |
816 | f[i * stride] = d[i]; |
817 | } |
818 | } |
819 | |
820 | #undef square |
821 | |
822 | Vector<uint8_t> Voxelizer::get_sdf_3d_image() const { |
823 | Vector3i octree_size = get_voxel_gi_octree_size(); |
824 | |
825 | uint32_t float_count = octree_size.x * octree_size.y * octree_size.z; |
826 | float *work_memory = memnew_arr(float, float_count); |
827 | for (uint32_t i = 0; i < float_count; i++) { |
828 | work_memory[i] = INF; |
829 | } |
830 | |
831 | uint32_t y_mult = octree_size.x; |
832 | uint32_t z_mult = y_mult * octree_size.y; |
833 | |
834 | //plot solid cells |
835 | { |
836 | const Cell *cells = bake_cells.ptr(); |
837 | uint32_t cell_count = bake_cells.size(); |
838 | |
839 | for (uint32_t i = 0; i < cell_count; i++) { |
840 | if (cells[i].level < (cell_subdiv - 1)) { |
841 | continue; //do not care about this level |
842 | } |
843 | |
844 | work_memory[cells[i].x + cells[i].y * y_mult + cells[i].z * z_mult] = 0; |
845 | } |
846 | } |
847 | |
848 | //process in each direction |
849 | |
850 | //xy->z |
851 | |
852 | for (int i = 0; i < octree_size.x; i++) { |
853 | for (int j = 0; j < octree_size.y; j++) { |
854 | edt(&work_memory[i + j * y_mult], z_mult, octree_size.z); |
855 | } |
856 | } |
857 | |
858 | //xz->y |
859 | |
860 | for (int i = 0; i < octree_size.x; i++) { |
861 | for (int j = 0; j < octree_size.z; j++) { |
862 | edt(&work_memory[i + j * z_mult], y_mult, octree_size.y); |
863 | } |
864 | } |
865 | |
866 | //yz->x |
867 | for (int i = 0; i < octree_size.y; i++) { |
868 | for (int j = 0; j < octree_size.z; j++) { |
869 | edt(&work_memory[i * y_mult + j * z_mult], 1, octree_size.x); |
870 | } |
871 | } |
872 | |
873 | Vector<uint8_t> image3d; |
874 | image3d.resize(float_count); |
875 | { |
876 | uint8_t *w = image3d.ptrw(); |
877 | for (uint32_t i = 0; i < float_count; i++) { |
878 | uint32_t d = uint32_t(Math::sqrt(work_memory[i])); |
879 | if (d == 0) { |
880 | w[i] = 0; |
881 | } else { |
882 | w[i] = MIN(d, 254u) + 1; |
883 | } |
884 | } |
885 | } |
886 | |
887 | return image3d; |
888 | } |
889 | |
890 | #undef INF |
891 | |
892 | void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) { |
893 | if (p_level == cell_subdiv - 1) { |
894 | Vector3 center = p_aabb.get_center(); |
895 | Transform3D xform; |
896 | xform.origin = center; |
897 | xform.basis.scale(p_aabb.size * 0.5); |
898 | p_multimesh->set_instance_transform(idx, xform); |
899 | Color col; |
900 | col = Color(bake_cells[p_idx].albedo[0], bake_cells[p_idx].albedo[1], bake_cells[p_idx].albedo[2]); |
901 | //Color col = Color(bake_cells[p_idx].emission[0], bake_cells[p_idx].emission[1], bake_cells[p_idx].emission[2]); |
902 | p_multimesh->set_instance_color(idx, col); |
903 | |
904 | idx++; |
905 | |
906 | } else { |
907 | for (int i = 0; i < 8; i++) { |
908 | uint32_t child = bake_cells[p_idx].children[i]; |
909 | |
910 | if (child == CHILD_EMPTY || child >= (uint32_t)max_original_cells) { |
911 | continue; |
912 | } |
913 | |
914 | AABB aabb = p_aabb; |
915 | aabb.size *= 0.5; |
916 | |
917 | if (i & 1) { |
918 | aabb.position.x += aabb.size.x; |
919 | } |
920 | if (i & 2) { |
921 | aabb.position.y += aabb.size.y; |
922 | } |
923 | if (i & 4) { |
924 | aabb.position.z += aabb.size.z; |
925 | } |
926 | |
927 | _debug_mesh(bake_cells[p_idx].children[i], p_level + 1, aabb, p_multimesh, idx); |
928 | } |
929 | } |
930 | } |
931 | |
932 | Ref<MultiMesh> Voxelizer::create_debug_multimesh() { |
933 | Ref<MultiMesh> mm; |
934 | |
935 | mm.instantiate(); |
936 | |
937 | mm->set_transform_format(MultiMesh::TRANSFORM_3D); |
938 | mm->set_use_colors(true); |
939 | mm->set_instance_count(leaf_voxel_count); |
940 | |
941 | Ref<ArrayMesh> mesh; |
942 | mesh.instantiate(); |
943 | |
944 | { |
945 | Array arr; |
946 | arr.resize(Mesh::ARRAY_MAX); |
947 | |
948 | Vector<Vector3> vertices; |
949 | Vector<Color> colors; |
950 | #define ADD_VTX(m_idx) \ |
951 | vertices.push_back(face_points[m_idx]); \ |
952 | colors.push_back(Color(1, 1, 1, 1)); |
953 | |
954 | for (int i = 0; i < 6; i++) { |
955 | Vector3 face_points[4]; |
956 | |
957 | for (int j = 0; j < 4; j++) { |
958 | real_t v[3]; |
959 | v[0] = 1.0; |
960 | v[1] = 1 - 2 * ((j >> 1) & 1); |
961 | v[2] = v[1] * (1 - 2 * (j & 1)); |
962 | |
963 | for (int k = 0; k < 3; k++) { |
964 | if (i < 3) { |
965 | face_points[j][(i + k) % 3] = v[k]; |
966 | } else { |
967 | face_points[3 - j][(i + k) % 3] = -v[k]; |
968 | } |
969 | } |
970 | } |
971 | |
972 | //tri 1 |
973 | ADD_VTX(0); |
974 | ADD_VTX(1); |
975 | ADD_VTX(2); |
976 | //tri 2 |
977 | ADD_VTX(2); |
978 | ADD_VTX(3); |
979 | ADD_VTX(0); |
980 | } |
981 | |
982 | arr[Mesh::ARRAY_VERTEX] = vertices; |
983 | arr[Mesh::ARRAY_COLOR] = colors; |
984 | mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); |
985 | } |
986 | |
987 | { |
988 | Ref<StandardMaterial3D> fsm; |
989 | fsm.instantiate(); |
990 | fsm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); |
991 | fsm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); |
992 | fsm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); |
993 | fsm->set_albedo(Color(1, 1, 1, 1)); |
994 | |
995 | mesh->surface_set_material(0, fsm); |
996 | } |
997 | |
998 | mm->set_mesh(mesh); |
999 | |
1000 | int idx = 0; |
1001 | _debug_mesh(0, 0, po2_bounds, mm, idx); |
1002 | |
1003 | return mm; |
1004 | } |
1005 | |
1006 | Transform3D Voxelizer::get_to_cell_space_xform() const { |
1007 | return to_cell_space; |
1008 | } |
1009 | |
1010 | Voxelizer::Voxelizer() { |
1011 | } |
1012 | |