Streaming/LOD can be set to follow the editor camera instead of being centered on world origin
This commit is contained in:
parent
659e45fe32
commit
418cf0e630
12
CHANGELOG.md
12
CHANGELOG.md
@ -13,16 +13,20 @@ Semver is not yet in place, so each version can have breaking changes, although
|
|||||||
- General
|
- General
|
||||||
- Introduction of Voxel Server, which shares threaded tasks among all voxel nodes
|
- Introduction of Voxel Server, which shares threaded tasks among all voxel nodes
|
||||||
- Voxel data is no longer copied when sent to processing threads, reducing high memory spikes in some scenarios
|
- Voxel data is no longer copied when sent to processing threads, reducing high memory spikes in some scenarios
|
||||||
- Added a utility class to load MagicaVoxel `.vox` files
|
- Added a utility class to load `.vox` files created with MagicaVoxel (scripts only)
|
||||||
- Voxel nodes can be moved, scaled and rotated
|
- Voxel nodes can be moved, scaled and rotated
|
||||||
- Voxel nodes can be limited to specific bounds, rather than being infinitely paging volumes (multiples of block size)
|
- Voxel nodes can be limited to specific bounds, rather than being infinitely paging volumes (multiples of block size)
|
||||||
- Meshers are now resources so you can choose and configure them per terrain
|
- Meshers are now resources so you can choose and configure them per terrain
|
||||||
|
|
||||||
|
- Editor
|
||||||
|
- Streaming/LOD can be set to follow the editor camera instead of being centered on world origin
|
||||||
|
- Added About window
|
||||||
|
|
||||||
- Smooth voxels
|
- Smooth voxels
|
||||||
- Shaders now have access to the transform of each block, useful for triplanar mapping on moving volumes
|
- Shaders now have access to the transform of each block, useful for triplanar mapping on moving volumes
|
||||||
|
|
||||||
- Blocky voxels
|
- Blocky voxels
|
||||||
- Introduced a second blocky mesher dedicated to colored cubes, with greedy meshing and palette support
|
- Introduced a second blocky mesher dedicated to colored cubes, with greedy meshing and palette support (scripts only)
|
||||||
- Replaced `transparent` property with `transparency_index` for more control on the culling of transparent faces
|
- Replaced `transparent` property with `transparency_index` for more control on the culling of transparent faces
|
||||||
|
|
||||||
- Breaking changes
|
- Breaking changes
|
||||||
@ -43,7 +47,6 @@ Semver is not yet in place, so each version can have breaking changes, although
|
|||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
- General
|
- General
|
||||||
- Terrain nodes now render in the editor, unless scripts are involved (can be changed with an option)
|
|
||||||
- Added per-voxel and per-block metadata, which are saved by file streams along with voxel data
|
- Added per-voxel and per-block metadata, which are saved by file streams along with voxel data
|
||||||
- `StringName` is now used when possible to call script functions, to reduce overhead
|
- `StringName` is now used when possible to call script functions, to reduce overhead
|
||||||
- Exposed block serializer to allow encoding voxels for network or files from script
|
- Exposed block serializer to allow encoding voxels for network or files from script
|
||||||
@ -51,6 +54,9 @@ Semver is not yet in place, so each version can have breaking changes, although
|
|||||||
- The module only prints debug logs if the engine is in verbose mode
|
- The module only prints debug logs if the engine is in verbose mode
|
||||||
- `VoxelTerrain` now emit signals when blocks are loaded and unloaded
|
- `VoxelTerrain` now emit signals when blocks are loaded and unloaded
|
||||||
|
|
||||||
|
- Editor
|
||||||
|
- Terrain nodes now render in the editor, unless scripts are involved (can be changed with an option)
|
||||||
|
|
||||||
- Blocky voxels
|
- Blocky voxels
|
||||||
- Added collision masks to blocky voxels, which takes effect with `VoxelBoxMover` and voxel raycasts
|
- Added collision masks to blocky voxels, which takes effect with `VoxelBoxMover` and voxel raycasts
|
||||||
- Added random tick API for blocky terrains
|
- Added random tick API for blocky terrains
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "../about_window.h"
|
#include "../about_window.h"
|
||||||
#include "../graph/voxel_graph_node_inspector_wrapper.h"
|
#include "../graph/voxel_graph_node_inspector_wrapper.h"
|
||||||
|
|
||||||
|
#include <scene/3d/camera.h>
|
||||||
#include <scene/gui/menu_button.h>
|
#include <scene/gui/menu_button.h>
|
||||||
|
|
||||||
VoxelTerrainEditorPlugin::VoxelTerrainEditorPlugin(EditorNode *p_node) {
|
VoxelTerrainEditorPlugin::VoxelTerrainEditorPlugin(EditorNode *p_node) {
|
||||||
@ -13,6 +14,13 @@ VoxelTerrainEditorPlugin::VoxelTerrainEditorPlugin(EditorNode *p_node) {
|
|||||||
menu_button->get_popup()->add_item(TTR("Re-generate"), MENU_RESTART_STREAM);
|
menu_button->get_popup()->add_item(TTR("Re-generate"), MENU_RESTART_STREAM);
|
||||||
menu_button->get_popup()->add_item(TTR("Re-mesh"), MENU_REMESH);
|
menu_button->get_popup()->add_item(TTR("Re-mesh"), MENU_REMESH);
|
||||||
menu_button->get_popup()->add_separator();
|
menu_button->get_popup()->add_separator();
|
||||||
|
menu_button->get_popup()->add_item(TTR("Stream follow camera"), MENU_STREAM_FOLLOW_CAMERA);
|
||||||
|
{
|
||||||
|
const int i = menu_button->get_popup()->get_item_index(MENU_STREAM_FOLLOW_CAMERA);
|
||||||
|
menu_button->get_popup()->set_item_as_checkable(i, true);
|
||||||
|
menu_button->get_popup()->set_item_checked(i, _editor_viewer_follows_camera);
|
||||||
|
}
|
||||||
|
menu_button->get_popup()->add_separator();
|
||||||
menu_button->get_popup()->add_item(TTR("About Voxel Tools..."), MENU_ABOUT);
|
menu_button->get_popup()->add_item(TTR("About Voxel Tools..."), MENU_ABOUT);
|
||||||
menu_button->get_popup()->connect("id_pressed", this, "_on_menu_item_selected");
|
menu_button->get_popup()->connect("id_pressed", this, "_on_menu_item_selected");
|
||||||
menu_button->hide();
|
menu_button->hide();
|
||||||
@ -25,6 +33,19 @@ VoxelTerrainEditorPlugin::VoxelTerrainEditorPlugin(EditorNode *p_node) {
|
|||||||
base_control->add_child(_about_window);
|
base_control->add_child(_about_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VoxelTerrainEditorPlugin::_notification(int p_what) {
|
||||||
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_ENTER_TREE:
|
||||||
|
_editor_viewer_id = VoxelServer::get_singleton()->add_viewer();
|
||||||
|
VoxelServer::get_singleton()->set_viewer_distance(_editor_viewer_id, 512);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NOTIFICATION_EXIT_TREE:
|
||||||
|
VoxelServer::get_singleton()->remove_viewer(_editor_viewer_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Things the plugin doesn't directly work on, but still handles to keep things visible.
|
// Things the plugin doesn't directly work on, but still handles to keep things visible.
|
||||||
// This is basically a hack because it's not easy to express that with EditorPlugin API.
|
// This is basically a hack because it's not easy to express that with EditorPlugin API.
|
||||||
// The use case being, as long as we edit an object NESTED within a voxel terrain, we should keep things visible.
|
// The use case being, as long as we edit an object NESTED within a voxel terrain, we should keep things visible.
|
||||||
@ -107,6 +128,17 @@ void VoxelTerrainEditorPlugin::make_visible(bool visible) {
|
|||||||
// So we'll need to check if _node is null all over the place
|
// So we'll need to check if _node is null all over the place
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VoxelTerrainEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
|
||||||
|
VoxelServer::get_singleton()->set_viewer_distance(_editor_viewer_id, p_camera->get_zfar());
|
||||||
|
_editor_camera_last_position = p_camera->get_global_transform().origin;
|
||||||
|
|
||||||
|
if (_editor_viewer_follows_camera) {
|
||||||
|
VoxelServer::get_singleton()->set_viewer_position(_editor_viewer_id, _editor_camera_last_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void VoxelTerrainEditorPlugin::_on_menu_item_selected(int id) {
|
void VoxelTerrainEditorPlugin::_on_menu_item_selected(int id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case MENU_RESTART_STREAM:
|
case MENU_RESTART_STREAM:
|
||||||
@ -119,6 +151,17 @@ void VoxelTerrainEditorPlugin::_on_menu_item_selected(int id) {
|
|||||||
_node->remesh_all_blocks();
|
_node->remesh_all_blocks();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MENU_STREAM_FOLLOW_CAMERA: {
|
||||||
|
_editor_viewer_follows_camera = !_editor_viewer_follows_camera;
|
||||||
|
|
||||||
|
const int i = _menu_button->get_popup()->get_item_index(MENU_STREAM_FOLLOW_CAMERA);
|
||||||
|
_menu_button->get_popup()->set_item_checked(i, _editor_viewer_follows_camera);
|
||||||
|
|
||||||
|
if (_editor_viewer_follows_camera) {
|
||||||
|
VoxelServer::get_singleton()->set_viewer_position(_editor_viewer_id, _editor_camera_last_position);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case MENU_ABOUT:
|
case MENU_ABOUT:
|
||||||
_about_window->popup_centered();
|
_about_window->popup_centered();
|
||||||
break;
|
break;
|
||||||
|
@ -15,6 +15,10 @@ public:
|
|||||||
bool handles(Object *p_object) const override;
|
bool handles(Object *p_object) const override;
|
||||||
void edit(Object *p_object) override;
|
void edit(Object *p_object) override;
|
||||||
void make_visible(bool visible) override;
|
void make_visible(bool visible) override;
|
||||||
|
bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _notification(int p_what);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set_node(VoxelNode *node);
|
void set_node(VoxelNode *node);
|
||||||
@ -28,11 +32,16 @@ private:
|
|||||||
enum MenuID {
|
enum MenuID {
|
||||||
MENU_RESTART_STREAM,
|
MENU_RESTART_STREAM,
|
||||||
MENU_REMESH,
|
MENU_REMESH,
|
||||||
|
MENU_STREAM_FOLLOW_CAMERA,
|
||||||
MENU_ABOUT
|
MENU_ABOUT
|
||||||
};
|
};
|
||||||
|
|
||||||
VoxelNode *_node = nullptr;
|
VoxelNode *_node = nullptr;
|
||||||
|
|
||||||
|
uint32_t _editor_viewer_id = -1;
|
||||||
|
Vector3 _editor_camera_last_position;
|
||||||
|
bool _editor_viewer_follows_camera = false;
|
||||||
|
|
||||||
MenuButton *_menu_button = nullptr;
|
MenuButton *_menu_button = nullptr;
|
||||||
VoxelAboutWindow *_about_window = nullptr;
|
VoxelAboutWindow *_about_window = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -56,13 +56,6 @@ VoxelServer::VoxelServer() {
|
|||||||
_meshing_thread_pool.set_priority_update_period(64);
|
_meshing_thread_pool.set_priority_update_period(64);
|
||||||
_meshing_thread_pool.set_batch_count(1);
|
_meshing_thread_pool.set_batch_count(1);
|
||||||
|
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
|
||||||
// Default viewer
|
|
||||||
const uint32_t default_viewer_id = add_viewer();
|
|
||||||
Viewer &default_viewer = _world.viewers.get(default_viewer_id);
|
|
||||||
default_viewer.is_default = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init world
|
// Init world
|
||||||
_world.shared_priority_dependency = gd_make_shared<PriorityDependencyShared>();
|
_world.shared_priority_dependency = gd_make_shared<PriorityDependencyShared>();
|
||||||
|
|
||||||
@ -297,30 +290,11 @@ void VoxelServer::remove_volume(uint32_t volume_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t VoxelServer::add_viewer() {
|
uint32_t VoxelServer::add_viewer() {
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
|
||||||
// Remove default viewer if any
|
|
||||||
_world.viewers.for_each_with_id([this](Viewer &viewer, uint32_t id) {
|
|
||||||
if (viewer.is_default) {
|
|
||||||
// Safe because StructDB does not reallocate the data structure on removal
|
|
||||||
_world.viewers.destroy(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return _world.viewers.create(Viewer());
|
return _world.viewers.create(Viewer());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelServer::remove_viewer(uint32_t viewer_id) {
|
void VoxelServer::remove_viewer(uint32_t viewer_id) {
|
||||||
_world.viewers.destroy(viewer_id);
|
_world.viewers.destroy(viewer_id);
|
||||||
|
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
|
||||||
// Re-add default viewer
|
|
||||||
if (_world.viewers.count() == 0) {
|
|
||||||
const uint32_t default_viewer_id = add_viewer();
|
|
||||||
Viewer &default_viewer = _world.viewers.get(default_viewer_id);
|
|
||||||
default_viewer.is_default = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelServer::set_viewer_position(uint32_t viewer_id, Vector3 position) {
|
void VoxelServer::set_viewer_position(uint32_t viewer_id, Vector3 position) {
|
||||||
|
@ -62,7 +62,6 @@ public:
|
|||||||
unsigned int view_distance = 128;
|
unsigned int view_distance = 128;
|
||||||
bool require_collisions = false;
|
bool require_collisions = false;
|
||||||
bool require_visuals = true;
|
bool require_visuals = true;
|
||||||
bool is_default = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum VolumeType {
|
enum VolumeType {
|
||||||
|
@ -507,22 +507,16 @@ void VoxelLodTerrain::_notification(int p_what) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector3 VoxelLodTerrain::get_local_viewer_pos() const {
|
Vector3 VoxelLodTerrain::get_local_viewer_pos() const {
|
||||||
if (Engine::get_singleton()->is_editor_hint()) {
|
Vector3 pos = (_lods[0].last_viewer_block_pos << _lods[0].map.get_block_size_pow2()).to_vec3();
|
||||||
// TODO Use editor's camera here
|
|
||||||
return Vector3();
|
|
||||||
|
|
||||||
} else {
|
// TODO Support for multiple viewers, this is a placeholder implementation
|
||||||
Vector3 pos = (_lods[0].last_viewer_block_pos << _lods[0].map.get_block_size_pow2()).to_vec3();
|
VoxelServer::get_singleton()->for_each_viewer([&pos](const VoxelServer::Viewer &viewer, uint32_t viewer_id) {
|
||||||
|
pos = viewer.world_position;
|
||||||
|
});
|
||||||
|
|
||||||
// TODO Support for multiple viewers, this is a placeholder implementation
|
const Transform world_to_local = get_global_transform().affine_inverse();
|
||||||
VoxelServer::get_singleton()->for_each_viewer([&pos](const VoxelServer::Viewer &viewer, uint32_t viewer_id) {
|
pos = world_to_local.xform(pos);
|
||||||
pos = viewer.world_position;
|
return pos;
|
||||||
});
|
|
||||||
|
|
||||||
const Transform world_to_local = get_global_transform().affine_inverse();
|
|
||||||
pos = world_to_local.xform(pos);
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelLodTerrain::try_schedule_loading_with_neighbors(const Vector3i &p_bpos, int lod_index) {
|
void VoxelLodTerrain::try_schedule_loading_with_neighbors(const Vector3i &p_bpos, int lod_index) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user