diff options
Diffstat (limited to 'servers/rendering/renderer_scene_cull.cpp')
-rw-r--r-- | servers/rendering/renderer_scene_cull.cpp | 238 |
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; + } } |