mirror of
https://github.com/godotengine/godot.git
synced 2025-10-31 21:51:22 +00:00
Add VoxelGI bake cancelling and progress UI improvement
This commit is contained in:
parent
0c45ace151
commit
da191168fe
6 changed files with 116 additions and 36 deletions
|
|
@ -146,15 +146,15 @@ void VoxelGIEditorPlugin::make_visible(bool p_visible) {
|
||||||
|
|
||||||
EditorProgress *VoxelGIEditorPlugin::tmp_progress = nullptr;
|
EditorProgress *VoxelGIEditorPlugin::tmp_progress = nullptr;
|
||||||
|
|
||||||
void VoxelGIEditorPlugin::bake_func_begin(int p_steps) {
|
void VoxelGIEditorPlugin::bake_func_begin() {
|
||||||
ERR_FAIL_COND(tmp_progress != nullptr);
|
ERR_FAIL_COND(tmp_progress != nullptr);
|
||||||
|
|
||||||
tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake VoxelGI"), p_steps));
|
tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake VoxelGI"), 1000, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelGIEditorPlugin::bake_func_step(int p_step, const String &p_description) {
|
bool VoxelGIEditorPlugin::bake_func_step(int p_progress, const String &p_description) {
|
||||||
ERR_FAIL_NULL(tmp_progress);
|
ERR_FAIL_NULL_V(tmp_progress, false);
|
||||||
tmp_progress->step(p_description, p_step, false);
|
return tmp_progress->step(p_description, p_progress, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelGIEditorPlugin::bake_func_end() {
|
void VoxelGIEditorPlugin::bake_func_end() {
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ class VoxelGIEditorPlugin : public EditorPlugin {
|
||||||
EditorFileDialog *probe_file = nullptr;
|
EditorFileDialog *probe_file = nullptr;
|
||||||
|
|
||||||
static EditorProgress *tmp_progress;
|
static EditorProgress *tmp_progress;
|
||||||
static void bake_func_begin(int p_steps);
|
static void bake_func_begin();
|
||||||
static void bake_func_step(int p_step, const String &p_description);
|
static bool bake_func_step(int p_progress, const String &p_description);
|
||||||
static void bake_func_end();
|
static void bake_func_end();
|
||||||
|
|
||||||
void _bake();
|
void _bake();
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,17 @@ VoxelGI::BakeBeginFunc VoxelGI::bake_begin_function = nullptr;
|
||||||
VoxelGI::BakeStepFunc VoxelGI::bake_step_function = nullptr;
|
VoxelGI::BakeStepFunc VoxelGI::bake_step_function = nullptr;
|
||||||
VoxelGI::BakeEndFunc VoxelGI::bake_end_function = nullptr;
|
VoxelGI::BakeEndFunc VoxelGI::bake_end_function = nullptr;
|
||||||
|
|
||||||
|
static int voxelizer_plot_bake_base = 0;
|
||||||
|
static int voxelizer_plot_bake_total = 0;
|
||||||
|
|
||||||
|
static bool voxelizer_plot_bake_step_function(int current, int) {
|
||||||
|
return VoxelGI::bake_step_function((voxelizer_plot_bake_base + current) * 500 / voxelizer_plot_bake_total, RTR("Plotting Meshes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool voxelizer_sdf_bake_step_function(int current, int total) {
|
||||||
|
return VoxelGI::bake_step_function(500 + current * 500 / total, RTR("Generating Distance Field"));
|
||||||
|
}
|
||||||
|
|
||||||
Vector3i VoxelGI::get_estimated_cell_size() const {
|
Vector3i VoxelGI::get_estimated_cell_size() const {
|
||||||
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
|
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
|
||||||
int cell_subdiv = subdiv_value[subdiv];
|
int cell_subdiv = subdiv_value[subdiv];
|
||||||
|
|
@ -432,22 +443,27 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
|
||||||
_find_meshes(p_from_node, mesh_list);
|
_find_meshes(p_from_node, mesh_list);
|
||||||
|
|
||||||
if (bake_begin_function) {
|
if (bake_begin_function) {
|
||||||
bake_begin_function(mesh_list.size() + 1);
|
bake_begin_function();
|
||||||
}
|
}
|
||||||
|
|
||||||
int pmc = 0;
|
Voxelizer::BakeStepFunc voxelizer_step_func = bake_step_function != nullptr ? voxelizer_plot_bake_step_function : nullptr;
|
||||||
|
|
||||||
|
voxelizer_plot_bake_total = voxelizer_plot_bake_base = 0;
|
||||||
for (PlotMesh &E : mesh_list) {
|
for (PlotMesh &E : mesh_list) {
|
||||||
if (bake_step_function) {
|
voxelizer_plot_bake_total += baker.get_bake_steps(E.mesh);
|
||||||
bake_step_function(pmc, RTR("Plotting Meshes") + " " + itos(pmc) + "/" + itos(mesh_list.size()));
|
}
|
||||||
|
for (PlotMesh &E : mesh_list) {
|
||||||
|
if (baker.plot_mesh(E.local_xform, E.mesh, E.instance_materials, E.override_material, voxelizer_step_func) != Voxelizer::BAKE_RESULT_OK) {
|
||||||
|
baker.end_bake();
|
||||||
|
if (bake_end_function) {
|
||||||
|
bake_end_function();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
voxelizer_plot_bake_base += baker.get_bake_steps(E.mesh);
|
||||||
pmc++;
|
|
||||||
|
|
||||||
baker.plot_mesh(E.local_xform, E.mesh, E.instance_materials, E.override_material);
|
|
||||||
}
|
}
|
||||||
if (bake_step_function) {
|
if (bake_step_function) {
|
||||||
bake_step_function(pmc++, RTR("Finishing Plot"));
|
bake_step_function(500, RTR("Finishing Plot"));
|
||||||
}
|
}
|
||||||
|
|
||||||
baker.end_bake();
|
baker.end_bake();
|
||||||
|
|
@ -476,19 +492,22 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bake_step_function) {
|
if (bake_step_function) {
|
||||||
bake_step_function(pmc++, RTR("Generating Distance Field"));
|
bake_step_function(500, RTR("Generating Distance Field"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<uint8_t> df = baker.get_sdf_3d_image();
|
voxelizer_step_func = bake_step_function != nullptr ? voxelizer_sdf_bake_step_function : nullptr;
|
||||||
|
|
||||||
RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization);
|
Vector<uint8_t> df;
|
||||||
|
if (baker.get_sdf_3d_image(df, voxelizer_step_func) == Voxelizer::BAKE_RESULT_OK) {
|
||||||
|
RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization);
|
||||||
|
|
||||||
probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-size / 2, size), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
|
probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-size / 2, size), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
|
||||||
|
|
||||||
set_probe_data(probe_data_new);
|
set_probe_data(probe_data_new);
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
probe_data_new->set_edited(true); //so it gets saved
|
probe_data_new->set_edited(true); //so it gets saved
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bake_end_function) {
|
if (bake_end_function) {
|
||||||
|
|
|
||||||
|
|
@ -108,8 +108,8 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*BakeBeginFunc)(int);
|
typedef void (*BakeBeginFunc)();
|
||||||
typedef void (*BakeStepFunc)(int, const String &);
|
typedef bool (*BakeStepFunc)(int, const String &);
|
||||||
typedef void (*BakeEndFunc)();
|
typedef void (*BakeEndFunc)();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -382,8 +382,24 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
|
||||||
return mc;
|
return mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) {
|
int Voxelizer::get_bake_steps(Ref<Mesh> &p_mesh) const {
|
||||||
ERR_FAIL_COND_MSG(!p_xform.is_finite(), "Invalid mesh bake transform.");
|
int bake_total = 0;
|
||||||
|
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
|
||||||
|
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
|
||||||
|
continue; // Only triangles.
|
||||||
|
}
|
||||||
|
Array a = p_mesh->surface_get_arrays(i);
|
||||||
|
Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
|
||||||
|
Vector<int> index = a[Mesh::ARRAY_INDEX];
|
||||||
|
bake_total += (index.size() > 0 ? index.size() : vertices.size()) / 3;
|
||||||
|
}
|
||||||
|
return bake_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
Voxelizer::BakeResult Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material, BakeStepFunc p_bake_step_func) {
|
||||||
|
ERR_FAIL_COND_V_MSG(!p_xform.is_finite(), BAKE_RESULT_INVALID_PARAMETER, "Invalid mesh bake transform.");
|
||||||
|
|
||||||
|
int bake_total = get_bake_steps(p_mesh), bake_current = 0;
|
||||||
|
|
||||||
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
|
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
|
||||||
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
|
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
|
||||||
|
|
@ -428,6 +444,13 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
|
||||||
Vector2 uvs[3];
|
Vector2 uvs[3];
|
||||||
Vector3 normal[3];
|
Vector3 normal[3];
|
||||||
|
|
||||||
|
bake_current++;
|
||||||
|
if (p_bake_step_func != nullptr && (bake_current & 2047) == 1) {
|
||||||
|
if (p_bake_step_func(bake_current, bake_total)) {
|
||||||
|
return BAKE_RESULT_CANCELLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
for (int k = 0; k < 3; k++) {
|
||||||
vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]);
|
vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]);
|
||||||
}
|
}
|
||||||
|
|
@ -460,6 +483,13 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
|
||||||
Vector2 uvs[3];
|
Vector2 uvs[3];
|
||||||
Vector3 normal[3];
|
Vector3 normal[3];
|
||||||
|
|
||||||
|
bake_current++;
|
||||||
|
if (p_bake_step_func != nullptr && (bake_current & 2047) == 1) {
|
||||||
|
if (p_bake_step_func(bake_current, bake_total)) {
|
||||||
|
return BAKE_RESULT_CANCELLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
for (int k = 0; k < 3; k++) {
|
||||||
vtxs[k] = p_xform.xform(vr[j * 3 + k]);
|
vtxs[k] = p_xform.xform(vr[j * 3 + k]);
|
||||||
}
|
}
|
||||||
|
|
@ -487,6 +517,8 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
|
||||||
}
|
}
|
||||||
|
|
||||||
max_original_cells = bake_cells.size();
|
max_original_cells = bake_cells.size();
|
||||||
|
|
||||||
|
return BAKE_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voxelizer::_sort() {
|
void Voxelizer::_sort() {
|
||||||
|
|
@ -821,7 +853,7 @@ static void edt(float *f, int stride, int n) {
|
||||||
|
|
||||||
#undef square
|
#undef square
|
||||||
|
|
||||||
Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
|
Voxelizer::BakeResult Voxelizer::get_sdf_3d_image(Vector<uint8_t> &r_image, BakeStepFunc p_bake_step_function) const {
|
||||||
Vector3i octree_size = get_voxel_gi_octree_size();
|
Vector3i octree_size = get_voxel_gi_octree_size();
|
||||||
|
|
||||||
uint32_t float_count = octree_size.x * octree_size.y * octree_size.z;
|
uint32_t float_count = octree_size.x * octree_size.y * octree_size.z;
|
||||||
|
|
@ -849,9 +881,17 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
|
||||||
|
|
||||||
//process in each direction
|
//process in each direction
|
||||||
|
|
||||||
|
int bake_total = octree_size.x * 2 + octree_size.y, bake_current = 0;
|
||||||
|
|
||||||
//xy->z
|
//xy->z
|
||||||
|
|
||||||
for (int i = 0; i < octree_size.x; i++) {
|
for (int i = 0; i < octree_size.x; i++, bake_current++) {
|
||||||
|
if (p_bake_step_function) {
|
||||||
|
if (p_bake_step_function(bake_current, bake_total)) {
|
||||||
|
memdelete_arr(work_memory);
|
||||||
|
return BAKE_RESULT_CANCELLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int j = 0; j < octree_size.y; j++) {
|
for (int j = 0; j < octree_size.y; j++) {
|
||||||
edt(&work_memory[i + j * y_mult], z_mult, octree_size.z);
|
edt(&work_memory[i + j * y_mult], z_mult, octree_size.z);
|
||||||
}
|
}
|
||||||
|
|
@ -859,23 +899,34 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
|
||||||
|
|
||||||
//xz->y
|
//xz->y
|
||||||
|
|
||||||
for (int i = 0; i < octree_size.x; i++) {
|
for (int i = 0; i < octree_size.x; i++, bake_current++) {
|
||||||
|
if (p_bake_step_function) {
|
||||||
|
if (p_bake_step_function(bake_current, bake_total)) {
|
||||||
|
memdelete_arr(work_memory);
|
||||||
|
return BAKE_RESULT_CANCELLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int j = 0; j < octree_size.z; j++) {
|
for (int j = 0; j < octree_size.z; j++) {
|
||||||
edt(&work_memory[i + j * z_mult], y_mult, octree_size.y);
|
edt(&work_memory[i + j * z_mult], y_mult, octree_size.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//yz->x
|
//yz->x
|
||||||
for (int i = 0; i < octree_size.y; i++) {
|
for (int i = 0; i < octree_size.y; i++, bake_current++) {
|
||||||
|
if (p_bake_step_function) {
|
||||||
|
if (p_bake_step_function(bake_current, bake_total)) {
|
||||||
|
memdelete_arr(work_memory);
|
||||||
|
return BAKE_RESULT_CANCELLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int j = 0; j < octree_size.z; j++) {
|
for (int j = 0; j < octree_size.z; j++) {
|
||||||
edt(&work_memory[i * y_mult + j * z_mult], 1, octree_size.x);
|
edt(&work_memory[i * y_mult + j * z_mult], 1, octree_size.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<uint8_t> image3d;
|
r_image.resize(float_count);
|
||||||
image3d.resize(float_count);
|
|
||||||
{
|
{
|
||||||
uint8_t *w = image3d.ptrw();
|
uint8_t *w = r_image.ptrw();
|
||||||
for (uint32_t i = 0; i < float_count; i++) {
|
for (uint32_t i = 0; i < float_count; i++) {
|
||||||
uint32_t d = uint32_t(Math::sqrt(work_memory[i]));
|
uint32_t d = uint32_t(Math::sqrt(work_memory[i]));
|
||||||
if (d == 0) {
|
if (d == 0) {
|
||||||
|
|
@ -888,7 +939,7 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
|
||||||
|
|
||||||
memdelete_arr(work_memory);
|
memdelete_arr(work_memory);
|
||||||
|
|
||||||
return image3d;
|
return BAKE_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef INF
|
#undef INF
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,15 @@
|
||||||
#include "scene/resources/multimesh.h"
|
#include "scene/resources/multimesh.h"
|
||||||
|
|
||||||
class Voxelizer {
|
class Voxelizer {
|
||||||
|
public:
|
||||||
|
enum BakeResult {
|
||||||
|
BAKE_RESULT_OK,
|
||||||
|
BAKE_RESULT_INVALID_PARAMETER,
|
||||||
|
BAKE_RESULT_CANCELLED,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef bool (*BakeStepFunc)(int, int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum : uint32_t {
|
enum : uint32_t {
|
||||||
CHILD_EMPTY = 0xFFFFFFFF
|
CHILD_EMPTY = 0xFFFFFFFF
|
||||||
|
|
@ -112,7 +121,8 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization);
|
void begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization);
|
||||||
void plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material);
|
int get_bake_steps(Ref<Mesh> &p_mesh) const;
|
||||||
|
BakeResult plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material, BakeStepFunc p_bake_step_function);
|
||||||
void end_bake();
|
void end_bake();
|
||||||
|
|
||||||
int get_voxel_gi_octree_depth() const;
|
int get_voxel_gi_octree_depth() const;
|
||||||
|
|
@ -121,7 +131,7 @@ public:
|
||||||
Vector<uint8_t> get_voxel_gi_octree_cells() const;
|
Vector<uint8_t> get_voxel_gi_octree_cells() const;
|
||||||
Vector<uint8_t> get_voxel_gi_data_cells() const;
|
Vector<uint8_t> get_voxel_gi_data_cells() const;
|
||||||
Vector<int> get_voxel_gi_level_cell_count() const;
|
Vector<int> get_voxel_gi_level_cell_count() const;
|
||||||
Vector<uint8_t> get_sdf_3d_image() const;
|
BakeResult get_sdf_3d_image(Vector<uint8_t> &r_image, BakeStepFunc p_bake_step_function) const;
|
||||||
|
|
||||||
Ref<MultiMesh> create_debug_multimesh();
|
Ref<MultiMesh> create_debug_multimesh();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue