| 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 |  | 
|---|