Show voxel bounds as min/max instead of pos/size

This commit is contained in:
Marc Gilleron 2022-07-10 22:04:20 +01:00
parent d6d592bb20
commit 97e4101234
8 changed files with 209 additions and 2 deletions

View File

@ -20,8 +20,8 @@ static const unsigned int MAX_BLOCK_COUNT_PER_REQUEST = 4 * 4 * 4;
// Using a higher maximum can cause int32 overflows when calculating dimensions. There is no use case for it.
static const unsigned int MAX_LOD = 24;
static const unsigned int MAX_VOLUME_EXTENT = 0x1fffffff;
static const unsigned int MAX_VOLUME_SIZE = 2 * MAX_VOLUME_EXTENT; // 1,073,741,822 voxels
static const int MAX_VOLUME_EXTENT = 0x1fffffff;
static const int MAX_VOLUME_SIZE = 2 * MAX_VOLUME_EXTENT; // 1,073,741,822 voxels
static const float INV_0x7f = 1.f / 0x7f;
static const float INV_0x7fff = 1.f / 0x7fff;

View File

@ -21,6 +21,7 @@ Godot 4 is required from this version.
- Added `ZN_ThreadedTask` to allow running custom tasks using the thread pool system
- Added `VoxelMeshSDF` to bake SDF from meshes, which can be used in voxel sculpting.
- Mesh resources are now fully built on threads with the Godot Vulkan renderer
- Editor: terrain bounds are now shown in the inspector as min/max instead of position/size
- `VoxelGeneratorGraph`: added support for outputting to the TYPE channel, allowing use with `VoxelMesherBlocky`
- `VoxelGeneratorGraph`: editor: unconnected inputs show their default value directly on the node
- `VoxelGeneratorGraph`: editor: allow to change the axes on preview nodes 3D slices

View File

@ -0,0 +1,108 @@
#include "editor_property_aabb_min_max.h"
#include <scene/gui/grid_container.h>
namespace zylann {
EditorPropertyAABBMinMax::EditorPropertyAABBMinMax() {
GridContainer *grid = memnew(GridContainer);
grid->set_columns(4);
add_child(grid);
for (int i = 0; i < _spin.size(); i++) {
if (i == 0) {
Label *label = memnew(Label);
label->set_text("Min");
grid->add_child(label);
} else if (i == 3) {
Label *label = memnew(Label);
label->set_text("Max");
grid->add_child(label);
}
EditorSpinSlider *sb = memnew(EditorSpinSlider);
sb->set_flat(true);
sb->set_h_size_flags(SIZE_EXPAND_FILL);
sb->connect("value_changed", callable_mp(this, &EditorPropertyAABBMinMax::_value_changed), varray(i));
_spin[i] = sb;
add_focusable(sb);
grid->add_child(sb);
}
_spin[0]->set_label("X");
_spin[1]->set_label("Y");
_spin[2]->set_label("Z");
_spin[3]->set_label("X");
_spin[4]->set_label("Y");
_spin[5]->set_label("Z");
set_bottom_editor(grid);
}
void EditorPropertyAABBMinMax::_set_read_only(bool p_read_only) {
for (int i = 0; i < 6; i++) {
_spin[i]->set_read_only(p_read_only);
}
};
void EditorPropertyAABBMinMax::_value_changed(double val, int spinbox_index) {
if (_setting) {
return;
}
AABB p;
p.position.x = _spin[0]->get_value();
p.position.y = _spin[1]->get_value();
p.position.z = _spin[2]->get_value();
p.size.x = _spin[3]->get_value() - p.position.x;
p.size.y = _spin[4]->get_value() - p.position.y;
p.size.z = _spin[5]->get_value() - p.position.z;
emit_changed(get_edited_property(), p, "");
}
void EditorPropertyAABBMinMax::update_property() {
const AABB val = get_edited_object()->get(get_edited_property());
_setting = true;
_spin[0]->set_value(val.position.x);
_spin[1]->set_value(val.position.y);
_spin[2]->set_value(val.position.z);
_spin[3]->set_value(val.position.x + val.size.x);
_spin[4]->set_value(val.position.y + val.size.y);
_spin[5]->set_value(val.position.z + val.size.z);
_setting = false;
}
void EditorPropertyAABBMinMax::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
const Color *colors = _get_property_colors();
for (unsigned int i = 0; i < _spin.size(); i++) {
_spin[i]->add_theme_color_override("label_color", colors[i % 3]);
}
} break;
}
}
void EditorPropertyAABBMinMax::setup(
double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
for (int i = 0; i < _spin.size(); i++) {
_spin[i]->set_min(p_min);
_spin[i]->set_max(p_max);
_spin[i]->set_step(p_step);
_spin[i]->set_hide_slider(p_no_slider);
_spin[i]->set_allow_greater(true);
_spin[i]->set_allow_lesser(true);
_spin[i]->set_suffix(p_suffix);
}
}
void EditorPropertyAABBMinMax::_bind_methods() {}
} // namespace zylann

