diff options
author | Juan Linietsky <juan@godotengine.org> | 2019-10-12 21:24:03 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 12:03:54 +0100 |
commit | 76c6f39d99b82a07bc4f88ec4b6fb13b532be725 (patch) | |
tree | 2aa9a343eab2ac6b29e72e56d5efd48af4904a42 | |
parent | 561b431d85314000fe70d42e39713e5da394c3b5 (diff) |
GIProbe now generates a distance field on bake using CPU, for better compatibility
-rw-r--r-- | scene/3d/gi_probe.cpp | 21 | ||||
-rw-r--r-- | scene/3d/gi_probe.h | 3 | ||||
-rw-r--r-- | scene/3d/voxelizer.cpp | 116 | ||||
-rw-r--r-- | scene/3d/voxelizer.h | 1 | ||||
-rw-r--r-- | servers/visual/rasterizer.h | 4 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp | 28 | ||||
-rw-r--r-- | servers/visual/rasterizer_rd/rasterizer_storage_rd.h | 4 | ||||
-rw-r--r-- | servers/visual/visual_server_raster.h | 3 | ||||
-rw-r--r-- | servers/visual/visual_server_wrap_mt.h | 3 | ||||
-rw-r--r-- | servers/visual_server.h | 3 |
10 files changed, 173 insertions, 13 deletions
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 52c4efb7f1..5f7f24a75d 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -41,6 +41,7 @@ void GIProbeData::_set_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("octree_size")); ERR_FAIL_COND(!p_data.has("octree_cells")); ERR_FAIL_COND(!p_data.has("octree_data")); + ERR_FAIL_COND(!p_data.has("octree_df")); ERR_FAIL_COND(!p_data.has("level_counts")); ERR_FAIL_COND(!p_data.has("to_cell_xform")); @@ -48,10 +49,11 @@ void GIProbeData::_set_data(const Dictionary &p_data) { Vector3 octree_size = p_data["octree_size"]; PoolVector<uint8_t> octree_cells = p_data["octree_cells"]; PoolVector<uint8_t> octree_data = p_data["octree_data"]; + PoolVector<uint8_t> octree_df = p_data["octree_df"]; PoolVector<int> octree_levels = p_data["level_counts"]; Transform to_cell_xform = p_data["to_cell_xform"]; - allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_levels); + allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_df, octree_levels); } Dictionary GIProbeData::_get_data() const { @@ -60,13 +62,14 @@ Dictionary GIProbeData::_get_data() const { d["octree_size"] = get_octree_size(); d["octree_cells"] = get_octree_cells(); d["octree_data"] = get_data_cells(); + d["octree_df"] = get_distance_field(); d["level_counts"] = get_level_counts(); d["to_cell_xform"] = get_to_cell_xform(); return d; } -void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) { - VS::get_singleton()->gi_probe_allocate(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_level_counts); +void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<uint8_t> &p_distance_field, const PoolVector<int> &p_level_counts) { + VS::get_singleton()->gi_probe_allocate(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts); bounds = p_aabb; to_cell_xform = p_to_cell_xform; octree_size = p_octree_size; @@ -84,6 +87,10 @@ PoolVector<uint8_t> GIProbeData::get_octree_cells() const { PoolVector<uint8_t> GIProbeData::get_data_cells() const { return VS::get_singleton()->gi_probe_get_data_cells(probe); } +PoolVector<uint8_t> GIProbeData::get_distance_field() const { + return VS::get_singleton()->gi_probe_get_distance_field(probe); +} + PoolVector<int> GIProbeData::get_level_counts() const { return VS::get_singleton()->gi_probe_get_level_counts(probe); } @@ -406,7 +413,13 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { if (probe_data.is_null()) probe_data.instance(); - probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_giprobe_octree_size(), baker.get_giprobe_octree_cells(), baker.get_giprobe_data_cells(), baker.get_giprobe_level_cell_count()); + if (bake_step_function) { + bake_step_function(pmc++, RTR("Generating Distance Field")); + } + + PoolVector<uint8_t> df = baker.get_sdf_3d_image(); + + probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_giprobe_octree_size(), baker.get_giprobe_octree_cells(), baker.get_giprobe_data_cells(), df, baker.get_giprobe_level_cell_count()); set_probe_data(probe_data); probe_data->set_edited(true); //so it gets saved diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 7cb4b435c5..3d4ee52469 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -61,11 +61,12 @@ protected: void _validate_property(PropertyInfo &property) const; public: - void allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts); + void allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<uint8_t> &p_distance_field, const PoolVector<int> &p_level_counts); AABB get_bounds() const; Vector3 get_octree_size() const; PoolVector<uint8_t> get_octree_cells() const; PoolVector<uint8_t> get_data_cells() const; + PoolVector<uint8_t> get_distance_field() const; PoolVector<int> get_level_counts() const; Transform get_to_cell_xform() const; diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index 2aa2f79f43..0e20f606d6 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -981,6 +981,122 @@ PoolVector<int> Voxelizer::get_giprobe_level_cell_count() const { return level_count; } +// euclidean distance computation based on: +// https://prideout.net/blog/distance_fields/ + +#define square(m_s) ((m_s) * (m_s)) +#define INF 1e20 + +/* dt of 1d function using squared distance */ +static void edt(float *f, int stride, int n) { + + float *d = (float *)alloca(sizeof(float) * n + sizeof(int) * n + sizeof(float) * (n + 1)); + int *v = (int *)&(d[n]); + float *z = (float *)&v[n]; + + int k = 0; + v[0] = 0; + z[0] = -INF; + z[1] = +INF; + for (int q = 1; q <= n - 1; q++) { + float s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]); + while (s <= z[k]) { + k--; + s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]); + } + k++; + v[k] = q; + + z[k] = s; + z[k + 1] = +INF; + } + + k = 0; + for (int q = 0; q <= n - 1; q++) { + while (z[k + 1] < q) + k++; + d[q] = square(q - v[k]) + f[v[k] * stride]; + } + + for (int i = 0; i < n; i++) { + f[i * stride] = d[i]; + } +} + +#undef square + +PoolVector<uint8_t> Voxelizer::get_sdf_3d_image() const { + + Vector3i octree_size = get_giprobe_octree_size(); + + uint32_t float_count = octree_size.x * octree_size.y * octree_size.z; + float *work_memory = memnew_arr(float, float_count); + for (uint32_t i = 0; i < float_count; i++) { + work_memory[i] = INF; + } + + uint32_t y_mult = octree_size.x; + uint32_t z_mult = y_mult * octree_size.y; + + //plot solid cells + { + const Cell *cells = bake_cells.ptr(); + uint32_t cell_count = bake_cells.size(); + + for (uint32_t i = 0; i < cell_count; i++) { + + if (cells[i].level < (cell_subdiv - 1)) { + continue; //do not care about this level + } + + work_memory[cells[i].x + cells[i].y * y_mult + cells[i].z * z_mult] = 0; + } + } + + //process in each direction + + //xy->z + + for (int i = 0; i < octree_size.x; i++) { + for (int j = 0; j < octree_size.y; j++) { + edt(&work_memory[i + j * y_mult], z_mult, octree_size.z); + } + } + + //xz->y + + for (int i = 0; i < octree_size.x; i++) { + for (int j = 0; j < octree_size.z; j++) { + edt(&work_memory[i + j * z_mult], y_mult, octree_size.y); + } + } + + //yz->x + for (int i = 0; i < octree_size.y; i++) { + for (int j = 0; j < octree_size.z; j++) { + edt(&work_memory[i * y_mult + j * z_mult], 1, octree_size.x); + } + } + + PoolVector<uint8_t> image3d; + image3d.resize(float_count); + { + PoolVector<uint8_t>::Write w = image3d.write(); + for (uint32_t i = 0; i < float_count; i++) { + uint32_t d = uint32_t(Math::sqrt(work_memory[i])); + if (d == 0) { + w[i] = 0; + } else { + w[i] = CLAMP(d, 0, 254) + 1; + } + } + } + + return image3d; +} + +#undef INF + void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) { if (p_level == cell_subdiv - 1) { diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h index 37de6b782e..5016ff029f 100644 --- a/scene/3d/voxelizer.h +++ b/scene/3d/voxelizer.h @@ -135,6 +135,7 @@ public: PoolVector<uint8_t> get_giprobe_octree_cells() const; PoolVector<uint8_t> get_giprobe_data_cells() const; PoolVector<int> get_giprobe_level_cell_count() const; + PoolVector<uint8_t> get_sdf_3d_image() const; Ref<MultiMesh> create_debug_multimesh(); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 5a39a6dbfd..51acd3a797 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -488,12 +488,14 @@ public: virtual RID gi_probe_create() = 0; - virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) = 0; + virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<uint8_t> &p_distance_field, const PoolVector<int> &p_level_counts) = 0; virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; virtual PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; virtual PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; + virtual PoolVector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; + virtual PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp index 4c5b9b94fb..fa4cd39049 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp @@ -3552,7 +3552,7 @@ RID RasterizerStorageRD::gi_probe_create() { return gi_probe_owner.make_rid(GIProbe()); } -void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) { +void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<uint8_t> &p_distance_field, const PoolVector<int> &p_level_counts) { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND(!gi_probe); @@ -3591,7 +3591,19 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells); gi_probe->data_buffer_size = p_data_cells.size(); - { + if (p_distance_field.size()) { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_R8_UNORM; + tf.width = gi_probe->octree_size.x; + tf.height = gi_probe->octree_size.y; + tf.depth = gi_probe->octree_size.z; + tf.type = RD::TEXTURE_TYPE_3D; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; + Vector<PoolVector<uint8_t> > s; + s.push_back(p_distance_field); + gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s); + } +#if 0 { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; @@ -3659,6 +3671,7 @@ void RasterizerStorageRD::gi_probe_allocate(RID p_gi_probe, const Transform &p_t RD::get_singleton()->free(uniform_set); RD::get_singleton()->free(shared_tex); } +#endif } gi_probe->version++; @@ -3697,6 +3710,15 @@ PoolVector<uint8_t> RasterizerStorageRD::gi_probe_get_data_cells(RID p_gi_probe) } return PoolVector<uint8_t>(); } +PoolVector<uint8_t> RasterizerStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const { + GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); + ERR_FAIL_COND_V(!gi_probe, PoolVector<uint8_t>()); + + if (gi_probe->data_buffer.is_valid()) { + return RD::get_singleton()->texture_get_data(gi_probe->sdf_texture, 0); + } + return PoolVector<uint8_t>(); +} PoolVector<int> RasterizerStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const { GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); ERR_FAIL_COND_V(!gi_probe, PoolVector<int>()); @@ -4341,7 +4363,7 @@ bool RasterizerStorageRD::free(RID p_rid) { reflection_probe->instance_dependency.instance_notify_deleted(p_rid); reflection_probe_owner.free(p_rid); } else if (gi_probe_owner.owns(p_rid)) { - gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), PoolVector<uint8_t>(), PoolVector<uint8_t>(), PoolVector<int>()); //deallocate + gi_probe_allocate(p_rid, Transform(), AABB(), Vector3i(), PoolVector<uint8_t>(), PoolVector<uint8_t>(), PoolVector<uint8_t>(), PoolVector<int>()); //deallocate GIProbe *gi_probe = gi_probe_owner.getornull(p_rid); gi_probe->instance_dependency.instance_notify_deleted(p_rid); gi_probe_owner.free(p_rid); diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h index 63713c6add..f24933a349 100644 --- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.h @@ -967,12 +967,14 @@ public: RID gi_probe_create(); - void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts); + void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<uint8_t> &p_distance_field, const PoolVector<int> &p_level_counts); AABB gi_probe_get_bounds(RID p_gi_probe) const; Vector3i gi_probe_get_octree_size(RID p_gi_probe) const; PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const; PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const; + PoolVector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const; + PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const; Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 38f5c1ec58..0edb2762fa 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -344,12 +344,13 @@ public: BIND0R(RID, gi_probe_create) - BIND7(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &) + BIND8(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &) BIND1RC(AABB, gi_probe_get_bounds, RID) BIND1RC(Vector3i, gi_probe_get_octree_size, RID) BIND1RC(PoolVector<uint8_t>, gi_probe_get_octree_cells, RID) BIND1RC(PoolVector<uint8_t>, gi_probe_get_data_cells, RID) + BIND1RC(PoolVector<uint8_t>, gi_probe_get_distance_field, RID) BIND1RC(PoolVector<int>, gi_probe_get_level_counts, RID) BIND1RC(Transform, gi_probe_get_to_cell_xform, RID) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 37a2fffa7a..29f2f20941 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -268,12 +268,13 @@ public: FUNCRID(gi_probe) - FUNC7(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &) + FUNC8(gi_probe_allocate, RID, const Transform &, const AABB &, const Vector3i &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<uint8_t> &, const PoolVector<int> &) FUNC1RC(AABB, gi_probe_get_bounds, RID) FUNC1RC(Vector3i, gi_probe_get_octree_size, RID) FUNC1RC(PoolVector<uint8_t>, gi_probe_get_octree_cells, RID) FUNC1RC(PoolVector<uint8_t>, gi_probe_get_data_cells, RID) + FUNC1RC(PoolVector<uint8_t>, gi_probe_get_distance_field, RID) FUNC1RC(PoolVector<int>, gi_probe_get_level_counts, RID) FUNC1RC(Transform, gi_probe_get_to_cell_xform, RID) diff --git a/servers/visual_server.h b/servers/visual_server.h index deab05b4da..9c86456804 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -465,12 +465,13 @@ public: virtual RID gi_probe_create() = 0; - virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<int> &p_level_counts) = 0; + virtual void gi_probe_allocate(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const PoolVector<uint8_t> &p_octree_cells, const PoolVector<uint8_t> &p_data_cells, const PoolVector<uint8_t> &p_distance_field, const PoolVector<int> &p_level_counts) = 0; virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; virtual PoolVector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; virtual PoolVector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; + virtual PoolVector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; virtual PoolVector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; |