Implement visibility range and dependencies.
This commit adds the following properties to GeometryInstance3D: `visibility_range_begin`, `visibility_range_begin_margin`, `visibility_range_end`, `visibility_range_end_margin`. Together they define a range in which the GeometryInstance3D will be visible from the camera, taking hysteresis into account for state changes. A begin or end value of 0 will be ignored, so the visibility range can be open-ended in both directions. This commit also adds the `visibility_parent` property to 'Node3D'. Which defines the visibility parents of the node and its subtree (until another parent is defined). Visual instances with a visibility parent will only be visible when the parent, and all of its ancestors recursively, are hidden because they are closer to the camera than their respective `visibility_range_begin` thresholds. Combining visibility ranges and visibility parents users can set-up a quick HLOD system that shows high detail meshes when close (i.e buildings, trees) and merged low detail meshes for far away groups (i.e. cities, woods).
This commit is contained in:
parent
12e0f10c74
commit
3a53ae5d9f
15 changed files with 918 additions and 305 deletions
181
core/templates/bin_sorted_array.h
Normal file
181
core/templates/bin_sorted_array.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*************************************************************************/
|
||||
/* bin_sorted_array.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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 BIN_SORTED_ARRAY_H
|
||||
#define BIN_SORTED_ARRAY_H
|
||||
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "core/templates/paged_array.h"
|
||||
|
||||
template <class T>
|
||||
class BinSortedArray {
|
||||
PagedArray<T> array;
|
||||
LocalVector<uint64_t> bin_limits;
|
||||
|
||||
// Implement if elements need to keep track of their own index in the array.
|
||||
_FORCE_INLINE_ virtual void _update_idx(T &r_element, uint64_t p_idx) {}
|
||||
|
||||
_FORCE_INLINE_ void _swap(uint64_t p_a, uint64_t p_b) {
|
||||
SWAP(array[p_a], array[p_b]);
|
||||
_update_idx(array[p_a], p_a);
|
||||
_update_idx(array[p_b], p_b);
|
||||
}
|
||||
|
||||
public:
|
||||
uint64_t insert(T &p_element, uint64_t p_bin) {
|
||||
array.push_back(p_element);
|
||||
uint64_t new_idx = array.size() - 1;
|
||||
_update_idx(p_element, new_idx);
|
||||
bin_limits[0] = new_idx;
|
||||
if (p_bin != 0) {
|
||||
new_idx = move(new_idx, p_bin);
|
||||
}
|
||||
return new_idx;
|
||||
}
|
||||
|
||||
uint64_t move(uint64_t p_idx, uint64_t p_bin) {
|
||||
ERR_FAIL_COND_V(p_idx >= array.size(), -1);
|
||||
|
||||
uint64_t current_bin = bin_limits.size() - 1;
|
||||
while (p_idx > bin_limits[current_bin]) {
|
||||
current_bin--;
|
||||
}
|
||||
|
||||
if (p_bin == current_bin) {
|
||||
return p_idx;
|
||||
}
|
||||
|
||||
uint64_t current_idx = p_idx;
|
||||
if (p_bin > current_bin) {
|
||||
while (p_bin > current_bin) {
|
||||
uint64_t swap_idx = 0;
|
||||
|
||||
if (current_bin == bin_limits.size() - 1) {
|
||||
bin_limits.push_back(0);
|
||||
} else {
|
||||
bin_limits[current_bin + 1]++;
|
||||
swap_idx = bin_limits[current_bin + 1];
|
||||
}
|
||||
|
||||
if (current_idx != swap_idx) {
|
||||
_swap(current_idx, swap_idx);
|
||||
current_idx = swap_idx;
|
||||
}
|
||||
|
||||
current_bin++;
|
||||
}
|
||||
} else {
|
||||
while (p_bin < current_bin) {
|
||||
uint64_t swap_idx = bin_limits[current_bin];
|
||||
|
||||
if (current_idx != swap_idx) {
|
||||
_swap(current_idx, swap_idx);
|
||||
}
|
||||
|
||||
if (current_bin == bin_limits.size() - 1 && bin_limits[current_bin] == 0) {
|
||||
bin_limits.resize(bin_limits.size() - 1);
|
||||
} else {
|
||||
bin_limits[current_bin]--;
|
||||
}
|
||||
current_idx = swap_idx;
|
||||
current_bin--;
|
||||
}
|
||||
}
|
||||
|
||||
return current_idx;
|
||||
}
|
||||
|
||||
void remove(uint64_t p_idx) {
|
||||
ERR_FAIL_COND(p_idx >= array.size());
|
||||
uint64_t new_idx = move(p_idx, 0);
|
||||
uint64_t swap_idx = array.size() - 1;
|
||||
|
||||
if (new_idx != swap_idx) {
|
||||
_swap(new_idx, swap_idx);
|
||||
}
|
||||
|
||||
if (bin_limits[0] > 0) {
|
||||
bin_limits[0]--;
|
||||
}
|
||||
|
||||
array.pop_back();
|
||||
}
|
||||
|
||||
void set_page_pool(PagedArrayPool<T> *p_page_pool) {
|
||||
array.set_page_pool(p_page_pool);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ const T &operator[](uint64_t p_index) const {
|
||||
return array[p_index];
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ T &operator[](uint64_t p_index) {
|
||||
return array[p_index];
|
||||
}
|
||||
|
||||
int get_bin_count() {
|
||||
if (array.size() == 0) {
|
||||
return 0;
|
||||
}
|
||||
return bin_limits.size();
|
||||
}
|
||||
|
||||
int get_bin_start(int p_bin) {
|
||||
ERR_FAIL_COND_V(p_bin >= get_bin_count(), ~0U);
|
||||
if ((unsigned int)p_bin == bin_limits.size() - 1) {
|
||||
return 0;
|
||||
}
|
||||
return bin_limits[p_bin + 1] + 1;
|
||||
}
|
||||
|
||||
int get_bin_size(int p_bin) {
|
||||
ERR_FAIL_COND_V(p_bin >= get_bin_count(), 0);
|
||||
if ((unsigned int)p_bin == bin_limits.size() - 1) {
|
||||
return bin_limits[p_bin] + 1;
|
||||
}
|
||||
return bin_limits[p_bin] - bin_limits[p_bin + 1];
|
||||
}
|
||||
|
||||
void reset() {
|
||||
array.reset();
|
||||
bin_limits.clear();
|
||||
bin_limits.push_back(0);
|
||||
}
|
||||
|
||||
BinSortedArray() {
|
||||
bin_limits.push_back(0);
|
||||
}
|
||||
|
||||
virtual ~BinSortedArray() {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
#endif //BIN_SORTED_ARRAY_H
|
|
@ -52,26 +52,22 @@
|
|||
</member>
|
||||
<member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias" default="1.0">
|
||||
</member>
|
||||
<member name="lod_max_distance" type="float" setter="set_lod_max_distance" getter="get_lod_max_distance" default="0.0">
|
||||
The GeometryInstance3D'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 GeometryInstance3D'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 GeometryInstance3D'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 GeometryInstance3D's min LOD margin.
|
||||
[b]Note:[/b] This property currently has no effect.
|
||||
</member>
|
||||
<member name="material_override" type="Material" setter="set_material_override" getter="get_material_override">
|
||||
The material override for the whole geometry.
|
||||
If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh.
|
||||
</member>
|
||||
<member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin" default="0.0">
|
||||
Starting distance from which the GeometryInstance3D will be visible, taking [member visibility_range_begin_margin] into account as well. The default value of 0 is used to disable the range check.
|
||||
</member>
|
||||
<member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin" default="0.0">
|
||||
Margin for the [member visibility_range_begin] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_begin] threshold by this amount.
|
||||
</member>
|
||||
<member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end" default="0.0">
|
||||
Distance from which the GeometryInstance3D will be hidden, taking [member visibility_range_end_margin] into account as well. The default value of 0 is used to disable the range check..
|
||||
</member>
|
||||
<member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin" default="0.0">
|
||||
Margin for the [member visibility_range_end] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_end] threshold by this amount.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">
|
||||
|
|
|
@ -310,6 +310,9 @@
|
|||
<member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )">
|
||||
Local space [Transform3D] of this node, with respect to the parent node.
|
||||
</member>
|
||||
<member name="visibility_parent" type="NodePath" setter="set_visibility_parent" getter="get_visibility_parent" default="NodePath("")">
|
||||
Defines the visibility range parent for this node and its subtree. The visibility parent must be a GeometryInstance3D. Any visual instance will only be visible if the visibility parent (and all of its visibility ancestors) is hidden by being closer to the camera than its own [member GeometryInstance3D.visibility_range_begin]. Nodes hidden via the [member Node3D.visible] property are essentially removed from the visibility dependency tree, so dependant instances will not take the hidden node or its ancestors into account.
|
||||
</member>
|
||||
<member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true">
|
||||
If [code]true[/code], this node is drawn. The node is only visible if all of its antecedents are visible as well (in other words, [method is_visible_in_tree] must return [code]true[/code]).
|
||||
</member>
|
||||
|
|
|
@ -1175,17 +1175,6 @@
|
|||
Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_geometry_set_as_instance_lod">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="instance" type="RID">
|
||||
</argument>
|
||||
<argument index="1" name="as_lod_of_instance" type="RID">
|
||||
</argument>
|
||||
<description>
|
||||
Not implemented in Godot 3.x.
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_geometry_set_cast_shadows_setting">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -1197,23 +1186,6 @@
|
|||
Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance3D.cast_shadow].
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_geometry_set_draw_range">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="instance" type="RID">
|
||||
</argument>
|
||||
<argument index="1" name="min" type="float">
|
||||
</argument>
|
||||
<argument index="2" name="max" type="float">
|
||||
</argument>
|
||||
<argument index="3" name="min_margin" type="float">
|
||||
</argument>
|
||||
<argument index="4" name="max_margin" type="float">
|
||||
</argument>
|
||||
<description>
|
||||
Not implemented in Godot 3.x.
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_geometry_set_flag">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -1238,6 +1210,23 @@
|
|||
Sets a material that will override the material for all surfaces on the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_override].
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_geometry_set_visibility_range">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="instance" type="RID">
|
||||
</argument>
|
||||
<argument index="1" name="min" type="float">
|
||||
</argument>
|
||||
<argument index="2" name="max" type="float">
|
||||
</argument>
|
||||
<argument index="3" name="min_margin" type="float">
|
||||
</argument>
|
||||
<argument index="4" name="max_margin" type="float">
|
||||
</argument>
|
||||
<description>
|
||||
Sets the visibility range values for the given geometry instance. Equivalent to [member GeometryInstance3D.visibility_range_begin] and related properties.
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_set_base">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -1341,6 +1330,17 @@
|
|||
Sets the world space transform of the instance. Equivalent to [member Node3D.transform].
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_set_visibility_parent">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="instance" type="RID">
|
||||
</argument>
|
||||
<argument index="1" name="parent" type="RID">
|
||||
</argument>
|
||||
<description>
|
||||
Sets the visibility parent for the given instance. Equivalent to [member Node3D.visibility_parent].
|
||||
</description>
|
||||
</method>
|
||||
<method name="instance_set_visible">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/object/message_queue.h"
|
||||
#include "scene/3d/visual_instance_3d.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/scene_string_names.h"
|
||||
|
@ -148,6 +149,7 @@ void Node3D::_notification(int p_what) {
|
|||
_notify_dirty();
|
||||
|
||||
notification(NOTIFICATION_ENTER_WORLD);
|
||||
_update_visibility_parent(true);
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
|
@ -161,6 +163,7 @@ void Node3D::_notification(int p_what) {
|
|||
data.parent = nullptr;
|
||||
data.C = nullptr;
|
||||
data.top_level_active = false;
|
||||
_update_visibility_parent(true);
|
||||
} break;
|
||||
case NOTIFICATION_ENTER_WORLD: {
|
||||
data.inside_world = true;
|
||||
|
@ -690,6 +693,51 @@ void Node3D::force_update_transform() {
|
|||
notification(NOTIFICATION_TRANSFORM_CHANGED);
|
||||
}
|
||||
|
||||
void Node3D::_update_visibility_parent(bool p_update_root) {
|
||||
RID new_parent;
|
||||
|
||||
if (!visibility_parent_path.is_empty()) {
|
||||
if (!p_update_root) {
|
||||
return;
|
||||
}
|
||||
Node *parent = get_node_or_null(visibility_parent_path);
|
||||
ERR_FAIL_COND_MSG(!parent, "Can't find visibility parent node at path: " + visibility_parent_path);
|
||||
ERR_FAIL_COND_MSG(parent == this, "The visibility parent can't be the same node.");
|
||||
GeometryInstance3D *gi = Object::cast_to<GeometryInstance3D>(parent);
|
||||
ERR_FAIL_COND_MSG(!gi, "The visibility parent node must be a GeometryInstance3D, at path: " + visibility_parent_path);
|
||||
new_parent = gi ? gi->get_instance() : RID();
|
||||
} else if (data.parent) {
|
||||
new_parent = data.parent->data.visibility_parent;
|
||||
}
|
||||
|
||||
if (new_parent == data.visibility_parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.visibility_parent = new_parent;
|
||||
|
||||
VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(this);
|
||||
if (vi) {
|
||||
RS::get_singleton()->instance_set_visibility_parent(vi->get_instance(), data.visibility_parent);
|
||||
}
|
||||
|
||||
for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) {
|
||||
Node3D *c = E->get();
|
||||
c->_update_visibility_parent(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Node3D::set_visibility_parent(const NodePath &p_path) {
|
||||
visibility_parent_path = p_path;
|
||||
if (is_inside_tree()) {
|
||||
_update_visibility_parent(true);
|
||||
}
|
||||
}
|
||||
|
||||
NodePath Node3D::get_visibility_parent() const {
|
||||
return visibility_parent_path;
|
||||
}
|
||||
|
||||
void Node3D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_transform", "local"), &Node3D::set_transform);
|
||||
ClassDB::bind_method(D_METHOD("get_transform"), &Node3D::get_transform);
|
||||
|
@ -713,6 +761,9 @@ void Node3D::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("force_update_transform"), &Node3D::force_update_transform);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_visibility_parent", "path"), &Node3D::set_visibility_parent);
|
||||
ClassDB::bind_method(D_METHOD("get_visibility_parent"), &Node3D::get_visibility_parent);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_update_gizmo"), &Node3D::_update_gizmo);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("update_gizmo"), &Node3D::update_gizmo);
|
||||
|
@ -768,6 +819,7 @@ void Node3D::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
|
||||
ADD_GROUP("Visibility", "");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "Node3DGizmo", 0), "set_gizmo", "get_gizmo");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("visibility_changed"));
|
||||
|
|
|
@ -75,6 +75,8 @@ class Node3D : public Node {
|
|||
bool top_level = false;
|
||||
bool inside_world = false;
|
||||
|
||||
RID visibility_parent;
|
||||
|
||||
int children_lock = 0;
|
||||
Node3D *parent = nullptr;
|
||||
List<Node3D *> children;
|
||||
|
@ -95,12 +97,17 @@ class Node3D : public Node {
|
|||
|
||||
} data;
|
||||
|
||||
NodePath visibility_parent_path;
|
||||
|
||||
void _update_gizmo();
|
||||
void _notify_dirty();
|
||||
void _propagate_transform_changed(Node3D *p_origin);
|
||||
|
||||
void _propagate_visibility_changed();
|
||||
|
||||
void _propagate_visibility_parent();
|
||||
void _update_visibility_parent(bool p_update_root);
|
||||
|
||||
protected:
|
||||
_FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; }
|
||||
|
||||
|
@ -196,6 +203,9 @@ public:
|
|||
|
||||
void force_update_transform();
|
||||
|
||||
void set_visibility_parent(const NodePath &p_path);
|
||||
NodePath get_visibility_parent() const;
|
||||
|
||||
Node3D();
|
||||
};
|
||||
|
||||
|
|
|
@ -150,40 +150,40 @@ Ref<Material> GeometryInstance3D::get_material_override() const {
|
|||
return material_override;
|
||||
}
|
||||
|
||||
void GeometryInstance3D::set_lod_min_distance(float p_dist) {
|
||||
lod_min_distance = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
||||
void GeometryInstance3D::set_visibility_range_begin(float p_dist) {
|
||||
visibility_range_begin = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
|
||||
}
|
||||
|
||||
float GeometryInstance3D::get_lod_min_distance() const {
|
||||
return lod_min_distance;
|
||||
float GeometryInstance3D::get_visibility_range_begin() const {
|
||||
return visibility_range_begin;
|
||||
}
|
||||
|
||||
void GeometryInstance3D::set_lod_max_distance(float p_dist) {
|
||||
lod_max_distance = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
||||
void GeometryInstance3D::set_visibility_range_end(float p_dist) {
|
||||
visibility_range_end = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
|
||||
}
|
||||
|
||||
float GeometryInstance3D::get_lod_max_distance() const {
|
||||
return lod_max_distance;
|
||||
float GeometryInstance3D::get_visibility_range_end() const {
|
||||
return visibility_range_end;
|
||||
}
|
||||
|
||||
void GeometryInstance3D::set_lod_min_hysteresis(float p_dist) {
|
||||
lod_min_hysteresis = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
||||
void GeometryInstance3D::set_visibility_range_begin_margin(float p_dist) {
|
||||
visibility_range_begin_margin = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
|
||||
}
|
||||
|
||||
float GeometryInstance3D::get_lod_min_hysteresis() const {
|
||||
return lod_min_hysteresis;
|
||||
float GeometryInstance3D::get_visibility_range_begin_margin() const {
|
||||
return visibility_range_begin_margin;
|
||||
}
|
||||
|
||||
void GeometryInstance3D::set_lod_max_hysteresis(float p_dist) {
|
||||
lod_max_hysteresis = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis);
|
||||
void GeometryInstance3D::set_visibility_range_end_margin(float p_dist) {
|
||||
visibility_range_end_margin = p_dist;
|
||||
RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin);
|
||||
}
|
||||
|
||||
float GeometryInstance3D::get_lod_max_hysteresis() const {
|
||||
return lod_max_hysteresis;
|
||||
float GeometryInstance3D::get_visibility_range_end_margin() const {
|
||||
return visibility_range_end_margin;
|
||||
}
|
||||
|
||||
void GeometryInstance3D::_notification(int p_what) {
|
||||
|
@ -357,17 +357,17 @@ void GeometryInstance3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias);
|
||||
ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_lod_max_hysteresis", "mode"), &GeometryInstance3D::set_lod_max_hysteresis);
|
||||
ClassDB::bind_method(D_METHOD("get_lod_max_hysteresis"), &GeometryInstance3D::get_lod_max_hysteresis);
|
||||
ClassDB::bind_method(D_METHOD("set_visibility_range_end_margin", "distance"), &GeometryInstance3D::set_visibility_range_end_margin);
|
||||
ClassDB::bind_method(D_METHOD("get_visibility_range_end_margin"), &GeometryInstance3D::get_visibility_range_end_margin);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_lod_max_distance", "mode"), &GeometryInstance3D::set_lod_max_distance);
|
||||
ClassDB::bind_method(D_METHOD("get_lod_max_distance"), &GeometryInstance3D::get_lod_max_distance);
|
||||
ClassDB::bind_method(D_METHOD("set_visibility_range_end", "distance"), &GeometryInstance3D::set_visibility_range_end);
|
||||
ClassDB::bind_method(D_METHOD("get_visibility_range_end"), &GeometryInstance3D::get_visibility_range_end);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_lod_min_hysteresis", "mode"), &GeometryInstance3D::set_lod_min_hysteresis);
|
||||
ClassDB::bind_method(D_METHOD("get_lod_min_hysteresis"), &GeometryInstance3D::get_lod_min_hysteresis);
|
||||
ClassDB::bind_method(D_METHOD("set_visibility_range_begin_margin", "distance"), &GeometryInstance3D::set_visibility_range_begin_margin);
|
||||
ClassDB::bind_method(D_METHOD("get_visibility_range_begin_margin"), &GeometryInstance3D::get_visibility_range_begin_margin);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance3D::set_lod_min_distance);
|
||||
ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance3D::get_lod_min_distance);
|
||||
ClassDB::bind_method(D_METHOD("set_visibility_range_begin", "distance"), &GeometryInstance3D::set_visibility_range_begin);
|
||||
ClassDB::bind_method(D_METHOD("get_visibility_range_begin"), &GeometryInstance3D::get_visibility_range_begin);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
|
||||
ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
|
||||
|
@ -398,11 +398,11 @@ void GeometryInstance3D::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_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_GROUP("Visibility Range", "visibility_range_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin", "get_visibility_range_begin");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin_margin", "get_visibility_range_begin_margin");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end", "get_visibility_range_end");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end_margin", "get_visibility_range_end_margin");
|
||||
|
||||
//ADD_SIGNAL( MethodInfo("visibility_changed"));
|
||||
|
||||
|
|
|
@ -107,10 +107,13 @@ public:
|
|||
private:
|
||||
ShadowCastingSetting shadow_casting_setting = SHADOW_CASTING_SETTING_ON;
|
||||
Ref<Material> material_override;
|
||||
float lod_min_distance = 0.0;
|
||||
float lod_max_distance = 0.0;
|
||||
float lod_min_hysteresis = 0.0;
|
||||
float lod_max_hysteresis = 0.0;
|
||||
|
||||
float visibility_range_begin = 0.0;
|
||||
float visibility_range_end = 0.0;
|
||||
float visibility_range_begin_margin = 0.0;
|
||||
float visibility_range_end_margin = 0.0;
|
||||
|
||||
Vector<NodePath> visibility_range_children;
|
||||
|
||||
float lod_bias = 1.0;
|
||||
|
||||
|
@ -136,17 +139,20 @@ public:
|
|||
void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting);
|
||||
ShadowCastingSetting get_cast_shadows_setting() const;
|
||||
|
||||
void set_lod_min_distance(float p_dist);
|
||||
float get_lod_min_distance() const;
|
||||
void set_visibility_range_begin(float p_dist);
|
||||
float get_visibility_range_begin() const;
|
||||
|
||||
void set_lod_max_distance(float p_dist);
|
||||
float get_lod_max_distance() const;
|
||||
void set_visibility_range_end(float p_dist);
|
||||
float get_visibility_range_end() const;
|
||||
|
||||
void set_lod_min_hysteresis(float p_dist);
|
||||
float get_lod_min_hysteresis() const;
|
||||
void set_visibility_range_begin_margin(float p_dist);
|
||||
float get_visibility_range_begin_margin() const;
|
||||
|
||||
void set_lod_max_hysteresis(float p_dist);
|
||||
float get_lod_max_hysteresis() const;
|
||||
void set_visibility_range_end_margin(float p_dist);
|
||||
float get_visibility_range_end_margin() const;
|
||||
|
||||
void set_visibility_range_parent(const Node *p_parent);
|
||||
void clear_visibility_range_parent();
|
||||
|
||||
void set_material_override(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material_override() const;
|
||||
|
|
|
@ -63,6 +63,8 @@ public:
|
|||
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) = 0;
|
||||
virtual bool is_scenario(RID p_scenario) const = 0;
|
||||
virtual RID scenario_get_environment(RID p_scenario) = 0;
|
||||
virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0;
|
||||
virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0;
|
||||
|
||||
virtual RID instance_allocate() = 0;
|
||||
virtual void instance_initialize(RID p_rid) = 0;
|
||||
|
@ -82,6 +84,7 @@ public:
|
|||
virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0;
|
||||
|
||||
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0;
|
||||
virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0;
|
||||
|
||||
// don't use these in a game!
|
||||
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
|
||||
|
@ -92,8 +95,7 @@ public:
|
|||
virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) = 0;
|
||||
virtual void instance_geometry_set_material_override(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;
|
||||
virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
|
||||
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0;
|
||||
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0;
|
||||
|
||||
|
|
|
@ -323,6 +323,7 @@ void RendererSceneCull::scenario_initialize(RID p_rid) {
|
|||
|
||||
scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool);
|
||||
scenario->instance_data.set_page_pool(&instance_data_page_pool);
|
||||
scenario->instance_visibility.set_page_pool(&instance_visibility_data_page_pool);
|
||||
|
||||
RendererSceneOcclusionCull::get_singleton()->add_scenario(p_rid);
|
||||
|
||||
|
@ -369,6 +370,37 @@ RID RendererSceneCull::scenario_get_environment(RID p_scenario) {
|
|||
return scenario->environment;
|
||||
}
|
||||
|
||||
void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
|
||||
Scenario *scenario = scenario_owner.getornull(p_scenario);
|
||||
ERR_FAIL_COND(!scenario);
|
||||
if (!scenario->viewport_visibility_masks.has(p_viewport)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t mask = scenario->viewport_visibility_masks[p_viewport];
|
||||
scenario->used_viewport_visibility_bits &= ~mask;
|
||||
scenario->viewport_visibility_masks.erase(p_viewport);
|
||||
}
|
||||
|
||||
void RendererSceneCull::scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
|
||||
Scenario *scenario = scenario_owner.getornull(p_scenario);
|
||||
ERR_FAIL_COND(!scenario);
|
||||
ERR_FAIL_COND(scenario->viewport_visibility_masks.has(p_viewport));
|
||||
|
||||
uint64_t new_mask = 1;
|
||||
while (new_mask & scenario->used_viewport_visibility_bits) {
|
||||
new_mask <<= 1;
|
||||
}
|
||||
|
||||
if (new_mask == 0) {
|
||||
ERR_PRINT("Only 64 viewports per scenario allowed when using visibility ranges.");
|
||||
new_mask = ((uint64_t)1) << 63;
|
||||
}
|
||||
|
||||
scenario->viewport_visibility_masks[p_viewport] = new_mask;
|
||||
scenario->used_viewport_visibility_bits |= new_mask;
|
||||
}
|
||||
|
||||
/* INSTANCING API */
|
||||
|
||||
void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) {
|
||||
|
@ -1103,10 +1135,142 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance,
|
|||
}
|
||||
}
|
||||
|
||||
void RendererSceneCull::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
|
||||
void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {
|
||||
Instance *instance = instance_owner.getornull(p_instance);
|
||||
ERR_FAIL_COND(!instance);
|
||||
|
||||
instance->visibility_range_begin = p_min;
|
||||
instance->visibility_range_end = p_max;
|
||||
instance->visibility_range_begin_margin = p_min_margin;
|
||||
instance->visibility_range_end_margin = p_max_margin;
|
||||
|
||||
_update_instance_visibility_dependencies(instance);
|
||||
|
||||
if (instance->scenario && instance->visibility_index != -1) {
|
||||
InstanceVisibilityData &vd = instance->scenario->instance_visibility[instance->visibility_index];
|
||||
vd.range_begin = instance->visibility_range_begin;
|
||||
vd.range_end = instance->visibility_range_end;
|
||||
vd.range_begin_margin = instance->visibility_range_begin_margin;
|
||||
vd.range_end_margin = instance->visibility_range_end_margin;
|
||||
}
|
||||
}
|
||||
|
||||
void RendererSceneCull::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) {
|
||||
void RendererSceneCull::instance_set_visibility_parent(RID p_instance, RID p_parent_instance) {
|
||||
Instance *instance = instance_owner.getornull(p_instance);
|
||||
ERR_FAIL_COND(!instance);
|
||||
|
||||
Instance *old_parent = instance->visibility_parent;
|
||||
if (old_parent) {
|
||||
if ((1 << old_parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && old_parent->base_data) {
|
||||
InstanceGeometryData *old_parent_geom = static_cast<InstanceGeometryData *>(old_parent->base_data);
|
||||
old_parent_geom->visibility_dependencies.erase(instance);
|
||||
_update_instance_visibility_depth(old_parent);
|
||||
}
|
||||
instance->visibility_parent = nullptr;
|
||||
}
|
||||
|
||||
Instance *parent = instance_owner.getornull(p_parent_instance);
|
||||
ERR_FAIL_COND(p_parent_instance.is_valid() && !parent);
|
||||
|
||||
if (parent) {
|
||||
if ((1 << parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && parent->base_data) {
|
||||
InstanceGeometryData *parent_geom = static_cast<InstanceGeometryData *>(parent->base_data);
|
||||
parent_geom->visibility_dependencies.insert(instance);
|
||||
_update_instance_visibility_depth(parent);
|
||||
}
|
||||
instance->visibility_parent = parent;
|
||||
}
|
||||
|
||||
_update_instance_visibility_dependencies(instance);
|
||||
}
|
||||
|
||||
void RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) {
|
||||
bool cycle_detected = false;
|
||||
Set<Instance *> traversed_nodes;
|
||||
|
||||
{
|
||||
Instance *instance = p_instance;
|
||||
while (instance && ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && instance->base_data) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
|
||||
if (!geom->visibility_dependencies.is_empty()) {
|
||||
uint32_t depth = 0;
|
||||
for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
|
||||
if (((1 << E->get()->base_type) & RS::INSTANCE_GEOMETRY_MASK) == 0 || !E->get()->base_data) {
|
||||
continue;
|
||||
}
|
||||
InstanceGeometryData *child_geom = static_cast<InstanceGeometryData *>(E->get()->base_data);
|
||||
depth = MAX(depth, child_geom->visibility_dependencies_depth);
|
||||
}
|
||||
geom->visibility_dependencies_depth = depth + 1;
|
||||
} else {
|
||||
geom->visibility_dependencies_depth = 0;
|
||||
}
|
||||
|
||||
if (instance->scenario && instance->visibility_index != -1) {
|
||||
instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth);
|
||||
}
|
||||
|
||||
traversed_nodes.insert(instance);
|
||||
|
||||
instance = instance->visibility_parent;
|
||||
if (traversed_nodes.has(instance)) {
|
||||
cycle_detected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cycle_detected) {
|
||||
ERR_PRINT("Cycle detected in the visibility dependecies tree.");
|
||||
for (Set<Instance *>::Element *E = traversed_nodes.front(); E; E = E->next()) {
|
||||
Instance *instance = E->get();
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
|
||||
geom->visibility_dependencies_depth = 0;
|
||||
if (instance->scenario && instance->visibility_index != -1) {
|
||||
instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_instance) {
|
||||
bool is_geometry_instance = ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && p_instance->base_data;
|
||||
bool has_visibility_range = p_instance->visibility_range_begin > 0.0 || p_instance->visibility_range_end > 0.0;
|
||||
bool needs_visibility_cull = has_visibility_range && is_geometry_instance && p_instance->array_index != -1;
|
||||
|
||||
if (!needs_visibility_cull && p_instance->visibility_index != -1) {
|
||||
p_instance->scenario->instance_visibility.remove(p_instance->visibility_index);
|
||||
p_instance->visibility_index = -1;
|
||||
} else if (needs_visibility_cull && p_instance->visibility_index == -1) {
|
||||
InstanceVisibilityData vd;
|
||||
vd.instance = p_instance;
|
||||
vd.range_begin = p_instance->visibility_range_begin;
|
||||
vd.range_end = p_instance->visibility_range_end;
|
||||
vd.range_begin_margin = p_instance->visibility_range_begin_margin;
|
||||
vd.range_end_margin = p_instance->visibility_range_end_margin;
|
||||
vd.position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f;
|
||||
vd.array_index = p_instance->array_index;
|
||||
|
||||
InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data);
|
||||
p_instance->scenario->instance_visibility.insert(vd, geom_data->visibility_dependencies_depth);
|
||||
}
|
||||
|
||||
if (p_instance->scenario && p_instance->array_index != -1) {
|
||||
p_instance->scenario->instance_data[p_instance->array_index].visibility_index = p_instance->visibility_index;
|
||||
|
||||
InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data);
|
||||
if ((has_visibility_range || p_instance->visibility_parent) && (p_instance->visibility_index == -1 || (geom_data && geom_data->visibility_dependencies_depth == 0))) {
|
||||
p_instance->scenario->instance_data[p_instance->array_index].flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK;
|
||||
} else {
|
||||
p_instance->scenario->instance_data[p_instance->array_index].flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK;
|
||||
}
|
||||
|
||||
if (p_instance->visibility_parent) {
|
||||
p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = p_instance->visibility_parent->array_index;
|
||||
} else {
|
||||
p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) {
|
||||
|
@ -1352,12 +1516,23 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
|
|||
idata.layer_mask = p_instance->layer_mask;
|
||||
idata.flags = p_instance->base_type; //changing it means de-indexing, so this never needs to be changed later
|
||||
idata.base_rid = p_instance->base;
|
||||
idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1;
|
||||
idata.visibility_index = p_instance->visibility_index;
|
||||
|
||||
switch (p_instance->base_type) {
|
||||
case RS::INSTANCE_MESH:
|
||||
case RS::INSTANCE_MULTIMESH:
|
||||
case RS::INSTANCE_IMMEDIATE:
|
||||
case RS::INSTANCE_PARTICLES: {
|
||||
idata.instance_geometry = static_cast<InstanceGeometryData *>(p_instance->base_data)->geometry_instance;
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
|
||||
idata.instance_geometry = geom->geometry_instance;
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
|
||||
Instance *dep_instance = E->get();
|
||||
if (dep_instance->array_index != -1) {
|
||||
dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = p_instance->array_index;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case RS::INSTANCE_LIGHT: {
|
||||
idata.instance_data_rid = static_cast<InstanceLightData *>(p_instance->base_data)->instance.get_id();
|
||||
|
@ -1404,6 +1579,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
|
|||
|
||||
p_instance->scenario->instance_data.push_back(idata);
|
||||
p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb));
|
||||
_update_instance_visibility_dependencies(p_instance);
|
||||
} else {
|
||||
if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
|
||||
p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, bvh_aabb);
|
||||
|
@ -1413,6 +1589,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
|
|||
p_instance->scenario->instance_aabbs[p_instance->array_index] = InstanceBounds(p_instance->transformed_aabb);
|
||||
}
|
||||
|
||||
if (p_instance->visibility_index != -1) {
|
||||
p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f;
|
||||
}
|
||||
|
||||
//move instance and repair
|
||||
pair_pass++;
|
||||
|
||||
|
@ -1486,9 +1666,24 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) {
|
|||
//replace this by last
|
||||
int32_t swap_with_index = p_instance->scenario->instance_data.size() - 1;
|
||||
if (swap_with_index != p_instance->array_index) {
|
||||
p_instance->scenario->instance_data[swap_with_index].instance->array_index = p_instance->array_index; //swap
|
||||
Instance *swapped_instance = p_instance->scenario->instance_data[swap_with_index].instance;
|
||||
swapped_instance->array_index = p_instance->array_index; //swap
|
||||
p_instance->scenario->instance_data[p_instance->array_index] = p_instance->scenario->instance_data[swap_with_index];
|
||||
p_instance->scenario->instance_aabbs[p_instance->array_index] = p_instance->scenario->instance_aabbs[swap_with_index];
|
||||
|
||||
if (swapped_instance->visibility_index != -1) {
|
||||
swapped_instance->scenario->instance_visibility[swapped_instance->visibility_index].array_index = swapped_instance->array_index;
|
||||
}
|
||||
|
||||
if ((1 << swapped_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(swapped_instance->base_data);
|
||||
for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
|
||||
Instance *dep_instance = E->get();
|
||||
if (dep_instance != p_instance && dep_instance->array_index != -1) {
|
||||
dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = swapped_instance->array_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pop last
|
||||
|
@ -1505,7 +1700,16 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) {
|
|||
scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0);
|
||||
scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0);
|
||||
scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, nullptr, 0);
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) {
|
||||
Instance *dep_instance = E->get();
|
||||
if (dep_instance->array_index != -1) {
|
||||
dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_update_instance_visibility_dependencies(p_instance);
|
||||
}
|
||||
|
||||
void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
|
||||
|
@ -2272,16 +2476,73 @@ void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_
|
|||
#endif
|
||||
}
|
||||
|
||||
void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, CullData *cull_data) {
|
||||
void RendererSceneCull::_visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data) {
|
||||
uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
|
||||
uint32_t bin_from = p_thread * cull_data->cull_count / total_threads;
|
||||
uint32_t bin_to = (p_thread + 1 == total_threads) ? cull_data->cull_count : ((p_thread + 1) * cull_data->cull_count / total_threads);
|
||||
|
||||
_visibility_cull(*cull_data, cull_data->cull_offset + bin_from, cull_data->cull_offset + bin_to);
|
||||
}
|
||||
|
||||
void RendererSceneCull::_visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to) {
|
||||
Scenario *scenario = cull_data.scenario;
|
||||
for (unsigned int i = p_from; i < p_to; i++) {
|
||||
InstanceVisibilityData &vd = scenario->instance_visibility[i];
|
||||
InstanceData &idata = scenario->instance_data[vd.array_index];
|
||||
|
||||
if (idata.parent_array_index >= 0) {
|
||||
uint32_t parent_flags = scenario->instance_data[idata.parent_array_index].flags;
|
||||
if ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) || (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE) == 0) {
|
||||
idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
|
||||
idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int range_check = _visibility_range_check(vd, cull_data.camera_position, cull_data.viewport_mask);
|
||||
|
||||
if (range_check == -1) {
|
||||
idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
|
||||
idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
|
||||
} else if (range_check == 1) {
|
||||
idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
|
||||
idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
|
||||
} else {
|
||||
idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN;
|
||||
idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RendererSceneCull::_visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask) {
|
||||
float dist = p_camera_pos.distance_to(r_vis_data.position);
|
||||
|
||||
bool in_range_last_frame = p_viewport_mask & r_vis_data.viewport_state;
|
||||
float begin_offset = in_range_last_frame ? -r_vis_data.range_begin_margin : r_vis_data.range_begin_margin;
|
||||
float end_offset = in_range_last_frame ? r_vis_data.range_end_margin : -r_vis_data.range_end_margin;
|
||||
|
||||
if (r_vis_data.range_end > 0.0f && dist > r_vis_data.range_end + end_offset) {
|
||||
r_vis_data.viewport_state &= ~p_viewport_mask;
|
||||
return -1;
|
||||
} else if (r_vis_data.range_begin > 0.0f && dist < r_vis_data.range_begin + begin_offset) {
|
||||
r_vis_data.viewport_state &= ~p_viewport_mask;
|
||||
return 1;
|
||||
} else {
|
||||
r_vis_data.viewport_state |= p_viewport_mask;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_data) {
|
||||
uint32_t cull_total = cull_data->scenario->instance_data.size();
|
||||
uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
|
||||
uint32_t cull_from = p_thread * cull_total / total_threads;
|
||||
uint32_t cull_to = (p_thread + 1 == total_threads) ? cull_total : ((p_thread + 1) * cull_total / total_threads);
|
||||
|
||||
_frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to);
|
||||
_scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to);
|
||||
}
|
||||
|
||||
void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
|
||||
void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to) {
|
||||
uint64_t frame_number = RSG::rasterizer->get_frame_number();
|
||||
float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time();
|
||||
|
||||
|
@ -2296,177 +2557,192 @@ void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cu
|
|||
for (uint64_t i = p_from; i < p_to; i++) {
|
||||
bool mesh_visible = false;
|
||||
|
||||
if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum) && (cull_data.occlusion_buffer == nullptr || cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING ||
|
||||
!cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))) {
|
||||
InstanceData &idata = cull_data.scenario->instance_data[i];
|
||||
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
|
||||
InstanceData &idata = cull_data.scenario->instance_data[i];
|
||||
uint32_t visibility_flags = idata.flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN);
|
||||
int32_t visibility_check = -1;
|
||||
|
||||
if ((cull_data.visible_layers & idata.layer_mask) == 0) {
|
||||
//failure
|
||||
} else if (base_type == RS::INSTANCE_LIGHT) {
|
||||
cull_result.lights.push_back(idata.instance);
|
||||
cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) {
|
||||
scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
|
||||
}
|
||||
#define HIDDEN_BY_VISIBILITY_CHECKS (visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE || visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN)
|
||||
#define LAYER_CHECK (cull_data.visible_layers & idata.layer_mask)
|
||||
#define IN_FRUSTUM(f) (cull_data.scenario->instance_aabbs[i].in_frustum(f))
|
||||
#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_cull_data->viewport_mask) == 0)
|
||||
#define VIS_PARENT_CHECK ((idata.parent_array_index == -1) || ((cull_data.scenario->instance_data[idata.parent_array_index].flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK) == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE))
|
||||
#define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check)
|
||||
#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))
|
||||
|
||||
} else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
|
||||
if (cull_data.render_reflection_probe != idata.instance) {
|
||||
//avoid entering The Matrix
|
||||
if (!HIDDEN_BY_VISIBILITY_CHECKS) {
|
||||
if (LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) {
|
||||
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
|
||||
if (base_type == RS::INSTANCE_LIGHT) {
|
||||
cull_result.lights.push_back(idata.instance);
|
||||
cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) {
|
||||
scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
|
||||
}
|
||||
|
||||
if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
|
||||
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
|
||||
cull_data.cull->lock.lock();
|
||||
if (!reflection_probe->update_list.in_list()) {
|
||||
reflection_probe->render_step = 0;
|
||||
reflection_probe_render_list.add_last(&reflection_probe->update_list);
|
||||
} else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
|
||||
if (cull_data.render_reflection_probe != idata.instance) {
|
||||
//avoid entering The Matrix
|
||||
|
||||
if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
|
||||
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
|
||||
cull_data.cull->lock.lock();
|
||||
if (!reflection_probe->update_list.in_list()) {
|
||||
reflection_probe->render_step = 0;
|
||||
reflection_probe_render_list.add_last(&reflection_probe->update_list);
|
||||
}
|
||||
cull_data.cull->lock.unlock();
|
||||
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
|
||||
}
|
||||
cull_data.cull->lock.unlock();
|
||||
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
|
||||
if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
|
||||
cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
}
|
||||
}
|
||||
} else if (base_type == RS::INSTANCE_DECAL) {
|
||||
cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
|
||||
if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
|
||||
cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
} else if (base_type == RS::INSTANCE_VOXEL_GI) {
|
||||
InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(idata.instance->base_data);
|
||||
cull_data.cull->lock.lock();
|
||||
if (!voxel_gi->update_element.in_list()) {
|
||||
voxel_gi_update_list.add(&voxel_gi->update_element);
|
||||
}
|
||||
}
|
||||
} else if (base_type == RS::INSTANCE_DECAL) {
|
||||
cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
cull_data.cull->lock.unlock();
|
||||
cull_result.voxel_gi_instances.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
|
||||
} else if (base_type == RS::INSTANCE_VOXEL_GI) {
|
||||
InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(idata.instance->base_data);
|
||||
cull_data.cull->lock.lock();
|
||||
if (!voxel_gi->update_element.in_list()) {
|
||||
voxel_gi_update_list.add(&voxel_gi->update_element);
|
||||
}
|
||||
cull_data.cull->lock.unlock();
|
||||
cull_result.voxel_gi_instances.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
} else if (base_type == RS::INSTANCE_LIGHTMAP) {
|
||||
cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
} else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
|
||||
bool keep = true;
|
||||
|
||||
} else if (base_type == RS::INSTANCE_LIGHTMAP) {
|
||||
cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
|
||||
} else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
|
||||
bool keep = true;
|
||||
|
||||
if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) {
|
||||
RenderingServerDefault::redraw_request();
|
||||
}
|
||||
|
||||
if (base_type == RS::INSTANCE_MESH) {
|
||||
mesh_visible = true;
|
||||
} else if (base_type == RS::INSTANCE_PARTICLES) {
|
||||
//particles visible? process them
|
||||
if (RSG::storage->particles_is_inactive(idata.base_rid)) {
|
||||
//but if nothing is going on, don't do it.
|
||||
keep = false;
|
||||
} else {
|
||||
cull_data.cull->lock.lock();
|
||||
RSG::storage->particles_request_process(idata.base_rid);
|
||||
cull_data.cull->lock.unlock();
|
||||
RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized());
|
||||
//particles visible? request redraw
|
||||
if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) {
|
||||
RenderingServerDefault::redraw_request();
|
||||
}
|
||||
}
|
||||
|
||||
if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {
|
||||
InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
|
||||
instance_pair_buffer[idx++] = light->instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY);
|
||||
}
|
||||
|
||||
if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
|
||||
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
|
||||
|
||||
instance_pair_buffer[idx++] = reflection_probe->instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY);
|
||||
}
|
||||
|
||||
if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) {
|
||||
InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data);
|
||||
|
||||
instance_pair_buffer[idx++] = decal->instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
|
||||
}
|
||||
|
||||
if (idata.flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
for (Set<Instance *>::Element *E = geom->voxel_gi_instances.front(); E; E = E->next()) {
|
||||
InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(E->get()->base_data);
|
||||
|
||||
instance_pair_buffer[idx++] = voxel_gi->probe_instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
|
||||
}
|
||||
|
||||
if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
Color *sh = idata.instance->lightmap_sh.ptrw();
|
||||
const Color *target_sh = idata.instance->lightmap_target_sh.ptr();
|
||||
for (uint32_t j = 0; j < 9; j++) {
|
||||
sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
|
||||
}
|
||||
scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh);
|
||||
idata.instance->last_frame_pass = frame_number;
|
||||
}
|
||||
|
||||
if (keep) {
|
||||
cull_result.geometry_instances.push_back(idata.instance_geometry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) {
|
||||
for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) {
|
||||
if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->shadows[j].cascades[k].frustum)) {
|
||||
InstanceData &idata = cull_data.scenario->instance_data[i];
|
||||
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
|
||||
|
||||
if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) {
|
||||
cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry);
|
||||
if (base_type == RS::INSTANCE_MESH) {
|
||||
mesh_visible = true;
|
||||
} else if (base_type == RS::INSTANCE_PARTICLES) {
|
||||
//particles visible? process them
|
||||
if (RSG::storage->particles_is_inactive(idata.base_rid)) {
|
||||
//but if nothing is going on, don't do it.
|
||||
keep = false;
|
||||
} else {
|
||||
cull_data.cull->lock.lock();
|
||||
RSG::storage->particles_request_process(idata.base_rid);
|
||||
cull_data.cull->lock.unlock();
|
||||
RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized());
|
||||
//particles visible? request redraw
|
||||
RenderingServerDefault::redraw_request();
|
||||
}
|
||||
}
|
||||
|
||||
if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) {
|
||||
InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data);
|
||||
instance_pair_buffer[idx++] = light->instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY);
|
||||
}
|
||||
|
||||
if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) {
|
||||
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data);
|
||||
|
||||
instance_pair_buffer[idx++] = reflection_probe->instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY);
|
||||
}
|
||||
|
||||
if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
|
||||
for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) {
|
||||
InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data);
|
||||
|
||||
instance_pair_buffer[idx++] = decal->instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY);
|
||||
}
|
||||
|
||||
if (idata.flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
uint32_t idx = 0;
|
||||
for (Set<Instance *>::Element *E = geom->voxel_gi_instances.front(); E; E = E->next()) {
|
||||
InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(E->get()->base_data);
|
||||
|
||||
instance_pair_buffer[idx++] = voxel_gi->probe_instance;
|
||||
if (idx == MAX_INSTANCE_PAIRS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx);
|
||||
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
|
||||
}
|
||||
|
||||
if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) {
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
|
||||
Color *sh = idata.instance->lightmap_sh.ptrw();
|
||||
const Color *target_sh = idata.instance->lightmap_target_sh.ptr();
|
||||
for (uint32_t j = 0; j < 9; j++) {
|
||||
sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
|
||||
}
|
||||
scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh);
|
||||
idata.instance->last_frame_pass = frame_number;
|
||||
}
|
||||
|
||||
if (keep) {
|
||||
cull_result.geometry_instances.push_back(idata.instance_geometry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) {
|
||||
for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) {
|
||||
if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) {
|
||||
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
|
||||
|
||||
if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) {
|
||||
cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry);
|
||||
mesh_visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef HIDDEN_BY_VISIBILITY_CHECKS
|
||||
#undef LAYER_CHECK
|
||||
#undef IN_FRUSTUM
|
||||
#undef VIS_RANGE_CHECK
|
||||
#undef VIS_PARENT_CHECK
|
||||
#undef VIS_CHECK
|
||||
#undef OCCLUSION_CULLED
|
||||
|
||||
for (uint32_t j = 0; j < cull_data.cull->sdfgi.region_count; j++) {
|
||||
if (cull_data.scenario->instance_aabbs[i].in_aabb(cull_data.cull->sdfgi.region_aabb[j])) {
|
||||
InstanceData &idata = cull_data.scenario->instance_data[i];
|
||||
uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK;
|
||||
|
||||
if (base_type == RS::INSTANCE_LIGHT) {
|
||||
|
@ -2507,7 +2783,35 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not)
|
||||
}
|
||||
|
||||
RENDER_TIMESTAMP("Frustum Culling");
|
||||
RENDER_TIMESTAMP("Visibility Dependencies");
|
||||
|
||||
VisibilityCullData visibility_cull_data;
|
||||
if (scenario->instance_visibility.get_bin_count() > 0) {
|
||||
if (!scenario->viewport_visibility_masks.has(p_viewport)) {
|
||||
scenario_add_viewport_visibility_mask(scenario->self, p_viewport);
|
||||
}
|
||||
|
||||
visibility_cull_data.scenario = scenario;
|
||||
visibility_cull_data.viewport_mask = scenario->viewport_visibility_masks[p_viewport];
|
||||
visibility_cull_data.camera_position = p_camera_data->main_transform.origin;
|
||||
|
||||
for (int i = scenario->instance_visibility.get_bin_count() - 1; i > 0; i--) { // We skip bin 0
|
||||
visibility_cull_data.cull_offset = scenario->instance_visibility.get_bin_start(i);
|
||||
visibility_cull_data.cull_count = scenario->instance_visibility.get_bin_size(i);
|
||||
|
||||
if (visibility_cull_data.cull_count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visibility_cull_data.cull_count > thread_cull_threshold) {
|
||||
RendererThreadPool::singleton->thread_work_pool.do_work(RendererThreadPool::singleton->thread_work_pool.get_thread_count(), this, &RendererSceneCull::_visibility_cull_threaded, &visibility_cull_data);
|
||||
} else {
|
||||
_visibility_cull(visibility_cull_data, visibility_cull_data.cull_offset, visibility_cull_data.cull_offset + visibility_cull_data.cull_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RENDER_TIMESTAMP("Culling");
|
||||
|
||||
//rasterizer->set_camera(p_camera_data->main_transform, p_camera_data.main_projection, p_camera_data.is_ortogonal);
|
||||
|
||||
|
@ -2580,7 +2884,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
}
|
||||
}
|
||||
|
||||
frustum_cull_result.clear();
|
||||
scene_cull_result.clear();
|
||||
|
||||
{
|
||||
uint64_t cull_from = 0;
|
||||
|
@ -2603,19 +2907,19 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
#endif
|
||||
if (cull_to > thread_cull_threshold) {
|
||||
//multiple threads
|
||||
for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
|
||||
frustum_cull_result_threads[i].clear();
|
||||
for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
|
||||
scene_cull_result_threads[i].clear();
|
||||
}
|
||||
|
||||
RendererThreadPool::singleton->thread_work_pool.do_work(frustum_cull_result_threads.size(), this, &RendererSceneCull::_frustum_cull_threaded, &cull_data);
|
||||
RendererThreadPool::singleton->thread_work_pool.do_work(scene_cull_result_threads.size(), this, &RendererSceneCull::_scene_cull_threaded, &cull_data);
|
||||
|
||||
for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
|
||||
frustum_cull_result.append_from(frustum_cull_result_threads[i]);
|
||||
for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
|
||||
scene_cull_result.append_from(scene_cull_result_threads[i]);
|
||||
}
|
||||
|
||||
} else {
|
||||
//single threaded
|
||||
_frustum_cull(cull_data, frustum_cull_result, cull_from, cull_to);
|
||||
_scene_cull(cull_data, scene_cull_result, cull_from, cull_to);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CULL_TIME
|
||||
|
@ -2626,9 +2930,9 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
print_line("time taken: " + rtos(time_avg / time_count));
|
||||
#endif
|
||||
|
||||
if (frustum_cull_result.mesh_instances.size()) {
|
||||
for (uint64_t i = 0; i < frustum_cull_result.mesh_instances.size(); i++) {
|
||||
RSG::storage->mesh_instance_check_for_update(frustum_cull_result.mesh_instances[i]);
|
||||
if (scene_cull_result.mesh_instances.size()) {
|
||||
for (uint64_t i = 0; i < scene_cull_result.mesh_instances.size(); i++) {
|
||||
RSG::storage->mesh_instance_check_for_update(scene_cull_result.mesh_instances[i]);
|
||||
}
|
||||
RSG::storage->update_mesh_instances();
|
||||
}
|
||||
|
@ -2652,14 +2956,14 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
}
|
||||
render_shadow_data[max_shadows_used].light = cull.shadows[i].light_instance;
|
||||
render_shadow_data[max_shadows_used].pass = j;
|
||||
render_shadow_data[max_shadows_used].instances.merge_unordered(frustum_cull_result.directional_shadows[i].cascade_geometry_instances[j]);
|
||||
render_shadow_data[max_shadows_used].instances.merge_unordered(scene_cull_result.directional_shadows[i].cascade_geometry_instances[j]);
|
||||
max_shadows_used++;
|
||||
}
|
||||
}
|
||||
|
||||
// Positional Shadowss
|
||||
for (uint32_t i = 0; i < (uint32_t)frustum_cull_result.lights.size(); i++) {
|
||||
Instance *ins = frustum_cull_result.lights[i];
|
||||
for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) {
|
||||
Instance *ins = scene_cull_result.lights[i];
|
||||
|
||||
if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) {
|
||||
continue;
|
||||
|
@ -2763,13 +3067,13 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
if (cull.sdfgi.region_count > 0) {
|
||||
//update regions
|
||||
for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) {
|
||||
render_sdfgi_data[i].instances.merge_unordered(frustum_cull_result.sdfgi_region_geometry_instances[i]);
|
||||
render_sdfgi_data[i].instances.merge_unordered(scene_cull_result.sdfgi_region_geometry_instances[i]);
|
||||
render_sdfgi_data[i].region = i;
|
||||
}
|
||||
//check if static lights were culled
|
||||
bool static_lights_culled = false;
|
||||
for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) {
|
||||
if (frustum_cull_result.sdfgi_cascade_lights[i].size()) {
|
||||
if (scene_cull_result.sdfgi_cascade_lights[i].size()) {
|
||||
static_lights_culled = true;
|
||||
break;
|
||||
}
|
||||
|
@ -2778,7 +3082,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
if (static_lights_culled) {
|
||||
sdfgi_update_data.static_cascade_count = cull.sdfgi.cascade_light_count;
|
||||
sdfgi_update_data.static_cascade_indices = cull.sdfgi.cascade_light_index;
|
||||
sdfgi_update_data.static_positional_lights = frustum_cull_result.sdfgi_cascade_lights;
|
||||
sdfgi_update_data.static_positional_lights = scene_cull_result.sdfgi_cascade_lights;
|
||||
sdfgi_update_data.update_static = true;
|
||||
}
|
||||
}
|
||||
|
@ -2792,7 +3096,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
|
||||
//append the directional lights to the lights culled
|
||||
for (int i = 0; i < directional_lights.size(); i++) {
|
||||
frustum_cull_result.light_instances.push_back(directional_lights[i]);
|
||||
scene_cull_result.light_instances.push_back(directional_lights[i]);
|
||||
}
|
||||
|
||||
RID camera_effects;
|
||||
|
@ -2809,7 +3113,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
|
|||
}
|
||||
|
||||
RENDER_TIMESTAMP("Render Scene ");
|
||||
scene_render->render_scene(p_render_buffers, p_camera_data, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.voxel_gi_instances, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data);
|
||||
scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data);
|
||||
|
||||
for (uint32_t i = 0; i < max_shadows_used; i++) {
|
||||
render_shadow_data[i].instances.clear();
|
||||
|
@ -3144,7 +3448,7 @@ void RendererSceneCull::render_probes() {
|
|||
update_lights = true;
|
||||
}
|
||||
|
||||
frustum_cull_result.geometry_instances.clear();
|
||||
scene_cull_result.geometry_instances.clear();
|
||||
|
||||
RID instance_pair_buffer[MAX_INSTANCE_PAIRS];
|
||||
|
||||
|
@ -3171,10 +3475,10 @@ void RendererSceneCull::render_probes() {
|
|||
ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY);
|
||||
}
|
||||
|
||||
frustum_cull_result.geometry_instances.push_back(geom->geometry_instance);
|
||||
scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
|
||||
}
|
||||
|
||||
scene_render->voxel_gi_update(probe->probe_instance, update_lights, probe->light_instances, frustum_cull_result.geometry_instances);
|
||||
scene_render->voxel_gi_update(probe->probe_instance, update_lights, probe->light_instances, scene_cull_result.geometry_instances);
|
||||
|
||||
voxel_gi_update_list.remove(voxel_gi);
|
||||
|
||||
|
@ -3189,7 +3493,7 @@ void RendererSceneCull::render_particle_colliders() {
|
|||
if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) {
|
||||
//update heightfield
|
||||
instance_cull_result.clear();
|
||||
frustum_cull_result.geometry_instances.clear();
|
||||
scene_cull_result.geometry_instances.clear();
|
||||
|
||||
struct CullAABB {
|
||||
PagedArray<Instance *> *result;
|
||||
|
@ -3211,10 +3515,10 @@ void RendererSceneCull::render_particle_colliders() {
|
|||
continue;
|
||||
}
|
||||
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
|
||||
frustum_cull_result.geometry_instances.push_back(geom->geometry_instance);
|
||||
scene_cull_result.geometry_instances.push_back(geom->geometry_instance);
|
||||
}
|
||||
|
||||
scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, frustum_cull_result.geometry_instances);
|
||||
scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, scene_cull_result.geometry_instances);
|
||||
}
|
||||
heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front());
|
||||
}
|
||||
|
@ -3503,6 +3807,7 @@ bool RendererSceneCull::free(RID p_rid) {
|
|||
}
|
||||
scenario->instance_aabbs.reset();
|
||||
scenario->instance_data.reset();
|
||||
scenario->instance_visibility.reset();
|
||||
|
||||
scene_render->free(scenario->reflection_probe_shadow_atlas);
|
||||
scene_render->free(scenario->reflection_atlas);
|
||||
|
@ -3571,10 +3876,10 @@ RendererSceneCull::RendererSceneCull() {
|
|||
render_sdfgi_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool);
|
||||
}
|
||||
|
||||
frustum_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
|
||||
frustum_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
|
||||
for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
|
||||
frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
|
||||
scene_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
|
||||
scene_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
|
||||
for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
|
||||
scene_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool);
|
||||
}
|
||||
|
||||
indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame");
|
||||
|
@ -3595,11 +3900,11 @@ RendererSceneCull::~RendererSceneCull() {
|
|||
render_sdfgi_data[i].instances.reset();
|
||||
}
|
||||
|
||||
frustum_cull_result.reset();
|
||||
for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) {
|
||||
frustum_cull_result_threads[i].reset();
|
||||
scene_cull_result.reset();
|
||||
for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) {
|
||||
scene_cull_result_threads[i].reset();
|
||||
}
|
||||
frustum_cull_result_threads.clear();
|
||||
scene_cull_result_threads.clear();
|
||||
|
||||
if (dummy_occlusion_culling) {
|
||||
memdelete(dummy_occlusion_culling);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef RENDERING_SERVER_SCENE_CULL_H
|
||||
#define RENDERING_SERVER_SCENE_CULL_H
|
||||
|
||||
#include "core/templates/bin_sorted_array.h"
|
||||
#include "core/templates/pass_func.h"
|
||||
#include "servers/rendering/renderer_compositor.h"
|
||||
|
||||
|
@ -259,6 +260,9 @@ public:
|
|||
FLAG_USES_MESH_INSTANCE = (1 << 17),
|
||||
FLAG_REFLECTION_PROBE_DIRTY = (1 << 18),
|
||||
FLAG_IGNORE_OCCLUSION_CULLING = (1 << 19),
|
||||
FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK = (3 << 20), // 2 bits, overlaps with the other vis. dependency flags
|
||||
FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE = (1 << 20),
|
||||
FLAG_VISIBILITY_DEPENDENCY_HIDDEN = (1 << 21),
|
||||
};
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
@ -269,10 +273,33 @@ public:
|
|||
RendererSceneRender::GeometryInstance *instance_geometry;
|
||||
};
|
||||
Instance *instance = nullptr;
|
||||
int32_t parent_array_index = -1;
|
||||
int32_t visibility_index = -1;
|
||||
};
|
||||
|
||||
struct InstanceVisibilityData {
|
||||
uint64_t viewport_state = 0;
|
||||
int32_t array_index = -1;
|
||||
Vector3 position;
|
||||
Instance *instance = nullptr;
|
||||
float range_begin = 0.0f;
|
||||
float range_end = 0.0f;
|
||||
float range_begin_margin = 0.0f;
|
||||
float range_end_margin = 0.0f;
|
||||
};
|
||||
|
||||
class VisibilityArray : public BinSortedArray<InstanceVisibilityData> {
|
||||
_FORCE_INLINE_ virtual void _update_idx(InstanceVisibilityData &r_element, uint64_t p_idx) {
|
||||
r_element.instance->visibility_index = p_idx;
|
||||
if (r_element.instance->scenario && r_element.instance->array_index != -1) {
|
||||
r_element.instance->scenario->instance_data[r_element.instance->array_index].visibility_index = p_idx;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PagedArrayPool<InstanceBounds> instance_aabb_page_pool;
|
||||
PagedArrayPool<InstanceData> instance_data_page_pool;
|
||||
PagedArrayPool<InstanceVisibilityData> instance_visibility_data_page_pool;
|
||||
|
||||
struct Scenario {
|
||||
enum IndexerType {
|
||||
|
@ -292,6 +319,8 @@ public:
|
|||
RID camera_effects;
|
||||
RID reflection_probe_shadow_atlas;
|
||||
RID reflection_atlas;
|
||||
uint64_t used_viewport_visibility_bits;
|
||||
Map<RID, uint64_t> viewport_visibility_masks;
|
||||
|
||||
SelfList<Instance>::List instances;
|
||||
|
||||
|
@ -299,11 +328,13 @@ public:
|
|||
|
||||
PagedArray<InstanceBounds> instance_aabbs;
|
||||
PagedArray<InstanceData> instance_data;
|
||||
VisibilityArray instance_visibility;
|
||||
|
||||
Scenario() {
|
||||
indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY);
|
||||
indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES);
|
||||
debug = RS::SCENARIO_DEBUG_DISABLED;
|
||||
used_viewport_visibility_bits = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -326,6 +357,8 @@ public:
|
|||
virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count);
|
||||
virtual bool is_scenario(RID p_scenario) const;
|
||||
virtual RID scenario_get_environment(RID p_scenario);
|
||||
virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport);
|
||||
virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport);
|
||||
|
||||
/* INSTANCING API */
|
||||
|
||||
|
@ -399,6 +432,12 @@ public:
|
|||
//scenario stuff
|
||||
DynamicBVH::ID indexer_id;
|
||||
int32_t array_index;
|
||||
int32_t visibility_index = -1;
|
||||
float visibility_range_begin;
|
||||
float visibility_range_end;
|
||||
float visibility_range_begin_margin;
|
||||
float visibility_range_end_margin;
|
||||
Instance *visibility_parent = nullptr;
|
||||
Scenario *scenario;
|
||||
SelfList<Instance> scenario_item;
|
||||
|
||||
|
@ -412,12 +451,6 @@ public:
|
|||
float extra_margin;
|
||||
ObjectID object_id;
|
||||
|
||||
float lod_begin;
|
||||
float lod_end;
|
||||
float lod_begin_hysteresis;
|
||||
float lod_end_hysteresis;
|
||||
RID lod_instance;
|
||||
|
||||
Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior
|
||||
|
||||
uint64_t last_frame_pass;
|
||||
|
@ -495,10 +528,10 @@ public:
|
|||
|
||||
visible = true;
|
||||
|
||||
lod_begin = 0;
|
||||
lod_end = 0;
|
||||
lod_begin_hysteresis = 0;
|
||||
lod_end_hysteresis = 0;
|
||||
visibility_range_begin = 0;
|
||||
visibility_range_end = 0;
|
||||
visibility_range_begin_margin = 0;
|
||||
visibility_range_end_margin = 0;
|
||||
|
||||
last_frame_pass = 0;
|
||||
version = 1;
|
||||
|
@ -537,6 +570,8 @@ public:
|
|||
Set<Instance *> reflection_probes;
|
||||
Set<Instance *> voxel_gi_instances;
|
||||
Set<Instance *> lightmap_captures;
|
||||
Set<Instance *> visibility_dependencies;
|
||||
uint32_t visibility_dependencies_depth = 0;
|
||||
|
||||
InstanceGeometryData() {
|
||||
can_cast_shadows = true;
|
||||
|
@ -717,7 +752,7 @@ public:
|
|||
PagedArray<Instance *> instance_cull_result;
|
||||
PagedArray<Instance *> instance_shadow_cull_result;
|
||||
|
||||
struct FrustumCullResult {
|
||||
struct InstanceCullResult {
|
||||
PagedArray<RendererSceneRender::GeometryInstance *> geometry_instances;
|
||||
PagedArray<Instance *> lights;
|
||||
PagedArray<RID> light_instances;
|
||||
|
@ -782,7 +817,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void append_from(FrustumCullResult &p_cull_result) {
|
||||
void append_from(InstanceCullResult &p_cull_result) {
|
||||
geometry_instances.merge_unordered(p_cull_result.geometry_instances);
|
||||
lights.merge_unordered(p_cull_result.lights);
|
||||
light_instances.merge_unordered(p_cull_result.light_instances);
|
||||
|
@ -832,8 +867,8 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
FrustumCullResult frustum_cull_result;
|
||||
LocalVector<FrustumCullResult> frustum_cull_result_threads;
|
||||
InstanceCullResult scene_cull_result;
|
||||
LocalVector<InstanceCullResult> scene_cull_result_threads;
|
||||
|
||||
RendererSceneRender::RenderShadowData render_shadow_data[MAX_UPDATE_SHADOWS];
|
||||
uint32_t max_shadows_used = 0;
|
||||
|
@ -866,6 +901,11 @@ public:
|
|||
|
||||
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin);
|
||||
|
||||
virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance);
|
||||
|
||||
void _update_instance_visibility_depth(Instance *p_instance);
|
||||
void _update_instance_visibility_dependencies(Instance *p_instance);
|
||||
|
||||
// don't use these in a game!
|
||||
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const;
|
||||
virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
|
||||
|
@ -875,8 +915,8 @@ public:
|
|||
virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting);
|
||||
virtual void instance_geometry_set_material_override(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);
|
||||
virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin);
|
||||
|
||||
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index);
|
||||
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias);
|
||||
|
||||
|
@ -937,6 +977,19 @@ public:
|
|||
Frustum frustum;
|
||||
} cull;
|
||||
|
||||
struct VisibilityCullData {
|
||||
uint64_t viewport_mask;
|
||||
Scenario *scenario;
|
||||
Vector3 camera_position;
|
||||
uint32_t cull_offset;
|
||||
uint32_t cull_count;
|
||||
};
|
||||
|
||||
void _visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data);
|
||||
void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to);
|
||||
_FORCE_INLINE_ void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_idx);
|
||||
_FORCE_INLINE_ int _visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask);
|
||||
|
||||
struct CullData {
|
||||
Cull *cull;
|
||||
Scenario *scenario;
|
||||
|
@ -946,10 +999,11 @@ public:
|
|||
Instance *render_reflection_probe;
|
||||
const RendererSceneOcclusionCull::HZBuffer *occlusion_buffer;
|
||||
const CameraMatrix *camera_matrix;
|
||||
const VisibilityCullData *visibility_cull_data;
|
||||
};
|
||||
|
||||
void _frustum_cull_threaded(uint32_t p_thread, CullData *cull_data);
|
||||
void _frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to);
|
||||
void _scene_cull_threaded(uint32_t p_thread, CullData *cull_data);
|
||||
void _scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to);
|
||||
|
||||
bool _render_reflection_probe_step(Instance *p_instance, int p_step);
|
||||
void _render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true);
|
||||
|
|
|
@ -824,6 +824,10 @@ void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) {
|
|||
Viewport *viewport = viewport_owner.getornull(p_viewport);
|
||||
ERR_FAIL_COND(!viewport);
|
||||
|
||||
if (viewport->scenario.is_valid()) {
|
||||
RSG::scene->scenario_remove_viewport_visibility_mask(viewport->scenario, p_viewport);
|
||||
}
|
||||
|
||||
viewport->scenario = p_scenario;
|
||||
if (viewport->use_occlusion_culling) {
|
||||
RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, p_scenario);
|
||||
|
|
|
@ -726,6 +726,7 @@ public:
|
|||
FUNC2(instance_set_exterior, RID, bool)
|
||||
|
||||
FUNC2(instance_set_extra_visibility_margin, RID, real_t)
|
||||
FUNC2(instance_set_visibility_parent, RID, RID)
|
||||
|
||||
// don't use these in a game!
|
||||
FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID)
|
||||
|
@ -736,8 +737,7 @@ public:
|
|||
FUNC2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting)
|
||||
FUNC2(instance_geometry_set_material_override, RID, RID)
|
||||
|
||||
FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float)
|
||||
FUNC2(instance_geometry_set_as_instance_lod, RID, RID)
|
||||
FUNC5(instance_geometry_set_visibility_range, RID, float, float, float, float)
|
||||
FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
|
||||
FUNC2(instance_geometry_set_lod_bias, RID, float)
|
||||
|
||||
|
|
|
@ -1725,11 +1725,11 @@ void RenderingServer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton);
|
||||
ClassDB::bind_method(D_METHOD("instance_set_exterior", "instance", "enabled"), &RenderingServer::instance_set_exterior);
|
||||
ClassDB::bind_method(D_METHOD("instance_set_extra_visibility_margin", "instance", "margin"), &RenderingServer::instance_set_extra_visibility_margin);
|
||||
ClassDB::bind_method(D_METHOD("instance_set_visibility_parent", "instance", "parent"), &RenderingServer::instance_set_visibility_parent);
|
||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &RenderingServer::instance_geometry_set_flag);
|
||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &RenderingServer::instance_geometry_set_cast_shadows_setting);
|
||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &RenderingServer::instance_geometry_set_material_override);
|
||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_draw_range", "instance", "min", "max", "min_margin", "max_margin"), &RenderingServer::instance_geometry_set_draw_range);
|
||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_as_instance_lod", "instance", "as_lod_of_instance"), &RenderingServer::instance_geometry_set_as_instance_lod);
|
||||
ClassDB::bind_method(D_METHOD("instance_geometry_set_visibility_range", "instance", "min", "max", "min_margin", "max_margin"), &RenderingServer::instance_geometry_set_visibility_range);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &RenderingServer::_instances_cull_aabb_bind, DEFVAL(RID()));
|
||||
ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &RenderingServer::_instances_cull_ray_bind, DEFVAL(RID()));
|
||||
|
|
|
@ -1172,6 +1172,7 @@ public:
|
|||
virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0;
|
||||
|
||||
virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0;
|
||||
virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0;
|
||||
|
||||
// don't use these in a game!
|
||||
virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0;
|
||||
|
@ -1201,8 +1202,7 @@ public:
|
|||
virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) = 0;
|
||||
virtual void instance_geometry_set_material_override(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;
|
||||
virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0;
|
||||
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice) = 0;
|
||||
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0;
|
||||
|
||||
|
|
Loading…
Reference in a new issue