summaryrefslogtreecommitdiffstats
path: root/servers/rendering/renderer_scene_cull.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_scene_cull.cpp')
-rw-r--r--servers/rendering/renderer_scene_cull.cpp238
1 files changed, 154 insertions, 84 deletions
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index c5eabba326..b8f14bb611 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -33,10 +33,26 @@
#include "core/config/project_settings.h"
#include "core/object/worker_thread_pool.h"
#include "core/os/os.h"
+#include "rendering_light_culler.h"
#include "rendering_server_default.h"
#include <new>
+/* HALTON SEQUENCE */
+
+#ifndef _3D_DISABLED
+static float get_halton_value(int p_index, int p_base) {
+ float f = 1;
+ float r = 0;
+ while (p_index > 0) {
+ f = f / static_cast<float>(p_base);
+ r = r + f * (p_index % p_base);
+ p_index = p_index / p_base;
+ }
+ return r * 2.0f - 1.0f;
+}
+#endif // _3D_DISABLED
+
/* CAMERA API */
RID RendererSceneCull::camera_allocate() {
@@ -48,7 +64,7 @@ void RendererSceneCull::camera_initialize(RID p_rid) {
void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->type = Camera::PERSPECTIVE;
camera->fov = p_fovy_degrees;
camera->znear = p_z_near;
@@ -57,7 +73,7 @@ void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degree
void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->type = Camera::ORTHOGONAL;
camera->size = p_size;
camera->znear = p_z_near;
@@ -66,7 +82,7 @@ void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float
void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->type = Camera::FRUSTUM;
camera->size = p_size;
camera->offset = p_offset;
@@ -76,32 +92,32 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p
void RendererSceneCull::camera_set_transform(RID p_camera, const Transform3D &p_transform) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->transform = p_transform.orthonormalized();
}
void RendererSceneCull::camera_set_cull_mask(RID p_camera, uint32_t p_layers) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->visible_layers = p_layers;
}
void RendererSceneCull::camera_set_environment(RID p_camera, RID p_env) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->env = p_env;
}
void RendererSceneCull::camera_set_camera_attributes(RID p_camera, RID p_attributes) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->attributes = p_attributes;
}
void RendererSceneCull::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) {
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
camera->vaspect = p_enable;
}
@@ -143,7 +159,7 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) {
light->geometries.insert(A);
if (geom->can_cast_shadows) {
- light->shadow_dirty = true;
+ light->make_shadow_dirty();
}
if (A->scenario && A->array_index >= 0) {
@@ -250,7 +266,7 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) {
light->geometries.erase(A);
if (geom->can_cast_shadows) {
- light->shadow_dirty = true;
+ light->make_shadow_dirty();
}
if (A->scenario && A->array_index >= 0) {
@@ -375,25 +391,25 @@ void RendererSceneCull::scenario_initialize(RID p_rid) {
void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environment) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND(!scenario);
+ ERR_FAIL_NULL(scenario);
scenario->environment = p_environment;
}
void RendererSceneCull::scenario_set_camera_attributes(RID p_scenario, RID p_camera_attributes) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND(!scenario);
+ ERR_FAIL_NULL(scenario);
scenario->camera_attributes = p_camera_attributes;
}
void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_environment) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND(!scenario);
+ ERR_FAIL_NULL(scenario);
scenario->fallback_environment = p_environment;
}
void RendererSceneCull::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND(!scenario);
+ ERR_FAIL_NULL(scenario);
RSG::light_storage->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
}
@@ -403,13 +419,13 @@ bool RendererSceneCull::is_scenario(RID p_scenario) const {
RID RendererSceneCull::scenario_get_environment(RID p_scenario) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND_V(!scenario, RID());
+ ERR_FAIL_NULL_V(scenario, RID());
return scenario->environment;
}
void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND(!scenario);
+ ERR_FAIL_NULL(scenario);
if (!scenario->viewport_visibility_masks.has(p_viewport)) {
return;
}
@@ -421,7 +437,7 @@ void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario,
void RendererSceneCull::scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND(!scenario);
+ ERR_FAIL_NULL(scenario);
ERR_FAIL_COND(scenario->viewport_visibility_masks.has(p_viewport));
uint64_t new_mask = 1;
@@ -495,7 +511,7 @@ void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) {
void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
Scenario *scenario = instance->scenario;
@@ -738,7 +754,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->scenario) {
instance->scenario->instances.remove(&instance->scenario_item);
@@ -804,7 +820,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
if (p_scenario.is_valid()) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND(!scenario);
+ ERR_FAIL_NULL(scenario);
instance->scenario = scenario;
@@ -837,7 +853,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->layer_mask == p_mask) {
return;
@@ -856,7 +872,7 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
if (geom->can_cast_shadows) {
for (HashSet<RendererSceneCull::Instance *>::Iterator I = geom->lights.begin(); I != geom->lights.end(); ++I) {
InstanceLightData *light = static_cast<InstanceLightData *>((*I)->base_data);
- light->shadow_dirty = true;
+ light->make_shadow_dirty();
}
}
}
@@ -864,7 +880,7 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask)
void RendererSceneCull::instance_set_pivot_data(RID p_instance, float p_sorting_offset, bool p_use_aabb_center) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->sorting_offset = p_sorting_offset;
instance->use_aabb_center = p_use_aabb_center;
@@ -881,7 +897,7 @@ void RendererSceneCull::instance_set_pivot_data(RID p_instance, float p_sorting_
void RendererSceneCull::instance_geometry_set_transparency(RID p_instance, float p_transparency) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->transparency = p_transparency;
@@ -894,7 +910,7 @@ void RendererSceneCull::instance_geometry_set_transparency(RID p_instance, float
void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D &p_transform) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->transform == p_transform) {
return; //must be checked to avoid worst evil
@@ -914,14 +930,14 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D
void RendererSceneCull::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->object_id = p_id;
}
void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->update_item.in_list()) {
_update_dirty_instance(instance);
@@ -934,7 +950,7 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh
void RendererSceneCull::instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->base_type == RS::INSTANCE_MESH) {
//may not have been updated yet, may also have not been set yet. When updated will be correcte, worst case
@@ -950,7 +966,7 @@ void RendererSceneCull::instance_set_surface_override_material(RID p_instance, i
void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->visible == p_visible) {
return;
@@ -1000,7 +1016,7 @@ inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
ERR_FAIL_COND(!is_geometry_instance(instance->base_type));
if (p_aabb != AABB()) {
@@ -1025,7 +1041,7 @@ void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->skeleton == p_skeleton) {
return;
@@ -1051,7 +1067,7 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton)
void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->extra_margin = p_margin;
_instance_queue_update(instance, true, false);
@@ -1059,7 +1075,7 @@ void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, rea
void RendererSceneCull::instance_set_ignore_culling(RID p_instance, bool p_enabled) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->ignore_all_culling = p_enabled;
if (instance->scenario && instance->array_index >= 0) {
@@ -1075,7 +1091,7 @@ void RendererSceneCull::instance_set_ignore_culling(RID p_instance, bool p_enabl
Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const {
Vector<ObjectID> instances;
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND_V(!scenario, instances);
+ ERR_FAIL_NULL_V(scenario, instances);
const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling
@@ -1099,7 +1115,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID
Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
Vector<ObjectID> instances;
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND_V(!scenario, instances);
+ ERR_FAIL_NULL_V(scenario, instances);
const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling
struct CullRay {
@@ -1122,7 +1138,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, co
Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const {
Vector<ObjectID> instances;
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
- ERR_FAIL_COND_V(!scenario, instances);
+ ERR_FAIL_NULL_V(scenario, instances);
const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling
Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&p_convex[0], p_convex.size());
@@ -1146,7 +1162,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p
void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
//ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK));
@@ -1223,7 +1239,7 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF
void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->cast_shadows = p_shadow_casting_setting;
@@ -1255,7 +1271,7 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc
void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, RID p_material) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->material_override = p_material;
_instance_queue_update(instance, false, true);
@@ -1269,7 +1285,7 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance,
void RendererSceneCull::instance_geometry_set_material_overlay(RID p_instance, RID p_material) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->material_overlay = p_material;
_instance_queue_update(instance, false, true);
@@ -1283,7 +1299,7 @@ void RendererSceneCull::instance_geometry_set_material_overlay(RID p_instance, R
void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->visibility_range_begin = p_min;
instance->visibility_range_end = p_max;
@@ -1305,7 +1321,7 @@ void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, f
void RendererSceneCull::instance_set_visibility_parent(RID p_instance, RID p_parent_instance) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
Instance *old_parent = instance->visibility_parent;
if (old_parent) {
@@ -1425,7 +1441,7 @@ void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_ins
void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
if (instance->lightmap) {
InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(((Instance *)instance->lightmap)->base_data);
@@ -1456,7 +1472,7 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig
void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
instance->lod_bias = p_lod_bias;
@@ -1469,7 +1485,7 @@ void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_l
void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) {
Instance *instance = instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
@@ -1507,7 +1523,7 @@ void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, c
Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const {
const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!instance, Variant());
+ ERR_FAIL_NULL_V(instance, Variant());
if (instance->instance_shader_uniforms.has(p_parameter)) {
return instance->instance_shader_uniforms[p_parameter].value;
@@ -1517,7 +1533,7 @@ Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance
Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const {
const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!instance, Variant());
+ ERR_FAIL_NULL_V(instance, Variant());
if (instance->instance_shader_uniforms.has(p_parameter)) {
return instance->instance_shader_uniforms[p_parameter].default_value;
@@ -1527,7 +1543,7 @@ Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(
void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const {
const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!instance);
+ ERR_FAIL_NULL(instance);
const_cast<RendererSceneCull *>(this)->update_dirty_instances();
@@ -1550,7 +1566,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
RSG::light_storage->light_instance_set_transform(light->instance, p_instance->transform);
RSG::light_storage->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb));
- light->shadow_dirty = true;
+ light->make_shadow_dirty();
RS::LightBakeMode bake_mode = RSG::light_storage->light_get_bake_mode(p_instance->base);
if (RSG::light_storage->light_get_type(p_instance->base) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode) {
@@ -1635,7 +1651,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (geom->can_cast_shadows) {
for (const Instance *E : geom->lights) {
InstanceLightData *light = static_cast<InstanceLightData *>(E->base_data);
- light->shadow_dirty = true;
+ light->make_shadow_dirty();
}
}
@@ -1805,7 +1821,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
pair.pair_mask |= RS::INSTANCE_GEOMETRY_MASK;
pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY];
- if (RSG::light_storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) {
+ RS::LightBakeMode bake_mode = RSG::light_storage->light_get_bake_mode(p_instance->base);
+ if (bake_mode == RS::LIGHT_BAKE_STATIC || bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI);
pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES];
}
@@ -1970,7 +1987,6 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) {
}
}
- // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs
if (p_instance->extra_margin) {
new_aabb.grow_by(p_instance->extra_margin);
}
@@ -2060,6 +2076,9 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance)
}
void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) {
+ // For later tight culling, the light culler needs to know the details of the directional light.
+ light_culler->prepare_directional_light(p_instance, p_shadow_index);
+
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
Transform3D light_transform = p_instance->transform;
@@ -2224,7 +2243,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
// This trick here is what stabilizes the shadow (make potential jaggies to not move)
// at the cost of some wasted resolution. Still, the quality increase is very well worth it.
- const real_t unit = (radius + soft_shadow_expand) * 2.0 / texture_size;
+ const real_t unit = (radius + soft_shadow_expand) * 4.0 / texture_size;
x_max_cam = Math::snapped(x_vec.dot(center) + radius + soft_shadow_expand, unit);
x_min_cam = Math::snapped(x_vec.dot(center) - radius - soft_shadow_expand, unit);
y_max_cam = Math::snapped(y_vec.dot(center) + radius + soft_shadow_expand, unit);
@@ -2330,6 +2349,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
+ if (!light->is_shadow_update_full()) {
+ light_culler->cull_regular_light(instance_shadow_cull_result);
+ }
+
for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {
Instance *instance = instance_shadow_cull_result[j];
if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) {
@@ -2408,6 +2431,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
+ if (!light->is_shadow_update_full()) {
+ light_culler->cull_regular_light(instance_shadow_cull_result);
+ }
+
for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {
Instance *instance = instance_shadow_cull_result[j];
if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) {
@@ -2471,6 +2498,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++];
+ if (!light->is_shadow_update_full()) {
+ light_culler->cull_regular_light(instance_shadow_cull_result);
+ }
+
for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) {
Instance *instance = instance_shadow_cull_result[j];
if (!instance->visible || !((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows || !(p_visible_layers & instance->layer_mask)) {
@@ -2499,15 +2530,26 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
return animated_material_found;
}
-void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, bool p_use_taa, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) {
+void RendererSceneCull::render_camera(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, uint32_t p_jitter_phase_count, float p_screen_mesh_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) {
#ifndef _3D_DISABLED
Camera *camera = camera_owner.get_or_null(p_camera);
- ERR_FAIL_COND(!camera);
+ ERR_FAIL_NULL(camera);
Vector2 jitter;
- if (p_use_taa) {
- jitter = taa_jitter_array[RSG::rasterizer->get_frame_number() % TAA_JITTER_COUNT] / p_viewport_size;
+ if (p_jitter_phase_count > 0) {
+ uint32_t current_jitter_count = camera_jitter_array.size();
+ if (p_jitter_phase_count != current_jitter_count) {
+ // Resize the jitter array and fill it with the pre-computed Halton sequence.
+ camera_jitter_array.resize(p_jitter_phase_count);
+
+ for (uint32_t i = current_jitter_count; i < p_jitter_phase_count; i++) {
+ camera_jitter_array[i].x = get_halton_value(i, 2);
+ camera_jitter_array[i].y = get_halton_value(i, 3);
+ }
+ }
+
+ jitter = camera_jitter_array[RSG::rasterizer->get_frame_number() % p_jitter_phase_count] / p_viewport_size;
}
RendererSceneRender::CameraData camera_data;
@@ -2914,6 +2956,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
}
for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) {
+ if (!light_culler->cull_directional_light(cull_data.scenario->instance_aabbs[i], j)) {
+ continue;
+ }
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;
@@ -2966,6 +3011,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, 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_mesh_lod_threshold, bool p_using_shadows, RenderingMethod::RenderInfo *r_render_info) {
Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it
+ // Prepare the light - camera volume culling system.
+ light_culler->prepare_camera(p_camera_data->main_transform, p_camera_data->main_projection);
+
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(p_render_buffers.is_null());
@@ -3100,6 +3148,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
#ifdef DEBUG_CULL_TIME
uint64_t time_from = OS::get_singleton()->get_ticks_usec();
#endif
+
if (cull_to > thread_cull_threshold) {
//multiple threads
for (InstanceCullResult &thread : scene_cull_result_threads) {
@@ -3237,9 +3286,31 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
}
}
- if (light->shadow_dirty) {
- light->last_version++;
- light->shadow_dirty = false;
+ // We can detect whether multiple cameras are hitting this light, whether or not the shadow is dirty,
+ // so that we can turn off tighter caster culling.
+ light->detect_light_intersects_multiple_cameras(Engine::get_singleton()->get_frames_drawn());
+
+ if (light->is_shadow_dirty()) {
+ // Dirty shadows have no need to be drawn if
+ // the light volume doesn't intersect the camera frustum.
+
+ // Returns false if the entire light can be culled.
+ bool allow_redraw = light_culler->prepare_regular_light(*ins);
+
+ // Directional lights aren't handled here, _light_instance_update_shadow is called from elsewhere.
+ // Checking for this in case this changes, as this is assumed.
+ DEV_CHECK_ONCE(RSG::light_storage->light_get_type(ins->base) != RS::LIGHT_DIRECTIONAL);
+
+ // Tighter caster culling to the camera frustum should work correctly with multiple viewports + cameras.
+ // The first camera will cull tightly, but if the light is present on more than 1 camera, the second will
+ // do a full render, and mark the light as non-dirty.
+ // There is however a cost to tighter shadow culling in this situation (2 shadow updates in 1 frame),
+ // so we should detect this and switch off tighter caster culling automatically.
+ // This is done in the logic for `decrement_shadow_dirty()`.
+ if (allow_redraw) {
+ light->last_version++;
+ light->decrement_shadow_dirty();
+ }
}
bool redraw = RSG::light_storage->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version);
@@ -3247,10 +3318,14 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) {
//must redraw!
RENDER_TIMESTAMP("> Render Light3D " + itos(i));
- light->shadow_dirty = _light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_mesh_lod_threshold, p_visible_layers);
+ if (_light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_mesh_lod_threshold, p_visible_layers)) {
+ light->make_shadow_dirty();
+ }
RENDER_TIMESTAMP("< Render Light3D " + itos(i));
} else {
- light->shadow_dirty = redraw;
+ if (redraw) {
+ light->make_shadow_dirty();
+ }
}
}
}
@@ -3372,7 +3447,7 @@ void RendererSceneCull::render_empty_scene(const Ref<RenderSceneBuffers> &p_rend
bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int p_step) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
Scenario *scenario = p_instance->scenario;
- ERR_FAIL_COND_V(!scenario, true);
+ ERR_FAIL_NULL_V(scenario, true);
RenderingServerDefault::redraw_request(); //update, so it updates in editor
@@ -3927,7 +4002,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
//ability to cast shadows change, let lights now
for (const Instance *E : geom->lights) {
InstanceLightData *light = static_cast<InstanceLightData *>(E->base_data);
- light->shadow_dirty = true;
+ light->make_shadow_dirty();
}
geom->can_cast_shadows = can_cast_shadows;
@@ -3994,11 +4069,12 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
}
void RendererSceneCull::update_dirty_instances() {
- RSG::utilities->update_dirty_resources();
-
while (_instance_update_list.first()) {
_update_dirty_instance(_instance_update_list.first()->self());
}
+
+ // Update dirty resources after dirty instances as instance updates may affect resources.
+ RSG::utilities->update_dirty_resources();
}
void RendererSceneCull::update() {
@@ -4044,7 +4120,7 @@ bool RendererSceneCull::free(RID p_rid) {
scenario_owner.free(p_rid);
RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid);
- } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) {
+ } else if (RendererSceneOcclusionCull::get_singleton() && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) {
RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid);
} else if (instance_owner.owns(p_rid)) {
// delete the instance
@@ -4113,17 +4189,6 @@ void RendererSceneCull::set_scene_render(RendererSceneRender *p_scene_render) {
geometry_instance_pair_mask = scene_render->geometry_instance_get_pair_mask();
}
-float get_halton_value(int index, int base) {
- float f = 1;
- float r = 0;
- while (index > 0) {
- f = f / static_cast<float>(base);
- r = r + f * (index % base);
- index = index / base;
- }
- return r * 2.0f - 1.0f;
-};
-
RendererSceneCull::RendererSceneCull() {
render_pass = 1;
singleton = this;
@@ -4148,13 +4213,13 @@ RendererSceneCull::RendererSceneCull() {
thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances");
thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)WorkerThreadPool::get_singleton()->get_thread_count()); //make sure there is at least one thread per CPU
- taa_jitter_array.resize(TAA_JITTER_COUNT);
- for (int i = 0; i < TAA_JITTER_COUNT; i++) {
- taa_jitter_array[i].x = get_halton_value(i, 2);
- taa_jitter_array[i].y = get_halton_value(i, 3);
- }
-
dummy_occlusion_culling = memnew(RendererSceneOcclusionCull);
+
+ light_culler = memnew(RenderingLightCuller);
+
+ bool tighter_caster_culling = GLOBAL_DEF("rendering/lights_and_shadows/tighter_shadow_caster_culling", true);
+ light_culler->set_caster_culling_active(tighter_caster_culling);
+ light_culler->set_light_culling_active(tighter_caster_culling);
}
RendererSceneCull::~RendererSceneCull() {
@@ -4177,4 +4242,9 @@ RendererSceneCull::~RendererSceneCull() {
if (dummy_occlusion_culling) {
memdelete(dummy_occlusion_culling);
}
+
+ if (light_culler) {
+ memdelete(light_culler);
+ light_culler = nullptr;
+ }
}