View File

@ -0,0 +1,37 @@
#ifndef ZYLANN_EDITOR_PROPERTY_AABB_H
#define ZYLANN_EDITOR_PROPERTY_AABB_H
#include <editor/editor_inspector.h>
#include <editor/editor_spin_slider.h>
#include "../../util/fixed_array.h"
namespace zylann {
// Alternative to the default AABB editor which presents it as a minimum and maximum point
class EditorPropertyAABBMinMax : public EditorProperty {
GDCLASS(EditorPropertyAABBMinMax, EditorProperty);
public:
EditorPropertyAABBMinMax();
void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
virtual void update_property() override;
protected:
virtual void _set_read_only(bool p_read_only) override;
private:
void _value_changed(double p_val, int spinbox_index);
void _notification(int p_what);
static void _bind_methods();
FixedArray<EditorSpinSlider *, 6> _spin;
bool _setting = false;
};
} // namespace zylann
#endif // ZYLANN_EDITOR_PROPERTY_AABB_H

View File

@ -0,0 +1,37 @@
#include "voxel_terrain_editor_inspector_plugin.h"
#include "../../terrain/fixed_lod/voxel_terrain.h"
#include "../../terrain/variable_lod/voxel_lod_terrain.h"
#include "editor_property_aabb_min_max.h"
namespace zylann::voxel {
bool VoxelTerrainEditorInspectorPlugin::can_handle(Object *p_object) {
const VoxelTerrain *vt = Object::cast_to<VoxelTerrain>(p_object);
if (vt != nullptr) {
return true;
}
const VoxelLodTerrain *vlt = Object::cast_to<VoxelLodTerrain>(p_object);
if (vlt != nullptr) {
return true;
}
return false;
}
bool VoxelTerrainEditorInspectorPlugin::parse_property(Object *p_object, const Variant::Type p_type,
const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage,
const bool p_wide) {
if (p_type != Variant::AABB) {
return false;
}
// TODO Give the same name to these properties
if (p_path != "voxel_bounds" && p_path != "bounds") {
return false;
}
// Replace default AABB editor with this one
EditorPropertyAABBMinMax *ed = memnew(EditorPropertyAABBMinMax);
ed->setup(-constants::MAX_VOLUME_EXTENT, constants::MAX_VOLUME_EXTENT, 1, true);
add_property_editor(p_path, ed);
return true;
}
} // namespace zylann::voxel

View File

@ -0,0 +1,18 @@
#ifndef VOXEL_TERRAIN_EDITOR_INSPECTOR_PLUGIN_H
#define VOXEL_TERRAIN_EDITOR_INSPECTOR_PLUGIN_H
#include <editor/editor_inspector.h>
namespace zylann::voxel {
class VoxelTerrainEditorInspectorPlugin : public EditorInspectorPlugin {
GDCLASS(VoxelTerrainEditorInspectorPlugin, EditorInspectorPlugin)
public:
bool can_handle(Object *p_object) override;
bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint,
const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
};
} // namespace zylann::voxel
#endif // VOXEL_TERRAIN_EDITOR_INSPECTOR_PLUGIN_H

View File

@ -78,10 +78,14 @@ void VoxelTerrainEditorPlugin::_notification(int p_what) {
VoxelServer::get_singleton().set_viewer_distance(_editor_viewer_id, 512);
// No collision needed in editor, also it updates faster without
VoxelServer::get_singleton().set_viewer_requires_collisions(_editor_viewer_id, false);
_inspector_plugin.instantiate();
add_inspector_plugin(_inspector_plugin);
break;
case NOTIFICATION_EXIT_TREE:
VoxelServer::get_singleton().remove_viewer(_editor_viewer_id);
remove_inspector_plugin(_inspector_plugin);
break;
case NOTIFICATION_PROCESS:

View File

@ -1,6 +1,7 @@
#ifndef VOXEL_TERRAIN_EDITOR_PLUGIN_H
#define VOXEL_TERRAIN_EDITOR_PLUGIN_H
#include "voxel_terrain_editor_inspector_plugin.h"
#include <editor/editor_plugin.h>
class MenuButton;
@ -56,6 +57,7 @@ private:
MenuButton *_menu_button = nullptr;
VoxelAboutWindow *_about_window = nullptr;
VoxelTerrainEditorTaskIndicator *_task_indicator = nullptr;
Ref<VoxelTerrainEditorInspectorPlugin> _inspector_plugin;
};
} // namespace zylann::voxel