Discrete Level of Detail
Add scene side discrete level of detail. New node `LOD` for UI, and `LODManager` within `World` for automatically updating child visibilities based on distance from cameras.
This commit is contained in:
parent
354404db60
commit
1b5fa74e39
30 changed files with 713 additions and 134 deletions
|
@ -137,6 +137,11 @@
|
||||||
</method>
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
<members>
|
<members>
|
||||||
|
<member name="affect_lod" type="bool" setter="set_affect_lod" getter="get_affect_lod" default="true">
|
||||||
|
If [code]true[/code], the camera will be used to calculate the level of detail in [LOD] nodes.
|
||||||
|
Objects further from the camera will select lower levels of detail than those closer to the camera.
|
||||||
|
[b]Note:[/b] This property has no effect if [member projection] is set to [constant PROJECTION_ORTHOGONAL].
|
||||||
|
</member>
|
||||||
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
|
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
|
||||||
The culling mask that describes which 3D render layers are rendered by this camera.
|
The culling mask that describes which 3D render layers are rendered by this camera.
|
||||||
</member>
|
</member>
|
||||||
|
|
|
@ -45,22 +45,6 @@
|
||||||
<member name="lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance.LightmapScale" default="0">
|
<member name="lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance.LightmapScale" default="0">
|
||||||
Scale factor for the generated baked lightmap. Useful for adding detail to certain mesh instances.
|
Scale factor for the generated baked lightmap. Useful for adding detail to certain mesh instances.
|
||||||
</member>
|
</member>
|
||||||
<member name="lod_max_distance" type="float" setter="set_lod_max_distance" getter="get_lod_max_distance" default="0.0">
|
|
||||||
The GeometryInstance's max LOD distance.
|
|
||||||
[b]Note:[/b] This property currently has no effect.
|
|
||||||
</member>
|
|
||||||
<member name="lod_max_hysteresis" type="float" setter="set_lod_max_hysteresis" getter="get_lod_max_hysteresis" default="0.0">
|
|
||||||
The GeometryInstance's max LOD margin.
|
|
||||||
[b]Note:[/b] This property currently has no effect.
|
|
||||||
</member>
|
|
||||||
<member name="lod_min_distance" type="float" setter="set_lod_min_distance" getter="get_lod_min_distance" default="0.0">
|
|
||||||
The GeometryInstance's min LOD distance.
|
|
||||||
[b]Note:[/b] This property currently has no effect.
|
|
||||||
</member>
|
|
||||||
<member name="lod_min_hysteresis" type="float" setter="set_lod_min_hysteresis" getter="get_lod_min_hysteresis" default="0.0">
|
|
||||||
The GeometryInstance's min LOD margin.
|
|
||||||
[b]Note:[/b] This property currently has no effect.
|
|
||||||
</member>
|
|
||||||
<member name="material_overlay" type="Material" setter="set_material_overlay" getter="get_material_overlay">
|
<member name="material_overlay" type="Material" setter="set_material_overlay" getter="get_material_overlay">
|
||||||
The material overlay for the whole geometry.
|
The material overlay for the whole geometry.
|
||||||
If a material is assigned to this property, it will be rendered on top of any other active material for all the surfaces.
|
If a material is assigned to this property, it will be rendered on top of any other active material for all the surfaces.
|
||||||
|
|
27
doc/classes/LOD.xml
Normal file
27
doc/classes/LOD.xml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<class name="LOD" inherits="Spatial" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||||
|
<brief_description>
|
||||||
|
Provides discrete level of detail.
|
||||||
|
</brief_description>
|
||||||
|
<description>
|
||||||
|
Automatically hides and shows [Spatial] children depending on the distance from the closest [Camera] to the [LOD] node. Child nodes that don't inherit from [Spatial] are ignored by the LOD system.
|
||||||
|
Children are shown in order with the first children shown when closest to the [Camera], and the latter children shown when further away.
|
||||||
|
The threshold distances for changes are determined by [member Spatial.lod_range].
|
||||||
|
For example, a first child with a range of [code]2[/code] will be shown from distance 0 to 2. A second child with a range of [code]5[/code] will be shown from distance 2 to 7, etc.
|
||||||
|
</description>
|
||||||
|
<tutorials>
|
||||||
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
</methods>
|
||||||
|
<members>
|
||||||
|
<member name="hysteresis" type="float" setter="set_hysteresis" getter="get_hysteresis" default="1.0">
|
||||||
|
To prevent flickering at borders, a hysteresis distance will be added to threshold distances when the object is moving away from the [Camera].
|
||||||
|
</member>
|
||||||
|
<member name="lod_priority" type="int" setter="set_lod_priority" getter="get_lod_priority" default="0">
|
||||||
|
Determines the rate at which level of detail will be updated.
|
||||||
|
Higher priorities will update faster, but use more CPU.
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
|
<constants>
|
||||||
|
</constants>
|
||||||
|
</class>
|
|
@ -266,6 +266,10 @@
|
||||||
<member name="global_translation" type="Vector3" setter="set_global_translation" getter="get_global_translation">
|
<member name="global_translation" type="Vector3" setter="set_global_translation" getter="get_global_translation">
|
||||||
Global position of this node. This is equivalent to [code]global_transform.origin[/code].
|
Global position of this node. This is equivalent to [code]global_transform.origin[/code].
|
||||||
</member>
|
</member>
|
||||||
|
<member name="lod_range" type="float" setter="set_lod_range" getter="get_lod_range" default="10.0">
|
||||||
|
Determines the threshold distance at which this node will be shown or hidden when this node is parented by a [LOD] node.
|
||||||
|
For example, a first child with a range of [code]2[/code] will be shown from distance 0 to 2. A second child with a range of [code]5[/code] will be shown from distance 2 to 7, etc.
|
||||||
|
</member>
|
||||||
<member name="merging_mode" type="int" setter="set_merging_mode" getter="get_merging_mode" enum="Spatial.MergingMode" default="0">
|
<member name="merging_mode" type="int" setter="set_merging_mode" getter="get_merging_mode" enum="Spatial.MergingMode" default="0">
|
||||||
The merging mode determines whether merging features of the engine ([MergeGroup] and [RoomManager]) will attempt to operate on branches of the scene tree.
|
The merging mode determines whether merging features of the engine ([MergeGroup] and [RoomManager]) will attempt to operate on branches of the scene tree.
|
||||||
The default mode inherited from the scene tree root is [constant MERGING_MODE_ON].
|
The default mode inherited from the scene tree root is [constant MERGING_MODE_ON].
|
||||||
|
|
|
@ -1462,14 +1462,6 @@
|
||||||
Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
|
Once finished with your RID, you will want to free the RID using the VisualServer's [method free_rid] static method.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="instance_geometry_set_as_instance_lod">
|
|
||||||
<return type="void" />
|
|
||||||
<argument index="0" name="instance" type="RID" />
|
|
||||||
<argument index="1" name="as_lod_of_instance" type="RID" />
|
|
||||||
<description>
|
|
||||||
Not implemented in Godot 3.x.
|
|
||||||
</description>
|
|
||||||
</method>
|
|
||||||
<method name="instance_geometry_set_cast_shadows_setting">
|
<method name="instance_geometry_set_cast_shadows_setting">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="instance" type="RID" />
|
<argument index="0" name="instance" type="RID" />
|
||||||
|
@ -1478,17 +1470,6 @@
|
||||||
Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance.cast_shadow].
|
Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance.cast_shadow].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="instance_geometry_set_draw_range">
|
|
||||||
<return type="void" />
|
|
||||||
<argument index="0" name="instance" type="RID" />
|
|
||||||
<argument index="1" name="min" type="float" />
|
|
||||||
<argument index="2" name="max" type="float" />
|
|
||||||
<argument index="3" name="min_margin" type="float" />
|
|
||||||
<argument index="4" name="max_margin" type="float" />
|
|
||||||
<description>
|
|
||||||
Not implemented in Godot 3.x.
|
|
||||||
</description>
|
|
||||||
</method>
|
|
||||||
<method name="instance_geometry_set_flag">
|
<method name="instance_geometry_set_flag">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<argument index="0" name="instance" type="RID" />
|
<argument index="0" name="instance" type="RID" />
|
||||||
|
|
|
@ -1347,7 +1347,17 @@ void EditorNode::_find_node_types(Node *p_node, int &count_2d, int &count_3d) {
|
||||||
void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
||||||
EditorProgress save("save", TTR("Saving Scene"), 4);
|
EditorProgress save("save", TTR("Saving Scene"), 4);
|
||||||
|
|
||||||
|
Ref<World> edited_world;
|
||||||
|
|
||||||
if (editor_data.get_edited_scene_root() != nullptr) {
|
if (editor_data.get_edited_scene_root() != nullptr) {
|
||||||
|
// Allow a generic mechanism for the engine to make changes prior, and after saving.
|
||||||
|
if (editor_data.get_edited_scene_root()->get_tree() && editor_data.get_edited_scene_root()->get_tree()->get_root()) {
|
||||||
|
edited_world = editor_data.get_edited_scene_root()->get_tree()->get_root()->get_world();
|
||||||
|
if (edited_world.is_valid()) {
|
||||||
|
edited_world->notify_saving(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
save.step(TTR("Analyzing"), 0);
|
save.step(TTR("Analyzing"), 0);
|
||||||
|
|
||||||
int c2d = 0;
|
int c2d = 0;
|
||||||
|
@ -1428,6 +1438,10 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
|
||||||
save.step(TTR("Saving Scene"), 4);
|
save.step(TTR("Saving Scene"), 4);
|
||||||
_save_scene(p_file, p_idx);
|
_save_scene(p_file, p_idx);
|
||||||
|
|
||||||
|
if (edited_world.is_valid()) {
|
||||||
|
edited_world->notify_saving(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!singleton->cmdline_export_mode) {
|
if (!singleton->cmdline_export_mode) {
|
||||||
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
|
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
|
||||||
}
|
}
|
||||||
|
|
1
editor/icons/icon_l_o_d.svg
Normal file
1
editor/icons/icon_l_o_d.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.8914071 1.0013383-4.4946196 2.5949697-.4014433 6.2245994 5.5913828 2.7646396 4.49462-2.5949696.401443-6.2245994zm.1158866 1.9307015 2.4790833 2.563918.980876 3.428908-2.9964126 1.7299802-2.4790831-2.5639184-.9808766-3.428908z" fill="#fc9c9c" transform="matrix(1.0011971 .5780414 -.5780414 1.0011971 3.677961 -3.564097)"/></svg>
|
After Width: | Height: | Size: 423 B |
|
@ -45,6 +45,7 @@
|
||||||
#include "editor/spatial_editor_gizmos.h"
|
#include "editor/spatial_editor_gizmos.h"
|
||||||
#include "scene/3d/camera.h"
|
#include "scene/3d/camera.h"
|
||||||
#include "scene/3d/collision_shape.h"
|
#include "scene/3d/collision_shape.h"
|
||||||
|
#include "scene/3d/lod_manager.h"
|
||||||
#include "scene/3d/mesh_instance.h"
|
#include "scene/3d/mesh_instance.h"
|
||||||
#include "scene/3d/physics_body.h"
|
#include "scene/3d/physics_body.h"
|
||||||
#include "scene/3d/room_manager.h"
|
#include "scene/3d/room_manager.h"
|
||||||
|
@ -2735,7 +2736,12 @@ void SpatialEditorViewport::_notification(int p_what) {
|
||||||
} else {
|
} else {
|
||||||
set_freelook_active(false);
|
set_freelook_active(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
call_deferred("update_transform_gizmo_view");
|
call_deferred("update_transform_gizmo_view");
|
||||||
|
|
||||||
|
if (camera) {
|
||||||
|
camera->set_affect_lod(visible);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_what == NOTIFICATION_RESIZED) {
|
if (p_what == NOTIFICATION_RESIZED) {
|
||||||
|
@ -5503,6 +5509,14 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
|
||||||
VisualServer::get_singleton()->set_use_occlusion_culling(!is_checked);
|
VisualServer::get_singleton()->set_use_occlusion_culling(!is_checked);
|
||||||
view_menu->get_popup()->set_item_checked(checkbox_id, !is_checked);
|
view_menu->get_popup()->set_item_checked(checkbox_id, !is_checked);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case MENU_VIEW_LEVEL_OF_DETAIL: {
|
||||||
|
int checkbox_id = view_menu->get_popup()->get_item_index(p_option);
|
||||||
|
bool is_checked = view_menu->get_popup()->is_item_checked(checkbox_id);
|
||||||
|
LODManager::set_enabled(!is_checked);
|
||||||
|
view_menu->get_popup()->set_item_checked(checkbox_id, !is_checked);
|
||||||
|
EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->update_tree();
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case MENU_VIEW_CAMERA_SETTINGS: {
|
case MENU_VIEW_CAMERA_SETTINGS: {
|
||||||
settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
|
settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
|
||||||
|
@ -7076,6 +7090,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
|
||||||
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), KEY_NUMBERSIGN), MENU_VIEW_GRID);
|
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), KEY_NUMBERSIGN), MENU_VIEW_GRID);
|
||||||
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_portal_culling", TTR("View Portal Culling"), KEY_MASK_ALT | KEY_P), MENU_VIEW_PORTAL_CULLING);
|
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_portal_culling", TTR("View Portal Culling"), KEY_MASK_ALT | KEY_P), MENU_VIEW_PORTAL_CULLING);
|
||||||
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_occlusion_culling", TTR("View Occlusion Culling")), MENU_VIEW_OCCLUSION_CULLING);
|
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_occlusion_culling", TTR("View Occlusion Culling")), MENU_VIEW_OCCLUSION_CULLING);
|
||||||
|
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_level_of_detail", TTR("View Level of Detail")), MENU_VIEW_LEVEL_OF_DETAIL);
|
||||||
|
|
||||||
p->add_separator();
|
p->add_separator();
|
||||||
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
|
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
|
||||||
|
@ -7083,6 +7098,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
|
||||||
p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
|
p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
|
||||||
p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
|
p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
|
||||||
p->set_item_checked(p->get_item_index(MENU_VIEW_OCCLUSION_CULLING), true);
|
p->set_item_checked(p->get_item_index(MENU_VIEW_OCCLUSION_CULLING), true);
|
||||||
|
p->set_item_checked(p->get_item_index(MENU_VIEW_LEVEL_OF_DETAIL), true);
|
||||||
|
|
||||||
p->connect("id_pressed", this, "_menu_item_pressed");
|
p->connect("id_pressed", this, "_menu_item_pressed");
|
||||||
|
|
||||||
|
|
|
@ -674,6 +674,7 @@ private:
|
||||||
MENU_VIEW_GRID,
|
MENU_VIEW_GRID,
|
||||||
MENU_VIEW_PORTAL_CULLING,
|
MENU_VIEW_PORTAL_CULLING,
|
||||||
MENU_VIEW_OCCLUSION_CULLING,
|
MENU_VIEW_OCCLUSION_CULLING,
|
||||||
|
MENU_VIEW_LEVEL_OF_DETAIL,
|
||||||
MENU_VIEW_GIZMOS_3D_ICONS,
|
MENU_VIEW_GIZMOS_3D_ICONS,
|
||||||
MENU_VIEW_CAMERA_SETTINGS,
|
MENU_VIEW_CAMERA_SETTINGS,
|
||||||
MENU_LOCK_SELECTED,
|
MENU_LOCK_SELECTED,
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "editor/node_dock.h"
|
#include "editor/node_dock.h"
|
||||||
#include "editor/plugins/animation_player_editor_plugin.h"
|
#include "editor/plugins/animation_player_editor_plugin.h"
|
||||||
#include "editor/plugins/canvas_item_editor_plugin.h"
|
#include "editor/plugins/canvas_item_editor_plugin.h"
|
||||||
|
#include "scene/3d/lod_manager.h"
|
||||||
#include "scene/gui/label.h"
|
#include "scene/gui/label.h"
|
||||||
#include "scene/main/viewport.h"
|
#include "scene/main/viewport.h"
|
||||||
#include "scene/resources/packed_scene.h"
|
#include "scene/resources/packed_scene.h"
|
||||||
|
@ -162,7 +163,7 @@ void SceneTreeEditor::_toggle_visible(Node *p_node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
|
void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_disable_visibility) {
|
||||||
if (!p_node) {
|
if (!p_node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -405,9 +406,9 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
|
||||||
|
|
||||||
bool v = p_node->call("is_visible");
|
bool v = p_node->call("is_visible");
|
||||||
if (v) {
|
if (v) {
|
||||||
item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
|
item->add_button(0, get_icon("GuiVisibilityVisible", "EditorIcons"), BUTTON_VISIBILITY, p_disable_visibility, TTR("Toggle Visibility"));
|
||||||
} else {
|
} else {
|
||||||
item->add_button(0, get_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
|
item->add_button(0, get_icon("GuiVisibilityHidden", "EditorIcons"), BUTTON_VISIBILITY, p_disable_visibility, TTR("Toggle Visibility"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p_node->is_connected("visibility_changed", this, "_node_visibility_changed")) {
|
if (!p_node->is_connected("visibility_changed", this, "_node_visibility_changed")) {
|
||||||
|
@ -437,8 +438,12 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
|
||||||
item->set_as_cursor(0);
|
item->set_as_cursor(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In some cases we want to disable visibility control by the user
|
||||||
|
// for automatically visibility-controlled children.
|
||||||
|
bool disable_visibility = p_node->is_class("LOD") && LODManager::is_enabled();
|
||||||
|
|
||||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||||
_add_nodes(p_node->get_child(i), item);
|
_add_nodes(p_node->get_child(i), item, disable_visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid_types.size()) {
|
if (valid_types.size()) {
|
||||||
|
|
|
@ -73,7 +73,7 @@ class SceneTreeEditor : public Control {
|
||||||
|
|
||||||
void _compute_hash(Node *p_node, uint64_t &hash);
|
void _compute_hash(Node *p_node, uint64_t &hash);
|
||||||
|
|
||||||
void _add_nodes(Node *p_node, TreeItem *p_parent);
|
void _add_nodes(Node *p_node, TreeItem *p_parent, bool p_disable_visibility = false);
|
||||||
void _test_update_tree();
|
void _test_update_tree();
|
||||||
void _update_tree(bool p_scroll_to_selected = false);
|
void _update_tree(bool p_scroll_to_selected = false);
|
||||||
bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false);
|
bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false);
|
||||||
|
|
|
@ -504,6 +504,8 @@ void Camera::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
|
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
|
||||||
ClassDB::bind_method(D_METHOD("get_frustum"), &Camera::get_frustum);
|
ClassDB::bind_method(D_METHOD("get_frustum"), &Camera::get_frustum);
|
||||||
ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera::get_camera);
|
ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera::get_camera);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_affect_lod", "enable"), &Camera::set_affect_lod);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_affect_lod"), &Camera::get_affect_lod);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit);
|
ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit);
|
||||||
ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit);
|
ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit);
|
||||||
|
@ -523,6 +525,7 @@ void Camera::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
|
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "affect_lod"), "set_affect_lod", "get_affect_lod");
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
|
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
|
||||||
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
|
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
|
||||||
|
|
|
@ -88,6 +88,7 @@ private:
|
||||||
|
|
||||||
DopplerTracking doppler_tracking;
|
DopplerTracking doppler_tracking;
|
||||||
Ref<SpatialVelocityTracker> velocity_tracker;
|
Ref<SpatialVelocityTracker> velocity_tracker;
|
||||||
|
bool affect_lod = true;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _update_camera();
|
void _update_camera();
|
||||||
|
@ -170,6 +171,9 @@ public:
|
||||||
|
|
||||||
Vector3 get_doppler_tracked_velocity() const;
|
Vector3 get_doppler_tracked_velocity() const;
|
||||||
|
|
||||||
|
void set_affect_lod(bool p_enable) { affect_lod = p_enable; }
|
||||||
|
bool get_affect_lod() const { return affect_lod; }
|
||||||
|
|
||||||
Camera();
|
Camera();
|
||||||
~Camera();
|
~Camera();
|
||||||
};
|
};
|
||||||
|
|
250
scene/3d/lod.cpp
Normal file
250
scene/3d/lod.cpp
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* lod.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "lod.h"
|
||||||
|
|
||||||
|
#include "core/engine.h"
|
||||||
|
#include "scene/3d/visual_instance.h"
|
||||||
|
|
||||||
|
void LOD::_lod_register() {
|
||||||
|
if (!data.registered) {
|
||||||
|
Ref<World> world = get_world();
|
||||||
|
ERR_FAIL_COND(!world.is_valid());
|
||||||
|
world->_register_lod(this, data.queue_id);
|
||||||
|
data.registered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOD::_lod_unregister() {
|
||||||
|
if (data.registered) {
|
||||||
|
Ref<World> world = get_world();
|
||||||
|
ERR_FAIL_COND(!world.is_valid());
|
||||||
|
world->_unregister_lod(this, data.queue_id);
|
||||||
|
data.registered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOD::_notification(int p_what) {
|
||||||
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
|
if (is_visible_in_tree()) {
|
||||||
|
_lod_register();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
|
if (is_visible_in_tree()) {
|
||||||
|
_lod_unregister();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||||
|
if (is_inside_tree()) {
|
||||||
|
if (is_visible_in_tree()) {
|
||||||
|
_lod_register();
|
||||||
|
} else {
|
||||||
|
_lod_unregister();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOD::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("set_hysteresis", "distance"), &LOD::set_hysteresis);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_hysteresis"), &LOD::get_hysteresis);
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "hysteresis", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_hysteresis", "get_hysteresis");
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_lod_priority", "priority"), &LOD::set_lod_priority);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_lod_priority"), &LOD::get_lod_priority);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_priority", PROPERTY_HINT_RANGE, "0,4"), "set_lod_priority", "get_lod_priority");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOD::set_hysteresis(real_t p_distance) {
|
||||||
|
data.hysteresis = CLAMP((float)p_distance, 0.0f, 100000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOD::set_lod_priority(int p_priority) {
|
||||||
|
// We are just using priority as a user facing
|
||||||
|
// description. Internally we use queues.
|
||||||
|
int queue_id = CLAMP(p_priority, 0, 4);
|
||||||
|
|
||||||
|
if (queue_id == data.queue_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_inside_tree()) {
|
||||||
|
// If already in the world, we must remove the LOD
|
||||||
|
// and re-add in a different queue.
|
||||||
|
Ref<World> world = get_world();
|
||||||
|
ERR_FAIL_COND(!world.is_valid());
|
||||||
|
world->_unregister_lod(this, data.queue_id);
|
||||||
|
|
||||||
|
data.queue_id = queue_id;
|
||||||
|
|
||||||
|
world->_register_lod(this, data.queue_id);
|
||||||
|
} else {
|
||||||
|
data.queue_id = queue_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOD::_lod_pre_save() {
|
||||||
|
// The pre-save is primarily for the editor,
|
||||||
|
// to ensure that saved scenes do not have unnecessary
|
||||||
|
// diffs because of changes to which LOD child is active.
|
||||||
|
// We standardize on just showing the first child in saved scenes.
|
||||||
|
_update_child_distances();
|
||||||
|
|
||||||
|
int32_t num_lods = data.lod_children.size();
|
||||||
|
|
||||||
|
// Make first visible, and all others invisible.
|
||||||
|
data.current_lod_child = 0;
|
||||||
|
|
||||||
|
for (int32_t n = 0; n < num_lods; n++) {
|
||||||
|
uint32_t child_id = data.lod_children[n].child_id;
|
||||||
|
Spatial *child = Object::cast_to<Spatial>(get_child(child_id));
|
||||||
|
|
||||||
|
if (child) {
|
||||||
|
child->set_visible(n == data.current_lod_child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns whether a visibility change was triggered.
|
||||||
|
bool LOD::_lod_update(float p_camera_dist_squared) {
|
||||||
|
// This should later be done as a one-off, as
|
||||||
|
// this is expensive.
|
||||||
|
_update_child_distances();
|
||||||
|
|
||||||
|
int32_t num_lods = data.lod_children.size();
|
||||||
|
|
||||||
|
// LOD node has no valid children to update.
|
||||||
|
if (!num_lods) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.current_lod_child = MIN(data.current_lod_child, num_lods - 1);
|
||||||
|
int32_t curr = data.current_lod_child;
|
||||||
|
|
||||||
|
float dist = Math::sqrt(p_camera_dist_squared);
|
||||||
|
|
||||||
|
bool changed = true;
|
||||||
|
|
||||||
|
while (changed) {
|
||||||
|
changed = false;
|
||||||
|
if ((curr < num_lods - 1) && (dist >= (data.lod_children[curr + 1].distance) + data.hysteresis)) {
|
||||||
|
// Lower detail.
|
||||||
|
curr += 1;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curr && (dist < data.lod_children[curr].distance)) {
|
||||||
|
// Increase detail.
|
||||||
|
curr -= 1;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No change?
|
||||||
|
if ((curr == data.current_lod_child) && (data.current_lod_node == get_child(data.lod_children[curr].child_id))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.current_lod_child = curr;
|
||||||
|
|
||||||
|
// Make current visible, and all others invisible.
|
||||||
|
for (int32_t n = 0; n < num_lods; n++) {
|
||||||
|
uint32_t child_id = data.lod_children[n].child_id;
|
||||||
|
|
||||||
|
Spatial *child = Object::cast_to<Spatial>(get_child(child_id));
|
||||||
|
|
||||||
|
if (child) {
|
||||||
|
child->set_visible(n == curr);
|
||||||
|
if (n == curr) {
|
||||||
|
data.current_lod_node = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LOD::_update_child_distances() {
|
||||||
|
// Reserve enough space for all children, assuming they are all valid.
|
||||||
|
LODChild *lod_children = (LODChild *)alloca(sizeof(LODChild) * get_child_count());
|
||||||
|
|
||||||
|
// Reset prior to loop.
|
||||||
|
float total_dist = 0.0f;
|
||||||
|
uint32_t valid_count = 0;
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
bool is_editor = Engine::get_singleton()->is_editor_hint();
|
||||||
|
uint32_t visible_count = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check every possible node child, not all will be valid lod children.
|
||||||
|
for (int32_t n = 0; n < get_child_count(); n++) {
|
||||||
|
// Destination for a valid child.
|
||||||
|
LODChild &lod_child = lod_children[valid_count];
|
||||||
|
|
||||||
|
const Spatial *child = Object::cast_to<Spatial>(get_child(n));
|
||||||
|
if (child) {
|
||||||
|
// Fill the data.
|
||||||
|
lod_child.distance = total_dist;
|
||||||
|
lod_child.child_id = n;
|
||||||
|
|
||||||
|
// Keep running total of the distance range used by each lod child.
|
||||||
|
total_dist += child->get_lod_range();
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
if (is_editor && child->is_visible()) {
|
||||||
|
visible_count++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
valid_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size the actual vector, and copy data across.
|
||||||
|
data.lod_children.resize(valid_count);
|
||||||
|
if (valid_count) {
|
||||||
|
memcpy(&data.lod_children[0], lod_children, valid_count * sizeof(LODChild));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TOOLS_ENABLED
|
||||||
|
// Something external has changed the visibilities of the children,
|
||||||
|
// such as the editor.
|
||||||
|
if (is_editor && visible_count != 1) {
|
||||||
|
// Force the current child to reset.
|
||||||
|
data.current_lod_child = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
73
scene/3d/lod.h
Normal file
73
scene/3d/lod.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* lod.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LOD_H
|
||||||
|
#define LOD_H
|
||||||
|
|
||||||
|
#include "spatial.h"
|
||||||
|
|
||||||
|
class LOD : public Spatial {
|
||||||
|
GDCLASS(LOD, Spatial);
|
||||||
|
|
||||||
|
struct LODChild {
|
||||||
|
float distance;
|
||||||
|
int32_t child_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
LocalVector<LODChild> lod_children;
|
||||||
|
int32_t current_lod_child = 0;
|
||||||
|
float hysteresis = 1.0f;
|
||||||
|
int32_t queue_id = 0;
|
||||||
|
const Spatial *current_lod_node = nullptr;
|
||||||
|
bool registered = false;
|
||||||
|
} data;
|
||||||
|
|
||||||
|
friend class LODManager;
|
||||||
|
bool _lod_update(float p_camera_dist_squared);
|
||||||
|
void _lod_pre_save();
|
||||||
|
void _update_child_distances();
|
||||||
|
|
||||||
|
void _lod_register();
|
||||||
|
void _lod_unregister();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _notification(int p_what);
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_hysteresis(real_t p_distance);
|
||||||
|
real_t get_hysteresis() const { return data.hysteresis; }
|
||||||
|
|
||||||
|
void set_lod_priority(int p_priority);
|
||||||
|
int get_lod_priority() const { return data.queue_id; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOD_H
|
182
scene/3d/lod_manager.cpp
Normal file
182
scene/3d/lod_manager.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* lod_manager.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "lod_manager.h"
|
||||||
|
|
||||||
|
#include "scene/3d/camera.h"
|
||||||
|
#include "scene/3d/lod.h"
|
||||||
|
|
||||||
|
bool LODManager::_enabled = true;
|
||||||
|
|
||||||
|
void LODManager::register_camera(Camera *p_camera) {
|
||||||
|
DEV_ASSERT(p_camera);
|
||||||
|
data.cameras.push_back(p_camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LODManager::remove_camera(Camera *p_camera) {
|
||||||
|
data.cameras.erase(p_camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LODManager::register_lod(LOD *p_lod, uint32_t p_queue_id) {
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX(p_queue_id, NUM_LOD_QUEUES);
|
||||||
|
data.queues[p_queue_id].lods.push_back(p_lod);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LODManager::unregister_lod(LOD *p_lod, uint32_t p_queue_id) {
|
||||||
|
ERR_FAIL_UNSIGNED_INDEX(p_queue_id, NUM_LOD_QUEUES);
|
||||||
|
data.queues[p_queue_id].lods.erase(p_lod);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LODManager::_update_queue(uint32_t p_queue_id, const Vector3 *p_camera_positions, uint32_t p_num_cameras) {
|
||||||
|
// Some local aliases.
|
||||||
|
Queue &queue = data.queues[p_queue_id];
|
||||||
|
LocalVector<LOD *> &lods = queue.lods;
|
||||||
|
|
||||||
|
uint32_t total_lods = lods.size();
|
||||||
|
|
||||||
|
if (!total_lods) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wraparound.
|
||||||
|
queue.lod_iterator %= total_lods;
|
||||||
|
|
||||||
|
uint32_t first_lod = queue.lod_iterator;
|
||||||
|
|
||||||
|
uint32_t num_lods_to_check = 1;
|
||||||
|
uint32_t num_lods_to_change = 1;
|
||||||
|
|
||||||
|
switch (p_queue_id) {
|
||||||
|
case 4: {
|
||||||
|
num_lods_to_check = 3125;
|
||||||
|
num_lods_to_change = 32;
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
num_lods_to_check = 256;
|
||||||
|
num_lods_to_change = 8;
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
num_lods_to_check = 27;
|
||||||
|
num_lods_to_change = 4;
|
||||||
|
} break;
|
||||||
|
case 1: {
|
||||||
|
num_lods_to_check = 4;
|
||||||
|
num_lods_to_change = 1;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No point updating more lods than the total.
|
||||||
|
num_lods_to_check = MIN(num_lods_to_check, total_lods);
|
||||||
|
num_lods_to_change = MIN(num_lods_to_change, total_lods);
|
||||||
|
|
||||||
|
// Find minimum distances to cameras...
|
||||||
|
uint32_t changed = 0;
|
||||||
|
|
||||||
|
for (uint32_t l = 0; l < num_lods_to_check; l++) {
|
||||||
|
uint32_t lod_id = (first_lod + l) % total_lods;
|
||||||
|
LOD *lod = lods[lod_id];
|
||||||
|
Vector3 lod_pos = lod->get_global_translation();
|
||||||
|
|
||||||
|
float min_dist = FLT_MAX;
|
||||||
|
for (uint32_t c = 0; c < p_num_cameras; c++) {
|
||||||
|
float dist = (lod_pos - p_camera_positions[c]).length_squared();
|
||||||
|
min_dist = MIN(min_dist, dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lod->_lod_update(min_dist)) {
|
||||||
|
changed++;
|
||||||
|
if (changed >= num_lods_to_change) {
|
||||||
|
// Only update the iterator to where we got to.
|
||||||
|
num_lods_to_check = l + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.lod_iterator += num_lods_to_check;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LODManager::notify_saving(bool p_active) {
|
||||||
|
// When saving in the editor, to prevent file delta due to
|
||||||
|
// different visibilities from LOD childs, we standardize
|
||||||
|
// to showing the first LOD.
|
||||||
|
MutexLock lock(data.mutex);
|
||||||
|
data.saving = p_active;
|
||||||
|
|
||||||
|
if (p_active) {
|
||||||
|
for (uint32_t n = 0; n < NUM_LOD_QUEUES; n++) {
|
||||||
|
Queue &queue = data.queues[n];
|
||||||
|
LocalVector<LOD *> &lods = queue.lods;
|
||||||
|
|
||||||
|
for (uint32_t l = 0; l < lods.size(); l++) {
|
||||||
|
lods[l]->_lod_pre_save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LODManager::update() {
|
||||||
|
if (!_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutexLock lock(data.mutex);
|
||||||
|
|
||||||
|
// We don't want to change the visibilities while saving from the editor.
|
||||||
|
if (data.saving) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all camera positions
|
||||||
|
// Reserve enough for all cameras, some may not be used.
|
||||||
|
Vector3 *camera_positions = (Vector3 *)alloca(data.cameras.size() * sizeof(Vector3));
|
||||||
|
|
||||||
|
uint32_t num_cameras = 0;
|
||||||
|
for (uint32_t c = 0; c < data.cameras.size(); c++) {
|
||||||
|
const Camera *camera = data.cameras[c];
|
||||||
|
|
||||||
|
// Ignore ortho cameras for LOD.
|
||||||
|
if (!camera->get_affect_lod() || !camera->is_current() || (camera->get_projection() == Camera::PROJECTION_ORTHOGONAL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
camera_positions[num_cameras++] = camera->get_global_transform().origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!num_cameras) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t n = 0; n < NUM_LOD_QUEUES; n++) {
|
||||||
|
_update_queue(n, camera_positions, num_cameras);
|
||||||
|
}
|
||||||
|
}
|
74
scene/3d/lod_manager.h
Normal file
74
scene/3d/lod_manager.h
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* lod_manager.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LOD_MANAGER_H
|
||||||
|
#define LOD_MANAGER_H
|
||||||
|
|
||||||
|
#include "core/local_vector.h"
|
||||||
|
#include "core/os/mutex.h"
|
||||||
|
|
||||||
|
class Camera;
|
||||||
|
class LOD;
|
||||||
|
struct Vector3;
|
||||||
|
|
||||||
|
class LODManager {
|
||||||
|
public:
|
||||||
|
enum { NUM_LOD_QUEUES = 5 };
|
||||||
|
|
||||||
|
void register_camera(Camera *p_camera);
|
||||||
|
void remove_camera(Camera *p_camera);
|
||||||
|
void register_lod(LOD *p_lod, uint32_t p_queue_id);
|
||||||
|
void unregister_lod(LOD *p_lod, uint32_t p_queue_id);
|
||||||
|
void update();
|
||||||
|
|
||||||
|
void notify_saving(bool p_active);
|
||||||
|
|
||||||
|
static void set_enabled(bool p_enabled) { _enabled = p_enabled; }
|
||||||
|
static bool is_enabled() { return _enabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _update_queue(uint32_t p_queue_id, const Vector3 *p_camera_positions, uint32_t p_num_cameras);
|
||||||
|
|
||||||
|
struct Queue {
|
||||||
|
LocalVector<LOD *> lods;
|
||||||
|
uint32_t lod_iterator = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
LocalVector<Camera *> cameras;
|
||||||
|
Queue queues[NUM_LOD_QUEUES];
|
||||||
|
BinaryMutex mutex;
|
||||||
|
bool saving = false;
|
||||||
|
} data;
|
||||||
|
|
||||||
|
static bool _enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOD_MANAGER_H
|
|
@ -915,6 +915,10 @@ void Spatial::set_merging_mode(MergingMode p_mode) {
|
||||||
_propagate_merging_allowed(merging_allowed);
|
_propagate_merging_allowed(merging_allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spatial::set_lod_range(float p_range) {
|
||||||
|
data.lod_range = p_range;
|
||||||
|
}
|
||||||
|
|
||||||
void Spatial::force_update_transform() {
|
void Spatial::force_update_transform() {
|
||||||
ERR_FAIL_COND(!is_inside_tree());
|
ERR_FAIL_COND(!is_inside_tree());
|
||||||
if (!xform_change.in_list()) {
|
if (!xform_change.in_list()) {
|
||||||
|
@ -993,6 +997,9 @@ void Spatial::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_merging_mode", "mode"), &Spatial::set_merging_mode);
|
ClassDB::bind_method(D_METHOD("set_merging_mode", "mode"), &Spatial::set_merging_mode);
|
||||||
ClassDB::bind_method(D_METHOD("get_merging_mode"), &Spatial::get_merging_mode);
|
ClassDB::bind_method(D_METHOD("get_merging_mode"), &Spatial::get_merging_mode);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_lod_range", "range"), &Spatial::set_lod_range);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_lod_range"), &Spatial::get_lod_range);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Spatial::to_local);
|
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Spatial::to_local);
|
||||||
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Spatial::to_global);
|
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Spatial::to_global);
|
||||||
|
|
||||||
|
@ -1024,6 +1031,7 @@ void Spatial::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
|
||||||
ADD_GROUP("Misc", "");
|
ADD_GROUP("Misc", "");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL, "lod_range", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_lod_range", "get_lod_range");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "merging_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_merging_mode", "get_merging_mode");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "merging_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_merging_mode", "get_merging_mode");
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("visibility_changed"));
|
ADD_SIGNAL(MethodInfo("visibility_changed"));
|
||||||
|
|
|
@ -115,6 +115,7 @@ private:
|
||||||
List<Spatial *> children;
|
List<Spatial *> children;
|
||||||
List<Spatial *>::Element *C;
|
List<Spatial *>::Element *C;
|
||||||
|
|
||||||
|
float lod_range = 10.0f;
|
||||||
ClientPhysicsInterpolationData *client_physics_interpolation_data;
|
ClientPhysicsInterpolationData *client_physics_interpolation_data;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
@ -248,6 +249,9 @@ public:
|
||||||
|
|
||||||
void force_update_transform();
|
void force_update_transform();
|
||||||
|
|
||||||
|
void set_lod_range(float p_range);
|
||||||
|
float get_lod_range() const { return data.lod_range; }
|
||||||
|
|
||||||
Spatial();
|
Spatial();
|
||||||
~Spatial();
|
~Spatial();
|
||||||
};
|
};
|
||||||
|
|
|
@ -266,42 +266,6 @@ GeometryInstance::LightmapScale GeometryInstance::get_lightmap_scale() const {
|
||||||
return lightmap_scale;
|
return lightmap_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeometryInstance::set_lod_min_distance(float p_dist) {
|
|
||||||
lod_min_distance = p_dist;
|
|
||||||
VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
|
||||||
}
|
|
||||||
|
|
||||||
float GeometryInstance::get_lod_min_distance() const {
|
|
||||||
return lod_min_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GeometryInstance::set_lod_max_distance(float p_dist) {
|
|
||||||
lod_max_distance = p_dist;
|
|
||||||
VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
|
||||||
}
|
|
||||||
|
|
||||||
float GeometryInstance::get_lod_max_distance() const {
|
|
||||||
return lod_max_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GeometryInstance::set_lod_min_hysteresis(float p_dist) {
|
|
||||||
lod_min_hysteresis = p_dist;
|
|
||||||
VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
|
||||||
}
|
|
||||||
|
|
||||||
float GeometryInstance::get_lod_min_hysteresis() const {
|
|
||||||
return lod_min_hysteresis;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GeometryInstance::set_lod_max_hysteresis(float p_dist) {
|
|
||||||
lod_max_hysteresis = p_dist;
|
|
||||||
VS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
|
||||||
}
|
|
||||||
|
|
||||||
float GeometryInstance::get_lod_max_hysteresis() const {
|
|
||||||
return lod_max_hysteresis;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GeometryInstance::_notification(int p_what) {
|
void GeometryInstance::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,18 +331,6 @@ void GeometryInstance::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_lightmap_scale", "scale"), &GeometryInstance::set_lightmap_scale);
|
ClassDB::bind_method(D_METHOD("set_lightmap_scale", "scale"), &GeometryInstance::set_lightmap_scale);
|
||||||
ClassDB::bind_method(D_METHOD("get_lightmap_scale"), &GeometryInstance::get_lightmap_scale);
|
ClassDB::bind_method(D_METHOD("get_lightmap_scale"), &GeometryInstance::get_lightmap_scale);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_lod_max_hysteresis", "mode"), &GeometryInstance::set_lod_max_hysteresis);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_lod_max_hysteresis"), &GeometryInstance::get_lod_max_hysteresis);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_lod_max_distance", "mode"), &GeometryInstance::set_lod_max_distance);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_lod_max_distance"), &GeometryInstance::get_lod_max_distance);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_lod_min_hysteresis", "mode"), &GeometryInstance::set_lod_min_hysteresis);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_lod_min_hysteresis"), &GeometryInstance::get_lod_min_hysteresis);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance::set_lod_min_distance);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance::get_lod_min_distance);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin);
|
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin);
|
||||||
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
|
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
|
||||||
|
|
||||||
|
@ -397,12 +349,6 @@ void GeometryInstance::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_lightmap"), "set_generate_lightmap", "get_generate_lightmap");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_lightmap"), "set_generate_lightmap", "get_generate_lightmap");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
|
||||||
|
|
||||||
ADD_GROUP("LOD", "lod_");
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance");
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_hysteresis", "get_lod_min_hysteresis");
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_distance", "get_lod_max_distance");
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_hysteresis", "get_lod_max_hysteresis");
|
|
||||||
|
|
||||||
//ADD_SIGNAL( MethodInfo("visibility_changed"));
|
//ADD_SIGNAL( MethodInfo("visibility_changed"));
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_1X);
|
BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_1X);
|
||||||
|
@ -422,11 +368,6 @@ void GeometryInstance::_bind_methods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryInstance::GeometryInstance() {
|
GeometryInstance::GeometryInstance() {
|
||||||
lod_min_distance = 0;
|
|
||||||
lod_max_distance = 0;
|
|
||||||
lod_min_hysteresis = 0;
|
|
||||||
lod_max_hysteresis = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < FLAG_MAX; i++) {
|
for (int i = 0; i < FLAG_MAX; i++) {
|
||||||
flags[i] = false;
|
flags[i] = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,10 +121,6 @@ private:
|
||||||
ShadowCastingSetting shadow_casting_setting;
|
ShadowCastingSetting shadow_casting_setting;
|
||||||
Ref<Material> material_override;
|
Ref<Material> material_override;
|
||||||
Ref<Material> material_overlay;
|
Ref<Material> material_overlay;
|
||||||
float lod_min_distance;
|
|
||||||
float lod_max_distance;
|
|
||||||
float lod_min_hysteresis;
|
|
||||||
float lod_max_hysteresis;
|
|
||||||
|
|
||||||
float extra_cull_margin;
|
float extra_cull_margin;
|
||||||
|
|
||||||
|
@ -145,18 +141,6 @@ public:
|
||||||
void set_lightmap_scale(LightmapScale p_scale);
|
void set_lightmap_scale(LightmapScale p_scale);
|
||||||
LightmapScale get_lightmap_scale() const;
|
LightmapScale get_lightmap_scale() const;
|
||||||
|
|
||||||
void set_lod_min_distance(float p_dist);
|
|
||||||
float get_lod_min_distance() const;
|
|
||||||
|
|
||||||
void set_lod_max_distance(float p_dist);
|
|
||||||
float get_lod_max_distance() const;
|
|
||||||
|
|
||||||
void set_lod_min_hysteresis(float p_dist);
|
|
||||||
float get_lod_min_hysteresis() const;
|
|
||||||
|
|
||||||
void set_lod_max_hysteresis(float p_dist);
|
|
||||||
float get_lod_max_hysteresis() const;
|
|
||||||
|
|
||||||
virtual void set_material_override(const Ref<Material> &p_material);
|
virtual void set_material_override(const Ref<Material> &p_material);
|
||||||
Ref<Material> get_material_override() const;
|
Ref<Material> get_material_override() const;
|
||||||
|
|
||||||
|
|
|
@ -194,6 +194,7 @@
|
||||||
#include "scene/3d/label_3d.h"
|
#include "scene/3d/label_3d.h"
|
||||||
#include "scene/3d/light.h"
|
#include "scene/3d/light.h"
|
||||||
#include "scene/3d/listener.h"
|
#include "scene/3d/listener.h"
|
||||||
|
#include "scene/3d/lod.h"
|
||||||
#include "scene/3d/merge_group.h"
|
#include "scene/3d/merge_group.h"
|
||||||
#include "scene/3d/mesh_instance.h"
|
#include "scene/3d/mesh_instance.h"
|
||||||
#include "scene/3d/multimesh_instance.h"
|
#include "scene/3d/multimesh_instance.h"
|
||||||
|
@ -441,6 +442,7 @@ void register_scene_types() {
|
||||||
ClassDB::register_class<ARVROrigin>();
|
ClassDB::register_class<ARVROrigin>();
|
||||||
ClassDB::register_class<InterpolatedCamera>();
|
ClassDB::register_class<InterpolatedCamera>();
|
||||||
ClassDB::register_class<MeshInstance>();
|
ClassDB::register_class<MeshInstance>();
|
||||||
|
ClassDB::register_class<LOD>();
|
||||||
ClassDB::register_class<ImmediateGeometry>();
|
ClassDB::register_class<ImmediateGeometry>();
|
||||||
ClassDB::register_virtual_class<SpriteBase3D>();
|
ClassDB::register_virtual_class<SpriteBase3D>();
|
||||||
ClassDB::register_class<Sprite3D>();
|
ClassDB::register_class<Sprite3D>();
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "core/math/camera_matrix.h"
|
#include "core/math/camera_matrix.h"
|
||||||
#include "core/math/octree.h"
|
#include "core/math/octree.h"
|
||||||
#include "scene/3d/camera.h"
|
#include "scene/3d/camera.h"
|
||||||
|
#include "scene/3d/lod_manager.h"
|
||||||
#include "scene/3d/visibility_notifier.h"
|
#include "scene/3d/visibility_notifier.h"
|
||||||
#include "scene/scene_string_names.h"
|
#include "scene/scene_string_names.h"
|
||||||
#include "servers/navigation_server.h"
|
#include "servers/navigation_server.h"
|
||||||
|
@ -216,6 +217,7 @@ struct SpatialIndexer {
|
||||||
void World::_register_camera(Camera *p_camera) {
|
void World::_register_camera(Camera *p_camera) {
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
indexer->_add_camera(p_camera);
|
indexer->_add_camera(p_camera);
|
||||||
|
lod_manager->register_camera(p_camera);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +229,19 @@ void World::_update_camera(Camera *p_camera) {
|
||||||
void World::_remove_camera(Camera *p_camera) {
|
void World::_remove_camera(Camera *p_camera) {
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
indexer->_remove_camera(p_camera);
|
indexer->_remove_camera(p_camera);
|
||||||
|
lod_manager->remove_camera(p_camera);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::_register_lod(LOD *p_lod, uint32_t p_queue_id) {
|
||||||
|
#ifndef _3D_DISABLED
|
||||||
|
lod_manager->register_lod(p_lod, p_queue_id);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::_unregister_lod(LOD *p_lod, uint32_t p_queue_id) {
|
||||||
|
#ifndef _3D_DISABLED
|
||||||
|
lod_manager->unregister_lod(p_lod, p_queue_id);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +266,7 @@ void World::_remove_notifier(VisibilityNotifier *p_notifier) {
|
||||||
void World::_update(uint64_t p_frame) {
|
void World::_update(uint64_t p_frame) {
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
indexer->_update(p_frame);
|
indexer->_update(p_frame);
|
||||||
|
lod_manager->update();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,6 +330,12 @@ void World::get_camera_list(List<Camera *> *r_cameras) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::notify_saving(bool p_active) {
|
||||||
|
if (lod_manager) {
|
||||||
|
lod_manager->notify_saving(p_active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void World::_bind_methods() {
|
void World::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_space"), &World::get_space);
|
ClassDB::bind_method(D_METHOD("get_space"), &World::get_space);
|
||||||
ClassDB::bind_method(D_METHOD("get_scenario"), &World::get_scenario);
|
ClassDB::bind_method(D_METHOD("get_scenario"), &World::get_scenario);
|
||||||
|
@ -355,6 +377,7 @@ World::World() {
|
||||||
indexer = NULL;
|
indexer = NULL;
|
||||||
#else
|
#else
|
||||||
indexer = memnew(SpatialIndexer);
|
indexer = memnew(SpatialIndexer);
|
||||||
|
lod_manager = memnew(LODManager);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,5 +388,7 @@ World::~World() {
|
||||||
|
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
memdelete(indexer);
|
memdelete(indexer);
|
||||||
|
memdelete(lod_manager);
|
||||||
|
lod_manager = nullptr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,9 @@
|
||||||
|
|
||||||
class Camera;
|
class Camera;
|
||||||
class VisibilityNotifier;
|
class VisibilityNotifier;
|
||||||
|
class LOD;
|
||||||
struct SpatialIndexer;
|
struct SpatialIndexer;
|
||||||
|
class LODManager;
|
||||||
|
|
||||||
class World : public Resource {
|
class World : public Resource {
|
||||||
GDCLASS(World, Resource);
|
GDCLASS(World, Resource);
|
||||||
|
@ -50,6 +52,7 @@ private:
|
||||||
RID navigation_map;
|
RID navigation_map;
|
||||||
|
|
||||||
SpatialIndexer *indexer;
|
SpatialIndexer *indexer;
|
||||||
|
LODManager *lod_manager = nullptr;
|
||||||
Ref<Environment> environment;
|
Ref<Environment> environment;
|
||||||
Ref<Environment> fallback_environment;
|
Ref<Environment> fallback_environment;
|
||||||
|
|
||||||
|
@ -58,6 +61,7 @@ protected:
|
||||||
|
|
||||||
friend class Camera;
|
friend class Camera;
|
||||||
friend class VisibilityNotifier;
|
friend class VisibilityNotifier;
|
||||||
|
friend class LOD;
|
||||||
|
|
||||||
void _register_camera(Camera *p_camera);
|
void _register_camera(Camera *p_camera);
|
||||||
void _update_camera(Camera *p_camera);
|
void _update_camera(Camera *p_camera);
|
||||||
|
@ -66,6 +70,10 @@ protected:
|
||||||
void _register_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect);
|
void _register_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect);
|
||||||
void _update_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect);
|
void _update_notifier(VisibilityNotifier *p_notifier, const AABB &p_rect);
|
||||||
void _remove_notifier(VisibilityNotifier *p_notifier);
|
void _remove_notifier(VisibilityNotifier *p_notifier);
|
||||||
|
|
||||||
|
void _register_lod(LOD *p_lod, uint32_t p_queue_id);
|
||||||
|
void _unregister_lod(LOD *p_lod, uint32_t p_queue_id);
|
||||||
|
|
||||||
friend class Viewport;
|
friend class Viewport;
|
||||||
void _update(uint64_t p_frame);
|
void _update(uint64_t p_frame);
|
||||||
|
|
||||||
|
@ -84,6 +92,8 @@ public:
|
||||||
|
|
||||||
PhysicsDirectSpaceState *get_direct_space_state();
|
PhysicsDirectSpaceState *get_direct_space_state();
|
||||||
|
|
||||||
|
void notify_saving(bool p_active);
|
||||||
|
|
||||||
World();
|
World();
|
||||||
~World();
|
~World();
|
||||||
};
|
};
|
||||||
|
|
|
@ -658,9 +658,6 @@ public:
|
||||||
BIND2(instance_geometry_set_material_override, RID, RID)
|
BIND2(instance_geometry_set_material_override, RID, RID)
|
||||||
BIND2(instance_geometry_set_material_overlay, RID, RID)
|
BIND2(instance_geometry_set_material_overlay, RID, RID)
|
||||||
|
|
||||||
BIND5(instance_geometry_set_draw_range, RID, float, float, float, float)
|
|
||||||
BIND2(instance_geometry_set_as_instance_lod, RID, RID)
|
|
||||||
|
|
||||||
#undef BINDBASE
|
#undef BINDBASE
|
||||||
//from now on, calls forwarded to this singleton
|
//from now on, calls forwarded to this singleton
|
||||||
#define BINDBASE VSG::canvas
|
#define BINDBASE VSG::canvas
|
||||||
|
|
|
@ -2027,11 +2027,6 @@ void VisualServerScene::instance_geometry_set_material_overlay(RID p_instance, R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
|
|
||||||
}
|
|
||||||
void VisualServerScene::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualServerScene::_update_instance(Instance *p_instance) {
|
void VisualServerScene::_update_instance(Instance *p_instance) {
|
||||||
p_instance->version++;
|
p_instance->version++;
|
||||||
|
|
||||||
|
|
|
@ -892,9 +892,6 @@ public:
|
||||||
virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
|
virtual void instance_geometry_set_material_override(RID p_instance, RID p_material);
|
||||||
virtual void instance_geometry_set_material_overlay(RID p_instance, RID p_material);
|
virtual void instance_geometry_set_material_overlay(RID p_instance, RID p_material);
|
||||||
|
|
||||||
virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin);
|
|
||||||
virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance);
|
|
||||||
|
|
||||||
_FORCE_INLINE_ void _update_instance(Instance *p_instance);
|
_FORCE_INLINE_ void _update_instance(Instance *p_instance);
|
||||||
_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
|
_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
|
||||||
_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
|
_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
|
||||||
|
|
|
@ -566,9 +566,6 @@ public:
|
||||||
FUNC2(instance_geometry_set_material_override, RID, RID)
|
FUNC2(instance_geometry_set_material_override, RID, RID)
|
||||||
FUNC2(instance_geometry_set_material_overlay, RID, RID)
|
FUNC2(instance_geometry_set_material_overlay, RID, RID)
|
||||||
|
|
||||||
FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float)
|
|
||||||
FUNC2(instance_geometry_set_as_instance_lod, RID, RID)
|
|
||||||
|
|
||||||
/* CANVAS (2D) */
|
/* CANVAS (2D) */
|
||||||
|
|
||||||
FUNCRID(canvas)
|
FUNCRID(canvas)
|
||||||
|
|
|
@ -2188,8 +2188,6 @@ void VisualServer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &VisualServer::instance_geometry_set_cast_shadows_setting);
|
ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &VisualServer::instance_geometry_set_cast_shadows_setting);
|
||||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &VisualServer::instance_geometry_set_material_override);
|
ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &VisualServer::instance_geometry_set_material_override);
|
||||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_material_overlay", "instance", "material"), &VisualServer::instance_geometry_set_material_overlay);
|
ClassDB::bind_method(D_METHOD("instance_geometry_set_material_overlay", "instance", "material"), &VisualServer::instance_geometry_set_material_overlay);
|
||||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_draw_range", "instance", "min", "max", "min_margin", "max_margin"), &VisualServer::instance_geometry_set_draw_range);
|
|
||||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_as_instance_lod", "instance", "as_lod_of_instance"), &VisualServer::instance_geometry_set_as_instance_lod);
|
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &VisualServer::_instances_cull_aabb_bind, DEFVAL(RID()));
|
ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &VisualServer::_instances_cull_aabb_bind, DEFVAL(RID()));
|
||||||
ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &VisualServer::_instances_cull_ray_bind, DEFVAL(RID()));
|
ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &VisualServer::_instances_cull_ray_bind, DEFVAL(RID()));
|
||||||
|
|
|
@ -1001,9 +1001,6 @@ public:
|
||||||
virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0;
|
virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0;
|
||||||
virtual void instance_geometry_set_material_overlay(RID p_instance, RID p_material) = 0;
|
virtual void instance_geometry_set_material_overlay(RID p_instance, RID p_material) = 0;
|
||||||
|
|
||||||
virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
|
|
||||||
virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0;
|
|
||||||
|
|
||||||
/* CANVAS (2D) */
|
/* CANVAS (2D) */
|
||||||
|
|
||||||
virtual RID canvas_create() = 0;
|
virtual RID canvas_create() = 0;
|
||||||
|
|
Loading…
Reference in a new issue