diff options
Diffstat (limited to 'servers/rendering/renderer_scene_cull.cpp')
-rw-r--r-- | servers/rendering/renderer_scene_cull.cpp | 2129 |
1 files changed, 1310 insertions, 819 deletions
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 2e32c69cba..558516ac7c 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -39,13 +39,15 @@ /* CAMERA API */ -RID RendererSceneCull::camera_create() { - Camera *camera = memnew(Camera); - return camera_owner.make_rid(camera); +RID RendererSceneCull::camera_allocate() { + return camera_owner.allocate_rid(); +} +void RendererSceneCull::camera_initialize(RID p_rid) { + camera_owner.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.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->type = Camera::PERSPECTIVE; camera->fov = p_fovy_degrees; @@ -54,7 +56,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.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->type = Camera::ORTHOGONAL; camera->size = p_size; @@ -63,7 +65,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.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->type = Camera::FRUSTUM; camera->size = p_size; @@ -72,33 +74,33 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p camera->zfar = p_z_far; } -void RendererSceneCull::camera_set_transform(RID p_camera, const Transform &p_transform) { - Camera *camera = camera_owner.getornull(p_camera); +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); camera->transform = p_transform.orthonormalized(); } void RendererSceneCull::camera_set_cull_mask(RID p_camera, uint32_t p_layers) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->visible_layers = p_layers; } void RendererSceneCull::camera_set_environment(RID p_camera, RID p_env) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->env = p_env; } void RendererSceneCull::camera_set_camera_effects(RID p_camera, RID p_fx) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->effects = p_fx; } void RendererSceneCull::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->vaspect = p_enable; } @@ -107,6 +109,20 @@ bool RendererSceneCull::is_camera(RID p_camera) const { return camera_owner.owns(p_camera); } +/* OCCLUDER API */ + +RID RendererSceneCull::occluder_allocate() { + return RendererSceneOcclusionCull::get_singleton()->occluder_allocate(); +} + +void RendererSceneCull::occluder_initialize(RID p_rid) { + RendererSceneOcclusionCull::get_singleton()->occluder_initialize(p_rid); +} + +void RendererSceneCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { + RendererSceneOcclusionCull::get_singleton()->occluder_set_mesh(p_occluder, p_vertices, p_indices); +} + /* SCENARIO API */ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { @@ -135,7 +151,23 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + if (light->uses_projector) { + geom->projector_count++; + if (geom->projector_count == 1) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY; + } + } + + if (light->uses_softshadow) { + geom->softshadow_count++; + if (geom->softshadow_count == 1) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY; + } + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); @@ -147,7 +179,7 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); @@ -174,28 +206,29 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture } - } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - geom->gi_probes.insert(B); + geom->voxel_gi_instances.insert(B); if (A->dynamic_gi) { - gi_probe->dynamic_geometries.insert(A); + voxel_gi->dynamic_geometries.insert(A); } else { - gi_probe->geometries.insert(A); + voxel_gi->geometries.insert(A); } if (A->scenario && A->array_index >= 0) { InstanceData &idata = A->scenario->instance_data[A->array_index]; - idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY; } - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - gi_probe->lights.insert(A); + } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); + voxel_gi->lights.insert(A); } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_add_collision(A->base, B); + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); + RSG::storage->particles_add_collision(A->base, collision->instance); } } @@ -225,7 +258,33 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_LIGHTING_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + if (light->uses_projector) { +#ifdef DEBUG_ENABLED + if (geom->projector_count == 0) { + ERR_PRINT("geom->projector_count==0 - BUG!"); + } +#endif + geom->projector_count--; + if (geom->projector_count == 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY; + } + } + + if (light->uses_softshadow) { +#ifdef DEBUG_ENABLED + if (geom->softshadow_count == 0) { + ERR_PRINT("geom->softshadow_count==0 - BUG!"); + } +#endif + geom->softshadow_count--; + if (geom->softshadow_count == 0) { + InstanceData &idata = A->scenario->instance_data[A->array_index]; + idata.flags |= InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY; + } + } + + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); @@ -237,7 +296,7 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { idata.flags |= InstanceData::FLAG_GEOM_REFLECTION_DIRTY; } - } else if (self->pair_volumes_to_mesh && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && B->base_type == RS::INSTANCE_DECAL && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { InstanceDecalData *decal = static_cast<InstanceDecalData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); @@ -264,35 +323,39 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture } - } else if (B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - geom->gi_probes.erase(B); + geom->voxel_gi_instances.erase(B); if (A->dynamic_gi) { - gi_probe->dynamic_geometries.erase(A); + voxel_gi->dynamic_geometries.erase(A); } else { - gi_probe->geometries.erase(A); + voxel_gi->geometries.erase(A); } if (A->scenario && A->array_index >= 0) { InstanceData &idata = A->scenario->instance_data[A->array_index]; - idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY; } - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - gi_probe->lights.erase(A); + } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); + voxel_gi->lights.erase(A); } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { - RSG::storage->particles_remove_collision(A->base, B); + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); + RSG::storage->particles_remove_collision(A->base, collision->instance); } } -RID RendererSceneCull::scenario_create() { - Scenario *scenario = memnew(Scenario); - ERR_FAIL_COND_V(!scenario, RID()); - RID scenario_rid = scenario_owner.make_rid(scenario); - scenario->self = scenario_rid; +RID RendererSceneCull::scenario_allocate() { + return scenario_owner.allocate_rid(); +} +void RendererSceneCull::scenario_initialize(RID p_rid) { + scenario_owner.initialize_rid(p_rid); + + Scenario *scenario = scenario_owner.get_or_null(p_rid); + scenario->self = p_rid; scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create(); scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest @@ -304,36 +367,31 @@ RID RendererSceneCull::scenario_create() { 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); - return scenario_rid; -} - -void RendererSceneCull::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->debug = p_debug_mode; + RendererSceneOcclusionCull::get_singleton()->add_scenario(p_rid); } void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); scenario->environment = p_environment; } void RendererSceneCull::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); scenario->camera_effects = p_camera_effects; } void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!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.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count); } @@ -343,11 +401,42 @@ bool RendererSceneCull::is_scenario(RID p_scenario) const { } RID RendererSceneCull::scenario_get_environment(RID p_scenario) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_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); + 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.get_or_null(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) { @@ -365,14 +454,13 @@ void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_upda _instance_update_list.add(&p_instance->update_item); } -RID RendererSceneCull::instance_create() { - Instance *instance = memnew(Instance); - ERR_FAIL_COND_V(!instance, RID()); - - RID instance_rid = instance_owner.make_rid(instance); - instance->self = instance_rid; - - return instance_rid; +RID RendererSceneCull::instance_allocate() { + return instance_owner.allocate_rid(); +} +void RendererSceneCull::instance_initialize(RID p_rid) { + instance_owner.initialize_rid(p_rid); + Instance *instance = instance_owner.get_or_null(p_rid); + instance->self = p_rid; } void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) { @@ -386,6 +474,9 @@ void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) { p_instance->mesh_instance = RID(); } + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + scene_render->geometry_instance_set_mesh_instance(geom->geometry_instance, p_instance->mesh_instance); + if (p_instance->scenario && p_instance->array_index >= 0) { InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; if (p_instance->mesh_instance.is_valid()) { @@ -402,7 +493,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.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); Scenario *scenario = instance->scenario; @@ -421,10 +512,16 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } switch (instance->base_type) { + case RS::INSTANCE_MESH: + case RS::INSTANCE_MULTIMESH: + case RS::INSTANCE_PARTICLES: { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_free(geom->geometry_instance); + } break; case RS::INSTANCE_LIGHT: { InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); - if (scenario && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + if (scenario && instance->visible && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { scenario->dynamic_lights.erase(light->instance); } @@ -439,6 +536,13 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } scene_render->free(light->instance); } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); + RSG::storage->free(collision->instance); + } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + //none + } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); scene_render->free(reflection_probe->instance); @@ -457,26 +561,32 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { while (lightmap_data->users.front()) { instance_geometry_set_lightmap(lightmap_data->users.front()->get()->self, RID(), Rect2(), 0); } + scene_render->free(lightmap_data->instance); } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data); #ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + if (voxel_gi->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI."); } #endif #ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + if (voxel_gi->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI."); } #endif - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); + if (voxel_gi->update_element.in_list()) { + voxel_gi_update_list.remove(&voxel_gi->update_element); } - scene_render->free(gi_probe->probe_instance); + scene_render->free(voxel_gi->probe_instance); } break; + case RS::INSTANCE_OCCLUDER: { + if (scenario && instance->visible) { + RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance); + } + } break; default: { } } @@ -494,6 +604,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { if (p_base.is_valid()) { instance->base_type = RSG::storage->get_base_type(p_base); + + if (instance->base_type == RS::INSTANCE_NONE && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_base)) { + instance->base_type = RS::INSTANCE_OCCLUDER; + } + ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE); switch (instance->base_type) { @@ -510,12 +625,37 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } break; case RS::INSTANCE_MESH: case RS::INSTANCE_MULTIMESH: - case RS::INSTANCE_IMMEDIATE: case RS::INSTANCE_PARTICLES: { InstanceGeometryData *geom = memnew(InstanceGeometryData); instance->base_data = geom; + geom->geometry_instance = scene_render->geometry_instance_create(p_base); + + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, instance->skeleton); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, instance->material_override); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, instance->materials); + scene_render->geometry_instance_set_transform(geom->geometry_instance, instance->transform, instance->aabb, instance->transformed_aabb); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, instance->layer_mask); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, instance->lod_bias); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, instance->baked_light); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, instance->dynamic_gi); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, RID(), instance->lightmap_uv_scale, instance->lightmap_slice_index); + if (instance->lightmap_sh.size() == 9) { + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, instance->lightmap_sh.ptr()); + } } break; + case RS::INSTANCE_PARTICLES_COLLISION: { + InstanceParticlesCollisionData *collision = memnew(InstanceParticlesCollisionData); + collision->instance = RSG::storage->particles_collision_instance_create(p_base); + RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible); + instance->base_data = collision; + } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + InstanceVisibilityNotifierData *vnd = memnew(InstanceVisibilityNotifierData); + vnd->base = p_base; + instance->base_data = vnd; + } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); reflection_probe->owner = instance; @@ -533,20 +673,25 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { case RS::INSTANCE_LIGHTMAP: { InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData); instance->base_data = lightmap_data; - //lightmap_data->instance = scene_render->lightmap_data_instance_create(p_base); + lightmap_data->instance = scene_render->lightmap_instance_create(p_base); } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); - instance->base_data = gi_probe; - gi_probe->owner = instance; + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = memnew(InstanceVoxelGIData); + instance->base_data = voxel_gi; + voxel_gi->owner = instance; - if (scenario && !gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); + if (scenario && !voxel_gi->update_element.in_list()) { + voxel_gi_update_list.add(&voxel_gi->update_element); } - gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base); + voxel_gi->probe_instance = scene_render->voxel_gi_instance_create(p_base); } break; + case RS::INSTANCE_OCCLUDER: { + if (scenario) { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, p_base, instance->transform, instance->visible); + } + } break; default: { } } @@ -558,14 +703,14 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } //forcefully update the dependency now, so if for some reason it gets removed, we can immediately clear it - RSG::storage->base_update_dependency(p_base, instance); + RSG::storage->base_update_dependency(p_base, &instance->dependency_tracker); } _instance_queue_update(instance, true, true); } void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->scenario) { @@ -596,22 +741,27 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { case RS::INSTANCE_PARTICLES_COLLISION: { heightfield_particle_colliders_update_list.erase(instance); } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data); #ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + if (voxel_gi->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI."); } #endif #ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + if (voxel_gi->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI."); } #endif - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); + if (voxel_gi->update_element.in_list()) { + voxel_gi_update_list.remove(&voxel_gi->update_element); + } + } break; + case RS::INSTANCE_OCCLUDER: { + if (instance->visible) { + RendererSceneOcclusionCull::get_singleton()->scenario_remove_instance(instance->scenario->self, p_instance); } } break; default: { @@ -622,7 +772,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { } if (p_scenario.is_valid()) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); instance->scenario = scenario; @@ -637,12 +787,15 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { light->D = scenario->directional_lights.push_back(instance); } } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data); + if (!voxel_gi->update_element.in_list()) { + voxel_gi_update_list.add(&voxel_gi->update_element); } } break; + case RS::INSTANCE_OCCLUDER: { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(scenario->self, p_instance, instance->base, instance->transform, instance->visible); + } break; default: { } } @@ -652,17 +805,22 @@ 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.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->layer_mask = p_mask; if (instance->scenario && instance->array_index >= 0) { instance->scenario->instance_data[instance->array_index].layer_mask = p_mask; } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_layer_mask(geom->geometry_instance, p_mask); + } } -void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &p_transform) { - Instance *instance = instance_owner.getornull(p_instance); +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); if (instance->transform == p_transform) { @@ -687,14 +845,14 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform & } void RendererSceneCull::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!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.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->update_item.in_list()) { @@ -706,8 +864,8 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh } } -void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); +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); if (instance->base_type == RS::INSTANCE_MESH) { @@ -723,7 +881,7 @@ void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surf } void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->visible == p_visible) { @@ -739,14 +897,36 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { } else if (instance->indexer_id.is_valid()) { _unpair_instance(instance); } + + if (instance->base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data); + if (instance->scenario && RSG::storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + if (p_visible) { + instance->scenario->dynamic_lights.push_back(light->instance); + } else { + instance->scenario->dynamic_lights.erase(light->instance); + } + } + } + + if (instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); + RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible); + } + + if (instance->base_type == RS::INSTANCE_OCCLUDER) { + if (instance->scenario) { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(instance->scenario->self, p_instance, instance->base, instance->transform, p_visible); + } + } } inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { - return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE; + return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES; } void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); @@ -771,7 +951,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.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->skeleton == p_skeleton) { @@ -782,19 +962,21 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) if (p_skeleton.is_valid()) { //update the dependency now, so if cleared, we remove it - RSG::storage->skeleton_update_dependency(p_skeleton, instance); + RSG::storage->skeleton_update_dependency(p_skeleton, &instance->dependency_tracker); } - _instance_update_mesh_instance(instance); - _instance_queue_update(instance, true, true); -} -void RendererSceneCull::instance_set_exterior(RID p_instance, bool p_enabled) { + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + _instance_update_mesh_instance(instance); + + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_skeleton(geom->geometry_instance, p_skeleton); + } } void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->extra_margin = p_margin; @@ -803,7 +985,7 @@ void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, rea Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const { Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_V(!scenario, instances); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling @@ -827,7 +1009,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.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_V(!scenario, instances); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling @@ -850,7 +1032,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.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_V(!scenario, instances); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling @@ -874,7 +1056,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.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); //ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK)); @@ -892,6 +1074,11 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF } } + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_baked_light(geom->geometry_instance, p_enabled); + } + } break; case RS::INSTANCE_FLAG_USE_DYNAMIC_GI: { if (p_enabled == instance->dynamic_gi) { @@ -907,6 +1094,11 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF //once out of octree, can be changed instance->dynamic_gi = p_enabled; + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, p_enabled); + } + } break; case RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { instance->redraw_if_visible = p_enabled; @@ -921,13 +1113,25 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF } } break; + case RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING: { + instance->ignore_occlusion_culling = p_enabled; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + if (instance->ignore_occlusion_culling) { + idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_IGNORE_OCCLUSION_CULLING); + } + } + } break; default: { } } } void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->cast_shadows = p_shadow_casting_setting; @@ -948,25 +1152,167 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc } } + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); + } + _instance_queue_update(instance, false, true); } void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->material_override = p_material; _instance_queue_update(instance, false, true); + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_material_override(geom->geometry_instance, p_material); + } +} + +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.get_or_null(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_set_visibility_parent(RID p_instance, RID p_parent_instance) { + Instance *instance = instance_owner.get_or_null(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.get_or_null(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::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { +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 dependencies 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::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) { +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_center(); + 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) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->lightmap) { @@ -975,33 +1321,48 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig instance->lightmap = nullptr; } - Instance *lightmap_instance = instance_owner.getornull(p_lightmap); + Instance *lightmap_instance = instance_owner.get_or_null(p_lightmap); instance->lightmap = lightmap_instance; instance->lightmap_uv_scale = p_lightmap_uv_scale; instance->lightmap_slice_index = p_slice_index; + RID lightmap_instance_rid; + if (lightmap_instance) { InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(lightmap_instance->base_data); lightmap_data->users.insert(instance); + lightmap_instance_rid = lightmap_data->instance; + } + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, lightmap_instance_rid, p_lightmap_uv_scale, p_slice_index); } } void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->lod_bias = p_lod_bias; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_lod_bias(geom->geometry_instance, p_lod_bias); + } } void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); - Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter); + ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT); + + Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter); if (!E) { - RendererSceneRender::InstanceBase::InstanceShaderParameter isp; + Instance::InstanceShaderParameter isp; isp.index = -1; isp.info = PropertyInfo(); isp.value = p_value; @@ -1016,7 +1377,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.getornull(p_instance); + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!instance, Variant()); if (instance->instance_shader_parameters.has(p_parameter)) { @@ -1026,7 +1387,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.getornull(p_instance); + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!instance, Variant()); if (instance->instance_shader_parameters.has(p_parameter)) { @@ -1036,14 +1397,14 @@ 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.getornull(p_instance); + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); Vector<StringName> names; - for (Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { - names.push_back(E->key()); + for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : instance->instance_shader_parameters) { + names.push_back(E.key); } names.sort_custom<StringName::AlphCompare>(); for (int i = 0; i < names.size(); i++) { @@ -1064,13 +1425,13 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { RS::LightBakeMode bake_mode = RSG::storage->light_get_bake_mode(p_instance->base); if (RSG::storage->light_get_type(p_instance->base) != RS::LIGHT_DIRECTIONAL && bake_mode != light->bake_mode) { - if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + if (p_instance->visible && p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { p_instance->scenario->dynamic_lights.erase(light->instance); } light->bake_mode = bake_mode; - if (p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { + if (p_instance->visible && p_instance->scenario && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) { p_instance->scenario->dynamic_lights.push_back(light->instance); } } @@ -1079,9 +1440,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if (light->max_sdfgi_cascade != max_sdfgi_cascade) { light->max_sdfgi_cascade = max_sdfgi_cascade; //should most likely make sdfgi dirty in scenario } - } - - if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { + } else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform); @@ -1090,35 +1449,53 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY; } - } - - if (p_instance->base_type == RS::INSTANCE_DECAL) { + } else if (p_instance->base_type == RS::INSTANCE_DECAL) { InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data); scene_render->decal_instance_set_transform(decal->instance, p_instance->transform); - } - - if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data); + } else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data); - scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform); - } + scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(p_instance->base_data); - if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + scene_render->voxel_gi_instance_set_transform_to_data(voxel_gi->probe_instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); - } + } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { + InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(p_instance->base_data); - if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { //remove materials no longer used and un-own them if (RSG::storage->particles_collision_is_heightfield(p_instance->base)) { heightfield_particle_colliders_update_list.insert(p_instance); } + RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) { + if (p_instance->scenario) { + RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible); + } } if (p_instance->aabb.has_no_surface()) { return; } + if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { + //if this moved, update the captured objects + InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(p_instance->base_data); + //erase dependencies, since no longer a lightmap + + for (Set<Instance *>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { + Instance *geom = E->get(); + _instance_queue_update(geom, true, false); + } + } + + AABB new_aabb; + new_aabb = p_instance->transform.xform(p_instance->aabb); + p_instance->transformed_aabb = new_aabb; + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); //make sure lights are updated if it casts shadow @@ -1137,30 +1514,15 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if (!p_instance->lightmap_sh.is_empty()) { p_instance->lightmap_sh.clear(); //don't need SH p_instance->lightmap_target_sh.clear(); //don't need SH + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, nullptr); } } - } - if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) { - //if this moved, update the captured objects - InstanceLightmapData *lightmap_data = static_cast<InstanceLightmapData *>(p_instance->base_data); - //erase dependencies, since no longer a lightmap - - for (Set<Instance *>::Element *E = lightmap_data->geometries.front(); E; E = E->next()) { - Instance *geom = E->get(); - _instance_queue_update(geom, true, false); - } + scene_render->geometry_instance_set_transform(geom->geometry_instance, p_instance->transform, p_instance->aabb, p_instance->transformed_aabb); } - p_instance->mirror = p_instance->transform.basis.determinant() < 0.0; - - AABB new_aabb; - - new_aabb = p_instance->transform.xform(p_instance->aabb); - - p_instance->transformed_aabb = new_aabb; - - if (p_instance->scenario == nullptr || !p_instance->visible || Math::is_zero_approx(p_instance->transform.basis.determinant())) { + // note: we had to remove is equal approx check here, it meant that det == 0.000004 won't work, which is the case for some of our scenes. + if (p_instance->scenario == nullptr || !p_instance->visible || p_instance->transform.basis.determinant() == 0) { p_instance->prev_transformed_aabb = p_instance->transformed_aabb; return; } @@ -1194,18 +1556,44 @@ 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_PARTICLES: { + 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; + InstanceLightData *light_data = static_cast<InstanceLightData *>(p_instance->base_data); + idata.instance_data_rid = light_data->instance.get_id(); + light_data->uses_projector = RSG::storage->light_has_projector(p_instance->base); + light_data->uses_softshadow = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SIZE) > CMP_EPSILON; + } break; case RS::INSTANCE_REFLECTION_PROBE: { - idata.instance_data_rid = static_cast<InstanceReflectionProbeData *>(p_instance->base_data)->instance; + idata.instance_data_rid = static_cast<InstanceReflectionProbeData *>(p_instance->base_data)->instance.get_id(); } break; case RS::INSTANCE_DECAL: { - idata.instance_data_rid = static_cast<InstanceDecalData *>(p_instance->base_data)->instance; + idata.instance_data_rid = static_cast<InstanceDecalData *>(p_instance->base_data)->instance.get_id(); } break; - case RS::INSTANCE_GI_PROBE: { - idata.instance_data_rid = static_cast<InstanceGIProbeData *>(p_instance->base_data)->probe_instance; + case RS::INSTANCE_LIGHTMAP: { + idata.instance_data_rid = static_cast<InstanceLightmapData *>(p_instance->base_data)->instance.get_id(); + } break; + case RS::INSTANCE_VOXEL_GI: { + idata.instance_data_rid = static_cast<InstanceVoxelGIData *>(p_instance->base_data)->probe_instance.get_id(); + } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + idata.visibility_notifier = static_cast<InstanceVisibilityNotifierData *>(p_instance->base_data); } break; default: { } @@ -1231,9 +1619,13 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if (p_instance->mesh_instance.is_valid()) { idata.flags |= InstanceData::FLAG_USES_MESH_INSTANCE; } + if (p_instance->ignore_occlusion_culling) { + idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING; + } 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); @@ -1243,6 +1635,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_center(); + } + //move instance and repair pair_pass++; @@ -1255,29 +1651,33 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; - pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE; + pair.pair_mask |= 1 << RS::INSTANCE_VOXEL_GI; pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP; - - if (pair_volumes_to_mesh) { - pair.pair_mask |= 1 << RS::INSTANCE_DECAL; - pair.pair_mask |= 1 << RS::INSTANCE_REFLECTION_PROBE; + if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + pair.pair_mask |= 1 << RS::INSTANCE_PARTICLES_COLLISION; } + + pair.pair_mask |= geometry_instance_pair_mask; + pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; } else if (p_instance->base_type == RS::INSTANCE_LIGHT) { pair.pair_mask |= RS::INSTANCE_GEOMETRY_MASK; pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; if (RSG::storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) { - pair.pair_mask |= (1 << RS::INSTANCE_GI_PROBE); + pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI); pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; } - } else if (pair_volumes_to_mesh && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == RS::INSTANCE_DECAL)) { + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) { + pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; + pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; + } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (p_instance->base_type == RS::INSTANCE_DECAL)) { pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK; pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { pair.pair_mask = (1 << RS::INSTANCE_PARTICLES); pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; - } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { + } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) { //lights and geometries pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT); pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; @@ -1312,9 +1712,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 @@ -1325,11 +1740,22 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { p_instance->array_index = -1; if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { // Clear these now because the InstanceData containing the dirty flags is gone - p_instance->light_instances.clear(); - p_instance->reflection_probe_instances.clear(); - //p_instance->decal_instances.clear(); will implement later - p_instance->gi_probe_instances.clear(); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, nullptr, 0); + 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) { @@ -1358,14 +1784,6 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { } } break; - case RenderingServer::INSTANCE_IMMEDIATE: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->immediate_get_aabb(p_instance->base); - } - - } break; case RenderingServer::INSTANCE_PARTICLES: { if (p_instance->custom_aabb) { new_aabb = *p_instance->custom_aabb; @@ -1378,6 +1796,9 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); } break; + case RenderingServer::INSTANCE_VISIBLITY_NOTIFIER: { + new_aabb = RSG::storage->visibility_notifier_get_aabb(p_instance->base); + } break; case RenderingServer::INSTANCE_LIGHT: { new_aabb = RSG::storage->light_get_aabb(p_instance->base); @@ -1390,8 +1811,8 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { new_aabb = RSG::storage->decal_get_aabb(p_instance->base); } break; - case RenderingServer::INSTANCE_GI_PROBE: { - new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base); + case RenderingServer::INSTANCE_VOXEL_GI: { + new_aabb = RSG::storage->voxel_gi_get_bounds(p_instance->base); } break; case RenderingServer::INSTANCE_LIGHTMAP: { @@ -1429,8 +1850,8 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) continue; //we are inside, ignore exteriors } - Transform to_bounds = lightmap->transform.affine_inverse(); - Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center + Transform3D to_bounds = lightmap->transform.affine_inverse(); + Vector3 center = p_instance->transform.xform(p_instance->aabb.get_center()); //use aabb center Vector3 lm_pos = to_bounds.xform(center); @@ -1445,7 +1866,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) //rotate it Basis rot = lightmap->transform.basis.orthonormalized(); for (int i = 0; i < 3; i++) { - float csh[9]; + real_t csh[9]; for (int j = 0; j < 9; j++) { csh[j] = sh[j][i]; } @@ -1457,7 +1878,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0); - float blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); + real_t blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); //make blend more rounded blend = Math::lerp(inner_pos.length(), blend, blend); blend *= blend; @@ -1486,12 +1907,14 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) } } } + + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, p_instance->lightmap_sh.ptr()); } -void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) { +void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - Transform light_transform = p_instance->transform; + Transform3D light_transform = p_instance->transform; light_transform.orthonormalize(); //scale does not count on lights real_t max_distance = p_cam_projection.get_z_far(); @@ -1502,8 +1925,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); - RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); - real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); real_t range = max_distance - min_distance; @@ -1534,10 +1955,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base); - real_t first_radius = 0.0; - - real_t min_distance_bias_scale = distances[1]; - cull.shadow_count = p_shadow_index + 1; cull.shadows[p_shadow_index].cascade_count = splits; cull.shadows[p_shadow_index].light_instance = light->instance; @@ -1567,7 +1984,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in // obtain the light frustum ranges (given endpoints) - Transform transform = light_transform; //discard scale and stabilize light + Transform3D transform = light_transform; //discard scale and stabilize light Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized(); Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized(); @@ -1585,8 +2002,8 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in real_t z_min_cam = 0.f; //real_t z_max_cam = 0.f; - real_t bias_scale = 1.0; - real_t aspect_bias_scale = 1.0; + //real_t bias_scale = 1.0; + //real_t aspect_bias_scale = 1.0; //used for culling @@ -1640,12 +2057,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in radius *= texture_size / (texture_size - 2.0); //add a texel by each side - if (i == 0) { - first_radius = radius; - } else { - bias_scale = radius / first_radius; - } - z_min_cam = z_vec.dot(center) - radius; { @@ -1663,22 +2074,13 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in } } - x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; - x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; - y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; - y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; - - if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { - //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 - - real_t unit = radius * 2.0 / texture_size; - - x_max_cam = Math::snapped(x_max_cam, unit); - x_min_cam = Math::snapped(x_min_cam, unit); - y_max_cam = Math::snapped(y_max_cam, unit); - y_min_cam = Math::snapped(y_min_cam, unit); - } + // 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 * 2.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); + y_min_cam = Math::snapped(y_vec.dot(center) - radius - soft_shadow_expand, unit); } //now that we know all ranges, we can proceed to make the light frustum planes, for culling octree @@ -1698,64 +2100,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in // a pre pass will need to be needed to determine the actual z-near to be used - if (pancake_size > 0) { - z_max = z_vec.dot(center) + radius + pancake_size; - } - - if (aspect != 1.0) { - // if the aspect is different, then the radius will become larger. - // if this happens, then bias needs to be adjusted too, as depth will increase - // to do this, compare the depth of one that would have resulted from a square frustum - - CameraMatrix camera_matrix_square; - if (p_cam_orthogonal) { - Vector2 vp_he = camera_matrix.get_viewport_half_extents(); - if (p_cam_vaspect) { - camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } else { - camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } - } else { - Vector2 vp_he = camera_matrix.get_viewport_half_extents(); - if (p_cam_vaspect) { - camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true); - } else { - camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false); - } - } - - Vector3 endpoints_square[8]; // frustum plane endpoints - res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square); - ERR_CONTINUE(!res); - Vector3 center_square; - - for (int j = 0; j < 8; j++) { - center_square += endpoints_square[j]; - } - - center_square /= 8.0; - - real_t radius_square = 0; - - for (int j = 0; j < 8; j++) { - real_t d = center_square.distance_to(endpoints_square[j]); - if (d > radius_square) { - radius_square = d; - } - } - - radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side - - float z_max_square = z_vec.dot(center_square) + radius_square + pancake_size; - - real_t z_min_cam_square = z_vec.dot(center_square) - radius_square; - - aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square); - - // this is not entirely perfect, because the cull-adjusted z-max may be different - // but at least it's warranted that it results in a greater bias, so no acne should be present either way. - // pancaking also helps with this. - } + z_max = z_vec.dot(center) + radius + pancake_size; { CameraMatrix ortho_camera; @@ -1766,7 +2111,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); - Transform ortho_transform; + Transform3D ortho_transform; ortho_transform.basis = transform.basis; ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; @@ -1776,17 +2121,17 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in cull.shadows[p_shadow_index].cascades[i].zfar = z_max - z_min_cam; cull.shadows[p_shadow_index].cascades[i].split = distances[i + 1]; cull.shadows[p_shadow_index].cascades[i].shadow_texel_size = radius * 2.0 / texture_size; - cull.shadows[p_shadow_index].cascades[i].bias_scale = bias_scale * aspect_bias_scale * min_distance_bias_scale; + cull.shadows[p_shadow_index].cascades[i].bias_scale = (z_max - z_min_cam); cull.shadows[p_shadow_index].cascades[i].range_begin = z_max; cull.shadows[p_shadow_index].cascades[i].uv_scale = uv_scale; } } } -bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) { +bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - Transform light_transform = p_instance->transform; + Transform3D light_transform = p_instance->transform; light_transform.orthonormalize(); //scale does not count on lights bool animated_material_found = false; @@ -1798,6 +2143,9 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons RS::LightOmniShadowMode shadow_mode = RSG::storage->light_omni_get_shadow_mode(p_instance->base); if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !scene_render->light_instances_can_render_shadow_cube()) { + if (max_shadows_used + 2 > MAX_UPDATE_SHADOWS) { + return true; + } for (int i = 0; i < 2; i++) { //using this one ensures that raster deferred will have it RENDER_TIMESTAMP("Culling Shadow Paraboloid" + itos(i)); @@ -1814,7 +2162,6 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); planes.write[5] = light_transform.xform(Plane(Vector3(0, 0, -z), 0)); - geometry_instances_to_shadow_render.clear(); instance_shadow_cull_result.clear(); Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); @@ -1833,7 +2180,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); - Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); + RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++]; for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; @@ -1849,19 +2196,24 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons } } - geometry_instances_to_shadow_render.push_back(instance); + shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); } RSG::storage->update_mesh_instances(); scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, i, 0); - scene_render->render_shadow(light->instance, p_shadow_atlas, i, geometry_instances_to_shadow_render); + shadow_data.light = light->instance; + shadow_data.pass = i; } } else { //shadow cube + if (max_shadows_used + 6 > MAX_UPDATE_SHADOWS) { + return true; + } + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); CameraMatrix cm; - cm.set_perspective(90, 1, 0.01, radius); + cm.set_perspective(90, 1, radius * 0.005f, radius); for (int i = 0; i < 6; i++) { RENDER_TIMESTAMP("Culling Shadow Cube side" + itos(i)); @@ -1884,11 +2236,10 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons Vector3(0, -1, 0) }; - Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]); + Transform3D xform = light_transform * Transform3D().looking_at(view_normals[i], view_up[i]); Vector<Plane> planes = cm.get_projection_planes(xform); - geometry_instances_to_shadow_render.clear(); instance_shadow_cull_result.clear(); Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); @@ -1907,7 +2258,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); - Plane near_plane(xform.origin, -xform.basis.get_axis(2)); + RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++]; for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; @@ -1922,31 +2273,36 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons } } - geometry_instances_to_shadow_render.push_back(instance); + shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); } RSG::storage->update_mesh_instances(); scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0); - scene_render->render_shadow(light->instance, p_shadow_atlas, i, geometry_instances_to_shadow_render); + + shadow_data.light = light->instance; + shadow_data.pass = i; } //restore the regular DP matrix - scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); + //scene_render->light_instance_set_shadow_transform(light->instance, CameraMatrix(), light_transform, radius, 0, 0, 0); } } break; case RS::LIGHT_SPOT: { RENDER_TIMESTAMP("Culling Spot Light"); + if (max_shadows_used + 1 > MAX_UPDATE_SHADOWS) { + return true; + } + real_t radius = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_RANGE); real_t angle = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SPOT_ANGLE); CameraMatrix cm; - cm.set_perspective(angle * 2.0, 1.0, 0.01, radius); + cm.set_perspective(angle * 2.0, 1.0, 0.005f * radius, radius); Vector<Plane> planes = cm.get_projection_planes(light_transform); - geometry_instances_to_shadow_render.clear(); instance_shadow_cull_result.clear(); Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&planes[0], planes.size()); @@ -1965,7 +2321,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons p_scenario->indexers[Scenario::INDEXER_GEOMETRY].convex_query(planes.ptr(), planes.size(), points.ptr(), points.size(), cull_convex); - Plane near_plane(light_transform.origin, -light_transform.basis.get_axis(2)); + RendererSceneRender::RenderShadowData &shadow_data = render_shadow_data[max_shadows_used++]; for (int j = 0; j < (int)instance_shadow_cull_result.size(); j++) { Instance *instance = instance_shadow_cull_result[j]; @@ -1980,13 +2336,14 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons RSG::storage->mesh_instance_check_for_update(instance->mesh_instance); } } - geometry_instances_to_shadow_render.push_back(instance); + shadow_data.instances.push_back(static_cast<InstanceGeometryData *>(instance->base_data)->geometry_instance); } RSG::storage->update_mesh_instances(); scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0); - scene_render->render_shadow(light->instance, p_shadow_atlas, 0, geometry_instances_to_shadow_render); + shadow_data.light = light->instance; + shadow_data.pass = 0; } break; } @@ -1994,319 +2351,238 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons return animated_material_found; } -void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { -// render to mono camera +void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) { #ifndef _3D_DISABLED - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); - /* STEP 1 - SETUP CAMERA */ - CameraMatrix camera_matrix; - bool ortho = false; - - switch (camera->type) { - case Camera::ORTHOGONAL: { - camera_matrix.set_orthogonal( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = true; - } break; - case Camera::PERSPECTIVE: { - camera_matrix.set_perspective( - camera->fov, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; - - } break; - case Camera::FRUSTUM: { - camera_matrix.set_frustum( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->offset, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; - } break; - } - - RID environment = _render_get_environment(p_camera, p_scenario); - - _prepare_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); - _render_scene(p_render_buffers, camera->transform, camera_matrix, ortho, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); -#endif -} - -void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { - // render for AR/VR interface - - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); - - /* SETUP CAMERA, we are ignoring type and FOV here */ - float aspect = p_viewport_size.width / (float)p_viewport_size.height; - CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar); - - // We also ignore our camera position, it will have been positioned with a slightly old tracking position. - // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! - Transform world_origin = XRServer::get_singleton()->get_world_origin(); - Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); - - RID environment = _render_get_environment(p_camera, p_scenario); - - // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye - if (p_eye == XRInterface::EYE_LEFT) { - // Center our transform, we assume basis is equal. - Transform mono_transform = cam_transform; - Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); - mono_transform.origin += right_transform.origin; - mono_transform.origin *= 0.5; - - // We need to combine our projection frustums for culling. - // Ideally we should use our clipping planes for this and combine them, - // however our shadow map logic uses our projection matrix. - // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix. - - // - get some base values we need - float eye_dist = (mono_transform.origin - cam_transform.origin).length(); - float z_near = camera_matrix.get_z_near(); // get our near plane - float z_far = camera_matrix.get_z_far(); // get our far plane - float width = (2.0 * z_near) / camera_matrix.matrix[0][0]; - float x_shift = width * camera_matrix.matrix[2][0]; - float height = (2.0 * z_near) / camera_matrix.matrix[1][1]; - float y_shift = height * camera_matrix.matrix[2][1]; - - // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift); - - // - calculate our near plane size (horizontal only, right_near is mirrored) - float left_near = -eye_dist - ((width - x_shift) * 0.5); + RendererSceneRender::CameraData camera_data; + + // Setup Camera(s) + if (p_xr_interface.is_null()) { + // Normal camera + Transform3D transform = camera->transform; + CameraMatrix projection; + bool vaspect = camera->vaspect; + bool is_ortogonal = false; + + switch (camera->type) { + case Camera::ORTHOGONAL: { + projection.set_orthogonal( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); + is_ortogonal = true; + } break; + case Camera::PERSPECTIVE: { + projection.set_perspective( + camera->fov, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); - // - calculate our far plane size (horizontal only, right_far is mirrored) - float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near); - float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near); - if (left_far > left_far_right_eye) { - // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes. - left_far = left_far_right_eye; + } break; + case Camera::FRUSTUM: { + projection.set_frustum( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->offset, + camera->znear, + camera->zfar, + camera->vaspect); + } break; } - // - figure out required z-shift - float slope = (left_far - left_near) / (z_far - z_near); - float z_shift = (left_near / slope) - z_near; - - // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift) - float top_near = (height - y_shift) * 0.5; - top_near += (top_near / z_near) * z_shift; - float bottom_near = -(height + y_shift) * 0.5; - bottom_near += (bottom_near / z_near) * z_shift; - - // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift); - - // - generate our frustum - CameraMatrix combined_matrix; - combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift); - - // and finally move our camera back - Transform apply_z_shift; - apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards - mono_transform *= apply_z_shift; - - // now prepare our scene with our adjusted transform projection matrix - _prepare_scene(mono_transform, combined_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); - } else if (p_eye == XRInterface::EYE_MONO) { - // For mono render, prepare as per usual - _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); - } - - // And render our scene... - _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); -}; - -void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, float p_screen_lod_threshold, bool p_using_shadows) { - // Note, in stereo rendering: - // - p_cam_transform will be a transform in the middle of our two eyes - // - p_cam_projection is a wider frustrum that encompasses both eyes + camera_data.set_camera(transform, projection, is_ortogonal, vaspect); + } else { + // Setup our camera for our XR interface. + // We can support multiple views here each with their own camera + Transform3D transforms[RendererSceneRender::MAX_RENDER_VIEWS]; + CameraMatrix projections[RendererSceneRender::MAX_RENDER_VIEWS]; - Instance *render_reflection_probe = instance_owner.getornull(p_reflection_probe); //if null, not rendering to it + uint32_t view_count = p_xr_interface->get_view_count(); + ERR_FAIL_COND_MSG(view_count > RendererSceneRender::MAX_RENDER_VIEWS, "Requested view count is not supported"); - Scenario *scenario = scenario_owner.getornull(p_scenario); + float aspect = p_viewport_size.width / (float)p_viewport_size.height; - render_pass++; + Transform3D world_origin = XRServer::get_singleton()->get_world_origin(); - scene_render->set_scene_pass(render_pass); + // We ignore our camera position, it will have been positioned with a slightly old tracking position. + // Instead we take our origin point and have our XR interface add fresh tracking data! Whoohoo! + for (uint32_t v = 0; v < view_count; v++) { + transforms[v] = p_xr_interface->get_transform_for_view(v, world_origin); + projections[v] = p_xr_interface->get_projection_for_view(v, aspect, camera->znear, camera->zfar); + } - if (p_render_buffers.is_valid()) { - scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not) + if (view_count == 1) { + camera_data.set_camera(transforms[0], projections[0], false, camera->vaspect); + } else if (view_count == 2) { + camera_data.set_multiview_camera(view_count, transforms, projections, false, camera->vaspect); + } else { + // this won't be called (see fail check above) but keeping this comment to indicate we may support more then 2 views in the future... + } } - RENDER_TIMESTAMP("Frustum Culling"); - - //rasterizer->set_camera(camera->transform, camera_matrix,ortho); - - Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); - - Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized()); - - 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(); + RID environment = _render_get_environment(p_camera, p_scenario); - /* STEP 2 - CULL */ + RENDER_TIMESTAMP("Update occlusion buffer") + // For now just cull on the first camera + RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera_data.main_transform, camera_data.main_projection, camera_data.is_ortogonal, RendererThreadPool::singleton->thread_work_pool); - cull.frustum = Frustum(planes); + _render_scene(&camera_data, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold, true, r_render_info); +#endif +} - Vector<RID> directional_lights; - // directional lights - { - //reset shadows - for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { - for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { - cull.shadows[i].cascades[j].cull_result.clear(); - } - } +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); - cull.shadow_count = 0; + _visibility_cull(*cull_data, cull_data->cull_offset + bin_from, cull_data->cull_offset + bin_to); +} - Vector<Instance *> lights_with_shadow; +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]; - for (List<Instance *>::Element *E = scenario->directional_lights.front(); E; E = E->next()) { - if (!E->get()->visible) { + 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; } - - if (directional_lights.size() > RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) { - break; - } - - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - - //check shadow.. - - if (light) { - if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->get()->base) && !(RSG::storage->light_get_type(E->get()->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->get()->base))) { - lights_with_shadow.push_back(E->get()); - } - //add to list - directional_lights.push_back(light->instance); - } } - scene_render->set_directional_shadow_count(lights_with_shadow.size()); + int range_check = _visibility_range_check(vd, cull_data.camera_position, cull_data.viewport_mask); - for (int i = 0; i < lights_with_shadow.size(); i++) { - _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect); + 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; } } +} - { //sdfgi - cull.sdfgi.region_count = 0; +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); - for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { - cull.sdfgi.region_cull_result[i].clear(); - } + 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; - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].clear(); - } + 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; + } +} - if (p_render_buffers.is_valid()) { - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].clear(); - } - cull.sdfgi.cascade_light_count = 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); - uint32_t prev_cascade = 0xFFFFFFFF; - uint32_t pending_region_count = scene_render->sdfgi_get_pending_region_count(p_render_buffers); + _scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to); +} - for (uint32_t i = 0; i < pending_region_count; i++) { - cull.sdfgi.region_aabb[i] = scene_render->sdfgi_get_pending_region_bounds(p_render_buffers, i); - uint32_t region_cascade = scene_render->sdfgi_get_pending_region_cascade(p_render_buffers, i); - cull.sdfgi.region_cascade[i] = region_cascade; +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(); - if (region_cascade != prev_cascade) { - cull.sdfgi.cascade_light_index[cull.sdfgi.cascade_light_count] = region_cascade; - cull.sdfgi.cascade_light_count++; - prev_cascade = region_cascade; - } - } + uint32_t sdfgi_last_light_index = 0xFFFFFFFF; + uint32_t sdfgi_last_light_cascade = 0xFFFFFFFF; - cull.sdfgi.region_count = pending_region_count; - } - } + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; - { - //pre-clear results - geometry_instances_to_render.clear(); - light_cull_result.clear(); - lightmap_cull_result.clear(); - reflection_probe_instance_cull_result.clear(); - light_instance_cull_result.clear(); - gi_probe_instance_cull_result.clear(); - lightmap_cull_result.clear(); - decal_instance_cull_result.clear(); - mesh_instance_cull_result.clear(); - } + Transform3D inv_cam_transform = cull_data.cam_transform.inverse(); + float z_near = cull_data.camera_matrix->get_z_near(); - { - uint64_t cull_count = scenario->instance_data.size(); - uint32_t sdfgi_last_light_index = 0xFFFFFFFF; - uint32_t sdfgi_last_light_cascade = 0xFFFFFFFF; + for (uint64_t i = p_from; i < p_to; i++) { + bool mesh_visible = false; - for (uint64_t i = 0; i < cull_count; i++) { - bool mesh_visible = false; + 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 (scenario->instance_aabbs[i].in_frustum(cull.frustum)) { - InstanceData &idata = scenario->instance_data[i]; - uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; +#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_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) == 0 && 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)) - if ((p_visible_layers & idata.layer_mask) == 0) { - //failure - } else if (base_type == RS::INSTANCE_LIGHT) { - light_cull_result.push_back(idata.instance); - light_instance_cull_result.push_back(idata.instance_data_rid); - if (p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) { - scene_render->light_instance_mark_visible(idata.instance_data_rid); //mark it visible for shadow allocation later + 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 } } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) { - if (render_reflection_probe != idata.instance) { + 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(idata.instance_data_rid)) { + 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.lock.lock(); + 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.lock.unlock(); + cull_data.cull->lock.unlock(); idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY); } - if (scene_render->reflection_probe_instance_has_reflection(idata.instance_data_rid)) { - reflection_probe_instance_cull_result.push_back(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_DECAL) { - decal_instance_cull_result.push_back(idata.instance_data_rid); + cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid)); - } else if (base_type == RS::INSTANCE_GI_PROBE) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(idata.instance->base_data); - cull.lock.lock(); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); + } 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.lock.unlock(); - gi_probe_instance_cull_result.push_back(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_LIGHTMAP) { - lightmap_cull_result.push_back(idata.instance); + cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (base_type == RS::INSTANCE_VISIBLITY_NOTIFIER) { + InstanceVisibilityNotifierData *vnd = idata.visibility_notifier; + if (!vnd->list_element.in_list()) { + visible_notifier_list_lock.lock(); + visible_notifier_list.add(&vnd->list_element); + visible_notifier_list_lock.unlock(); + vnd->just_visible = true; + } + vnd->visible_in_frame = RSG::rasterizer->get_frame_number(); } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { bool keep = true; @@ -2322,191 +2598,347 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca //but if nothing is going on, don't do it. keep = false; } else { - cull.lock.lock(); + cull_data.cull->lock.lock(); RSG::storage->particles_request_process(idata.base_rid); - cull.lock.unlock(); - RSG::storage->particles_set_view_axis(idata.base_rid, -p_cam_transform.basis.get_axis(2).normalized()); + 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 (pair_volumes_to_mesh && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { + 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); - int l = 0; - //only called when lights AABB enter/exit this geometry - idata.instance->light_instances.resize(geom->lights.size()); + 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); - - idata.instance->light_instances.write[l++] = light->instance; + 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 (pair_volumes_to_mesh && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) { + if (idata.flags & InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + + scene_render->geometry_instance_set_softshadow_projector_pairing(geom->geometry_instance, geom->softshadow_count > 0, geom->projector_count > 0); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_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); - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - idata.instance->reflection_probe_instances.resize(geom->reflection_probes.size()); + 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); - idata.instance->reflection_probe_instances.write[l++] = reflection_probe->instance; + 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 (pair_volumes_to_mesh && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { - //InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - //todo for GLES3 + 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_GI_PROBE_DIRTY) { + if (idata.flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY) { InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - idata.instance->gi_probe_instances.resize(geom->gi_probes.size()); + 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); - for (Set<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); - - idata.instance->gi_probe_instances.write[l++] = gi_probe->probe_instance; + instance_pair_buffer[idx++] = voxel_gi->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } } - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + 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) { - geometry_instances_to_render.push_back(idata.instance); + cull_result.geometry_instances.push_back(idata.instance_geometry); } } } - for (uint32_t j = 0; j < cull.shadow_count; j++) { - for (uint32_t k = 0; k < cull.shadows[j].cascade_count; k++) { - if (scenario->instance_aabbs[i].in_frustum(cull.shadows[j].cascades[k].frustum)) { - InstanceData &idata = scenario->instance_data[i]; + 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.shadows[j].cascades[k].cull_result.push_back(idata.instance); + cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); mesh_visible = true; } } } } + } - for (uint32_t j = 0; j < cull.sdfgi.region_count; j++) { - if (scenario->instance_aabbs[i].in_aabb(cull.sdfgi.region_aabb[j])) { - InstanceData &idata = scenario->instance_data[i]; - uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; +#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 - if (base_type == RS::INSTANCE_LIGHT) { - InstanceLightData *instance_light = (InstanceLightData *)idata.instance->base_data; - if (instance_light->bake_mode == RS::LIGHT_BAKE_STATIC && cull.sdfgi.region_cascade[j] <= instance_light->max_sdfgi_cascade) { - if (sdfgi_last_light_index != i || sdfgi_last_light_cascade != cull.sdfgi.region_cascade[j]) { - sdfgi_last_light_index = i; - sdfgi_last_light_cascade = cull.sdfgi.region_cascade[j]; - cull.sdfgi.cascade_lights[sdfgi_last_light_cascade].push_back(instance_light->instance); - } - } - } else if ((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) { - if (idata.flags & InstanceData::FLAG_USES_BAKED_LIGHT) { - cull.sdfgi.region_cull_result[j].push_back(idata.instance); - mesh_visible = true; + 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])) { + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + + if (base_type == RS::INSTANCE_LIGHT) { + InstanceLightData *instance_light = (InstanceLightData *)idata.instance->base_data; + if (instance_light->bake_mode == RS::LIGHT_BAKE_STATIC && cull_data.cull->sdfgi.region_cascade[j] <= instance_light->max_sdfgi_cascade) { + if (sdfgi_last_light_index != i || sdfgi_last_light_cascade != cull_data.cull->sdfgi.region_cascade[j]) { + sdfgi_last_light_index = i; + sdfgi_last_light_cascade = cull_data.cull->sdfgi.region_cascade[j]; + cull_result.sdfgi_cascade_lights[sdfgi_last_light_cascade].push_back(instance_light->instance); } } + } else if ((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) { + if (idata.flags & InstanceData::FLAG_USES_BAKED_LIGHT) { + cull_result.sdfgi_region_geometry_instances[j].push_back(idata.instance_geometry); + mesh_visible = true; + } } } - - if (mesh_visible && scenario->instance_data[i].flags & InstanceData::FLAG_USES_MESH_INSTANCE) { - mesh_instance_cull_result.push_back(scenario->instance_data[i].instance->mesh_instance); - } } - if (mesh_instance_cull_result.size()) { - for (uint64_t i = 0; i < mesh_instance_cull_result.size(); i++) { - RSG::storage->mesh_instance_check_for_update(mesh_instance_cull_result[i]); - } - RSG::storage->update_mesh_instances(); + if (mesh_visible && cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_USES_MESH_INSTANCE) { + cull_result.mesh_instances.push_back(cull_data.scenario->instance_data[i].instance->mesh_instance); } } +} - //render shadows +void RendererSceneCull::_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, RendererScene::RenderInfo *r_render_info) { + Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it + + Scenario *scenario = scenario_owner.get_or_null(p_scenario); + + render_pass++; + + scene_render->set_scene_pass(render_pass); + + if (p_render_buffers.is_valid()) { + //no rendering code here, this is only to set up what needs to be done, request regions, etc. + 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("Visibility Dependencies"); - for (uint32_t i = 0; i < cull.shadow_count; i++) { - for (uint32_t j = 0; j < cull.shadows[i].cascade_count; j++) { - const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j]; - // print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size())); - scene_render->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale); - scene_render->render_shadow(cull.shadows[i].light_instance, p_shadow_atlas, j, c.cull_result, near_plane, p_cam_projection.get_lod_multiplier(), p_screen_lod_threshold); + 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); + } + + VisibilityCullData visibility_cull_data; + 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 SDFGI + RENDER_TIMESTAMP("Culling"); + //rasterizer->set_camera(p_camera_data->main_transform, p_camera_data.main_projection, p_camera_data.is_ortogonal); + + /* STEP 2 - CULL */ + + Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform); + cull.frustum = Frustum(planes); + + Vector<RID> directional_lights; + // directional lights { - if (cull.sdfgi.region_count > 0) { - //update regions - for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) { - scene_render->render_sdfgi(p_render_buffers, i, cull.sdfgi.region_cull_result[i]); + cull.shadow_count = 0; + + Vector<Instance *> lights_with_shadow; + + for (Instance *E : scenario->directional_lights) { + if (!E->visible) { + continue; } - //check if static lights were culled - bool static_lights_culled = false; - for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) { - if (cull.sdfgi.cascade_lights[i].size()) { - static_lights_culled = true; - break; - } + + if (directional_lights.size() > RendererSceneRender::MAX_DIRECTIONAL_LIGHTS) { + break; } - if (static_lights_culled) { - scene_render->render_sdfgi_static_lights(p_render_buffers, cull.sdfgi.cascade_light_count, cull.sdfgi.cascade_light_index, cull.sdfgi.cascade_lights); + InstanceLightData *light = static_cast<InstanceLightData *>(E->base_data); + + //check shadow.. + + if (light) { + if (p_using_shadows && p_shadow_atlas.is_valid() && RSG::storage->light_has_shadow(E->base) && !(RSG::storage->light_get_type(E->base) == RS::LIGHT_DIRECTIONAL && RSG::storage->light_directional_is_sky_only(E->base))) { + lights_with_shadow.push_back(E); + } + //add to list + directional_lights.push_back(light->instance); } } + scene_render->set_directional_shadow_count(lights_with_shadow.size()); + + for (int i = 0; i < lights_with_shadow.size(); i++) { + _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect); + } + } + + { //sdfgi + cull.sdfgi.region_count = 0; + if (p_render_buffers.is_valid()) { - scene_render->sdfgi_update_probes(p_render_buffers, p_environment, directional_lights, scenario->dynamic_lights.ptr(), scenario->dynamic_lights.size()); + cull.sdfgi.cascade_light_count = 0; + + uint32_t prev_cascade = 0xFFFFFFFF; + uint32_t pending_region_count = scene_render->sdfgi_get_pending_region_count(p_render_buffers); + + for (uint32_t i = 0; i < pending_region_count; i++) { + cull.sdfgi.region_aabb[i] = scene_render->sdfgi_get_pending_region_bounds(p_render_buffers, i); + uint32_t region_cascade = scene_render->sdfgi_get_pending_region_cascade(p_render_buffers, i); + cull.sdfgi.region_cascade[i] = region_cascade; + + if (region_cascade != prev_cascade) { + cull.sdfgi.cascade_light_index[cull.sdfgi.cascade_light_count] = region_cascade; + cull.sdfgi.cascade_light_count++; + prev_cascade = region_cascade; + } + } + + cull.sdfgi.region_count = pending_region_count; } } - //light_samplers_culled=0; + scene_cull_result.clear(); + + { + uint64_t cull_from = 0; + uint64_t cull_to = scenario->instance_data.size(); + + CullData cull_data; + + //prepare for eventual thread usage + cull_data.cull = &cull; + cull_data.scenario = scenario; + cull_data.shadow_atlas = p_shadow_atlas; + cull_data.cam_transform = p_camera_data->main_transform; + cull_data.visible_layers = p_visible_layers; + cull_data.render_reflection_probe = render_reflection_probe; + cull_data.occlusion_buffer = RendererSceneOcclusionCull::get_singleton()->buffer_get_ptr(p_viewport); + cull_data.camera_matrix = &p_camera_data->main_projection; + cull_data.visibility_viewport_mask = scenario->viewport_visibility_masks.has(p_viewport) ? scenario->viewport_visibility_masks[p_viewport] : 0; +//#define DEBUG_CULL_TIME +#ifdef DEBUG_CULL_TIME + uint64_t time_from = OS::get_singleton()->get_ticks_usec(); +#endif + if (cull_to > thread_cull_threshold) { + //multiple threads + 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(scene_cull_result_threads.size(), this, &RendererSceneCull::_scene_cull_threaded, &cull_data); + + 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 + _scene_cull(cull_data, scene_cull_result, cull_from, cull_to); + } - /* - print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0)); - print_line("OTO: "+itos(p_scenario->octree.get_octant_count())); - print_line("OTE: "+itos(p_scenario->octree.get_elem_count())); - print_line("OTP: "+itos(p_scenario->octree.get_pair_count())); - */ +#ifdef DEBUG_CULL_TIME + static float time_avg = 0; + static uint32_t time_count = 0; + time_avg += double(OS::get_singleton()->get_ticks_usec() - time_from) / 1000.0; + time_count++; + print_line("time taken: " + rtos(time_avg / time_count)); +#endif - /* STEP 3 - PROCESS PORTALS, VALIDATE ROOMS */ - //removed, will replace with culling + 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(); + } + } - /* STEP 4 - REMOVE FURTHER CULLED OBJECTS, ADD LIGHTS */ + //render shadows - /* STEP 5 - PROCESS POSITIONAL LIGHTS */ + max_shadows_used = 0; if (p_using_shadows) { //setup shadow maps - //SortArray<Instance*,_InstanceLightsort> sorter; - //sorter.sort(light_cull_result,light_cull_count); - for (uint32_t i = 0; i < (uint32_t)light_cull_result.size(); i++) { - Instance *ins = light_cull_result[i]; + // Directional Shadows + + for (uint32_t i = 0; i < cull.shadow_count; i++) { + for (uint32_t j = 0; j < cull.shadows[i].cascade_count; j++) { + const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j]; + // print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size())); + scene_render->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale); + if (max_shadows_used == MAX_UPDATE_SHADOWS) { + continue; + } + 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(scene_cull_result.directional_shadows[i].cascade_geometry_instances[j]); + max_shadows_used++; + } + } + + // Positional Shadowss + 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; @@ -2518,12 +2950,12 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca { //compute coverage - Transform cam_xf = p_cam_transform; - float zn = p_cam_projection.get_z_near(); + Transform3D cam_xf = p_camera_data->main_transform; + float zn = p_camera_data->main_projection.get_z_near(); Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane // near plane half width and height - Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents(); + Vector2 vp_half_extents = p_camera_data->main_projection.get_viewport_half_extents(); switch (RSG::storage->light_get_type(ins->base)) { case RS::LIGHT_OMNI: { @@ -2535,7 +2967,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca ins->transform.origin + cam_xf.basis.get_axis(0) * radius }; - if (!p_cam_orthogonal) { + if (!p_camera_data->is_ortogonal) { //if using perspetive, map them to near plane for (int j = 0; j < 2; j++) { if (p.distance_to(points[j]) < 0) { @@ -2563,7 +2995,7 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca base + cam_xf.basis.get_axis(0) * w }; - if (!p_cam_orthogonal) { + if (!p_camera_data->is_ortogonal) { //if using perspetive, map them to near plane for (int j = 0; j < 2; j++) { if (p.distance_to(points[j]) < 0) { @@ -2591,28 +3023,92 @@ void RendererSceneCull::_prepare_scene(const Transform p_cam_transform, const Ca bool redraw = scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version); - if (redraw) { + if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) { //must redraw! RENDER_TIMESTAMP(">Rendering Light " + itos(i)); - light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold); + light->shadow_dirty = _light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold); RENDER_TIMESTAMP("<Rendering Light " + itos(i)); + } else { + light->shadow_dirty = redraw; } } } + //render SDFGI + + { + sdfgi_update_data.update_static = false; + + 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(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 (scene_cull_result.sdfgi_cascade_lights[i].size()) { + static_lights_culled = true; + break; + } + } + + 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 = scene_cull_result.sdfgi_cascade_lights; + sdfgi_update_data.update_static = true; + } + } + + if (p_render_buffers.is_valid()) { + sdfgi_update_data.directional_lights = &directional_lights; + sdfgi_update_data.positional_light_instances = scenario->dynamic_lights.ptr(); + sdfgi_update_data.positional_light_count = scenario->dynamic_lights.size(); + } + } + //append the directional lights to the lights culled for (int i = 0; i < directional_lights.size(); i++) { - light_instance_cull_result.push_back(directional_lights[i]); + scene_cull_result.light_instances.push_back(directional_lights[i]); + } + + RID camera_effects; + if (p_force_camera_effects.is_valid()) { + camera_effects = p_force_camera_effects; + } else { + camera_effects = scenario->camera_effects; + } + /* PROCESS GEOMETRY AND DRAW SCENE */ + + RID occluders_tex; + if (p_viewport.is_valid()) { + occluders_tex = RSG::viewport->viewport_get_occluder_debug_texture(p_viewport); + } + + RENDER_TIMESTAMP("Render Scene "); + 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, r_render_info); + + for (uint32_t i = 0; i < max_shadows_used; i++) { + render_shadow_data[i].instances.clear(); + } + max_shadows_used = 0; + + for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) { + render_sdfgi_data[i].instances.clear(); } + + // virtual void render_scene(RID p_render_buffers, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0; } RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); if (camera && scene_render->is_environment(camera->env)) { return camera->env; } - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); if (!scenario) { return RID(); } @@ -2627,25 +3123,9 @@ RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { return RID(); } -void RendererSceneCull::_render_scene(RID p_render_buffers, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_environment, RID p_force_camera_effects, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - - RID camera_effects; - if (p_force_camera_effects.is_valid()) { - camera_effects = p_force_camera_effects; - } else { - camera_effects = scenario->camera_effects; - } - /* PROCESS GEOMETRY AND DRAW SCENE */ - - RENDER_TIMESTAMP("Render Scene "); - scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, geometry_instances_to_render, light_instance_cull_result, reflection_probe_instance_cull_result, gi_probe_instance_cull_result, decal_instance_cull_result, lightmap_cull_result, p_environment, camera_effects, p_shadow_atlas, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold); -} - void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { #ifndef _3D_DISABLED - - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); RID environment; if (scenario->environment.is_valid()) { @@ -2654,7 +3134,11 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, environment = scenario->fallback_environment; } RENDER_TIMESTAMP("Render Empty Scene "); - scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::InstanceBase *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RendererSceneRender::InstanceBase *>(), RID(), RID(), p_shadow_atlas, scenario->reflection_atlas, RID(), 0, 0); + + RendererSceneRender::CameraData camera_data; + camera_data.set_camera(Transform3D(), CameraMatrix(), true, false); + + scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); #endif } @@ -2704,10 +3188,10 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int CameraMatrix cm; cm.set_perspective(90, 1, 0.01, max_distance); - Transform local_view; + Transform3D local_view; local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); - Transform xform = p_instance->transform * local_view; + Transform3D xform = p_instance->transform * local_view; RID shadow_atlas; @@ -2716,9 +3200,18 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int shadow_atlas = scenario->reflection_probe_shadow_atlas; } + RID environment; + if (scenario->environment.is_valid()) { + environment = scenario->environment; + } else { + environment = scenario->fallback_environment; + } + RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); - _prepare_scene(xform, cm, false, false, RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, lod_threshold, use_shadows); - _render_scene(RID(), xform, cm, false, RID(), RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold); + RendererSceneRender::CameraData camera_data; + camera_data.set_camera(xform, cm, false, false); + + _render_scene(&camera_data, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows); } else { //do roughness postprocess step until it believes it's done @@ -2770,18 +3263,18 @@ void RendererSceneCull::render_probes() { ref_probe = next; } - /* GI PROBES */ + /* VOXEL GIS */ - SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first(); + SelfList<InstanceVoxelGIData> *voxel_gi = voxel_gi_update_list.first(); - if (gi_probe) { + if (voxel_gi) { RENDER_TIMESTAMP("Render GI Probes"); } - while (gi_probe) { - SelfList<InstanceGIProbeData> *next = gi_probe->next(); + while (voxel_gi) { + SelfList<InstanceVoxelGIData> *next = voxel_gi->next(); - InstanceGIProbeData *probe = gi_probe->self(); + InstanceVoxelGIData *probe = voxel_gi->self(); //Instance *instance_probe = probe->owner; //check if probe must be setup, but don't do if on the lighting thread @@ -2790,7 +3283,7 @@ void RendererSceneCull::render_probes() { int cache_count = 0; { int light_cache_size = probe->light_cache.size(); - const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr(); + const InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptr(); const RID *instance_caches = probe->light_instances.ptr(); int idx = 0; //must count visible lights @@ -2805,7 +3298,7 @@ void RendererSceneCull::render_probes() { } else if (idx >= light_cache_size) { cache_dirty = true; } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; + const InstanceVoxelGIData::LightCache *cache = &caches[idx]; if ( instance_caches[idx] != instance_light->instance || @@ -2826,8 +3319,7 @@ void RendererSceneCull::render_probes() { idx++; } - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); + for (const Instance *instance : probe->owner->scenario->directional_lights) { InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; if (!instance->visible) { continue; @@ -2837,7 +3329,7 @@ void RendererSceneCull::render_probes() { } else if (idx >= light_cache_size) { cache_dirty = true; } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; + const InstanceVoxelGIData::LightCache *cache = &caches[idx]; if ( instance_caches[idx] != instance_light->instance || @@ -2866,14 +3358,14 @@ void RendererSceneCull::render_probes() { cache_count = idx; } - bool update_lights = scene_render->gi_probe_needs_update(probe->probe_instance); + bool update_lights = scene_render->voxel_gi_needs_update(probe->probe_instance); if (cache_dirty) { probe->light_cache.resize(cache_count); probe->light_instances.resize(cache_count); if (cache_count) { - InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw(); + InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptrw(); RID *instance_caches = probe->light_instances.ptrw(); int idx = 0; //must count visible lights @@ -2884,7 +3376,7 @@ void RendererSceneCull::render_probes() { continue; } - InstanceGIProbeData::LightCache *cache = &caches[idx]; + InstanceVoxelGIData::LightCache *cache = &caches[idx]; instance_caches[idx] = instance_light->instance; cache->has_shadow = RSG::storage->light_has_shadow(instance->base); @@ -2900,14 +3392,13 @@ void RendererSceneCull::render_probes() { idx++; } - for (List<Instance *>::Element *E = probe->owner->scenario->directional_lights.front(); E; E = E->next()) { - Instance *instance = E->get(); + for (const Instance *instance : probe->owner->scenario->directional_lights) { InstanceLightData *instance_light = (InstanceLightData *)instance->base_data; if (!instance->visible) { continue; } - InstanceGIProbeData::LightCache *cache = &caches[idx]; + InstanceVoxelGIData::LightCache *cache = &caches[idx]; instance_caches[idx] = instance_light->instance; cache->has_shadow = RSG::storage->light_has_shadow(instance->base); @@ -2929,7 +3420,9 @@ void RendererSceneCull::render_probes() { update_lights = true; } - geometry_instances_to_render.clear(); + scene_cull_result.geometry_instances.clear(); + + RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; for (Set<Instance *>::Element *E = probe->dynamic_geometries.front(); E; E = E->next()) { Instance *ins = E->get(); @@ -2938,29 +3431,30 @@ void RendererSceneCull::render_probes() { } InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; - if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY)) { - //giprobes may be dirty, so update - int l = 0; - //only called when reflection probe AABB enter/exit this geometry - ins->gi_probe_instances.resize(geom->gi_probes.size()); - - for (Set<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { - InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); + if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY)) { + uint32_t idx = 0; + for (Set<Instance *>::Element *F = geom->voxel_gi_instances.front(); F; F = F->next()) { + InstanceVoxelGIData *voxel_gi2 = static_cast<InstanceVoxelGIData *>(F->get()->base_data); - ins->gi_probe_instances.write[l++] = gi_probe2->probe_instance; + instance_pair_buffer[idx++] = voxel_gi2->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } } - ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx); + + ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY); } - geometry_instances_to_render.push_back(E->get()); + scene_cull_result.geometry_instances.push_back(geom->geometry_instance); } - scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, geometry_instances_to_render); + scene_render->voxel_gi_update(probe->probe_instance, update_lights, probe->light_instances, scene_cull_result.geometry_instances); - gi_probe_update_list.remove(gi_probe); + voxel_gi_update_list.remove(voxel_gi); - gi_probe = next; + voxel_gi = next; } } @@ -2971,7 +3465,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(); - geometry_instances_to_render.clear(); + scene_cull_result.geometry_instances.clear(); struct CullAABB { PagedArray<Instance *> *result; @@ -2992,38 +3486,39 @@ void RendererSceneCull::render_particle_colliders() { if (!instance || !((1 << instance->base_type) & (RS::INSTANCE_GEOMETRY_MASK & (~(1 << RS::INSTANCE_PARTICLES))))) { //all but particles to avoid self collision continue; } - geometry_instances_to_render.push_back(instance); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_cull_result.geometry_instances.push_back(geom->geometry_instance); } - scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, geometry_instances_to_render); + 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()); } } -void RendererSceneCull::_update_instance_shader_parameters_from_material(Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter> &isparams, const Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter> &existing_isparams, RID p_material) { +void RendererSceneCull::_update_instance_shader_parameters_from_material(Map<StringName, Instance::InstanceShaderParameter> &isparams, const Map<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) { List<RendererStorage::InstanceShaderParam> plist; RSG::storage->material_get_instance_shader_parameters(p_material, &plist); - for (List<RendererStorage::InstanceShaderParam>::Element *E = plist.front(); E; E = E->next()) { - StringName name = E->get().info.name; + for (const RendererStorage::InstanceShaderParam &E : plist) { + StringName name = E.info.name; if (isparams.has(name)) { - if (isparams[name].info.type != E->get().info.type) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); + if (isparams[name].info.type != E.info.type) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different data types. Only the first one (in order) will display correctly."); } - if (isparams[name].index != E->get().index) { - WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E->get().info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); + if (isparams[name].index != E.index) { + WARN_PRINT("More than one material in instance export the same instance shader uniform '" + E.info.name + "', but they do it with different indices. Only the first one (in order) will display correctly."); } continue; //first one found always has priority } - RendererSceneRender::InstanceBase::InstanceShaderParameter isp; - isp.index = E->get().index; - isp.info = E->get().info; - isp.default_value = E->get().default_value; + Instance::InstanceShaderParameter isp; + isp.index = E.index; + isp.info = E.info; + isp.default_value = E.default_value; if (existing_isparams.has(name)) { isp.value = existing_isparams[name].value; } else { - isp.value = E->get().default_value; + isp.value = E.default_value; } isparams[name] = isp; } @@ -3035,14 +3530,14 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { } if (p_instance->update_dependencies) { - p_instance->instance_increase_version(); + p_instance->dependency_tracker.update_begin(); if (p_instance->base.is_valid()) { - RSG::storage->base_update_dependency(p_instance->base, p_instance); + RSG::storage->base_update_dependency(p_instance->base, &p_instance->dependency_tracker); } if (p_instance->material_override.is_valid()) { - RSG::storage->material_update_dependency(p_instance->material_override, p_instance); + RSG::storage->material_update_dependency(p_instance->material_override, &p_instance->dependency_tracker); } if (p_instance->base_type == RS::INSTANCE_MESH) { @@ -3059,7 +3554,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { bool can_cast_shadows = true; bool is_animated = false; - Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter> isparams; + Map<StringName, Instance::InstanceShaderParameter> isparams; if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_OFF) { can_cast_shadows = false; @@ -3094,7 +3589,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); } } @@ -3125,7 +3620,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); } } @@ -3133,27 +3628,8 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { can_cast_shadows = false; } - RSG::storage->base_update_dependency(mesh, p_instance); - } - } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) { - RID mat = RSG::storage->immediate_get_material(p_instance->base); - - if (!(!mat.is_valid() || RSG::storage->material_casts_shadows(mat))) { - can_cast_shadows = false; - } - - if (mat.is_valid() && RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - if (mat.is_valid()) { - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - } - - if (mat.is_valid()) { - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->base_update_dependency(mesh, &p_instance->dependency_tracker); } - } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { bool cast_shadows = false; @@ -3182,7 +3658,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - RSG::storage->material_update_dependency(mat, p_instance); + RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); } } } @@ -3210,23 +3686,31 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { p_instance->instance_allocated_shader_parameters = (p_instance->instance_shader_parameters.size() > 0); if (p_instance->instance_allocated_shader_parameters) { p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self); - for (Map<StringName, RendererSceneRender::InstanceBase::InstanceShaderParameter>::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { - if (E->get().value.get_type() != Variant::NIL) { - RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value); + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, p_instance->instance_allocated_shader_parameters_offset); + + for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : p_instance->instance_shader_parameters) { + if (E.value.value.get_type() != Variant::NIL) { + RSG::storage->global_variables_instance_update(p_instance->self, E.value.index, E.value.value); } } } else { RSG::storage->global_variables_instance_free(p_instance->self); p_instance->instance_allocated_shader_parameters_offset = -1; + scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, -1); } } } if (p_instance->skeleton.is_valid()) { - RSG::storage->skeleton_update_dependency(p_instance->skeleton, p_instance); + RSG::storage->skeleton_update_dependency(p_instance->skeleton, &p_instance->dependency_tracker); } - p_instance->clean_up_dependencies(); + p_instance->dependency_tracker.update_end(); + + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + scene_render->geometry_instance_set_surface_materials(geom->geometry_instance, p_instance->materials); + } } _instance_update_list.remove(&p_instance->update_item); @@ -3263,31 +3747,31 @@ bool RendererSceneCull::free(RID p_rid) { } if (camera_owner.owns(p_rid)) { - Camera *camera = camera_owner.getornull(p_rid); - camera_owner.free(p_rid); - memdelete(camera); } else if (scenario_owner.owns(p_rid)) { - Scenario *scenario = scenario_owner.getornull(p_rid); + Scenario *scenario = scenario_owner.get_or_null(p_rid); while (scenario->instances.first()) { instance_set_scenario(scenario->instances.first()->self()->self, 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); scenario_owner.free(p_rid); - memdelete(scenario); + RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid); + } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) { + RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid); } else if (instance_owner.owns(p_rid)) { // delete the instance update_dirty_instances(); - Instance *instance = instance_owner.getornull(p_rid); + Instance *instance = instance_owner.get_or_null(p_rid); instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0); instance_set_scenario(p_rid, RID()); @@ -3302,7 +3786,6 @@ bool RendererSceneCull::free(RID p_rid) { update_dirty_instances(); //in case something changed this instance_owner.free(p_rid); - memdelete(instance); } else { return false; } @@ -3314,6 +3797,28 @@ TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RI return scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size); } +void RendererSceneCull::update_visibility_notifiers() { + SelfList<InstanceVisibilityNotifierData> *E = visible_notifier_list.first(); + while (E) { + SelfList<InstanceVisibilityNotifierData> *N = E->next(); + + InstanceVisibilityNotifierData *visibility_notifier = E->self(); + if (visibility_notifier->just_visible) { + visibility_notifier->just_visible = false; + + RSG::storage->visibility_notifier_call(visibility_notifier->base, true, RSG::threaded); + } else { + if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) { + visible_notifier_list.remove(E); + + RSG::storage->visibility_notifier_call(visibility_notifier->base, false, RSG::threaded); + } + } + + E = N; + } +} + /*******************************/ /* Passthrough to Scene Render */ /*******************************/ @@ -3322,70 +3827,56 @@ TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RI RendererSceneCull *RendererSceneCull::singleton = nullptr; +void RendererSceneCull::set_scene_render(RendererSceneRender *p_scene_render) { + scene_render = p_scene_render; + geometry_instance_pair_mask = scene_render->geometry_instance_get_pair_mask(); +} + RendererSceneCull::RendererSceneCull() { render_pass = 1; singleton = this; - pair_volumes_to_mesh = false; instance_cull_result.set_page_pool(&instance_cull_page_pool); - mesh_instance_cull_result.set_page_pool(&rid_cull_page_pool); instance_shadow_cull_result.set_page_pool(&instance_cull_page_pool); - instance_sdfgi_cull_result.set_page_pool(&instance_cull_page_pool); - light_cull_result.set_page_pool(&instance_cull_page_pool); - geometry_instances_to_render.set_page_pool(&base_instance_cull_page_pool); - geometry_instances_to_shadow_render.set_page_pool(&base_instance_cull_page_pool); - lightmap_cull_result.set_page_pool(&base_instance_cull_page_pool); - - reflection_probe_instance_cull_result.set_page_pool(&rid_cull_page_pool); - light_instance_cull_result.set_page_pool(&rid_cull_page_pool); - gi_probe_instance_cull_result.set_page_pool(&rid_cull_page_pool); - decal_instance_cull_result.set_page_pool(&rid_cull_page_pool); - - for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { - for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { - cull.shadows[i].cascades[j].cull_result.set_page_pool(&base_instance_cull_page_pool); - } + for (uint32_t i = 0; i < MAX_UPDATE_SHADOWS; i++) { + render_shadow_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool); } - - for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { - cull.sdfgi.region_cull_result[i].set_page_pool(&base_instance_cull_page_pool); + for (uint32_t i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + render_sdfgi_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool); } - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].set_page_pool(&rid_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/spatial_indexer/update_iterations_per_frame"); + indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); + thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances"); + thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)RendererThreadPool::singleton->thread_work_pool.get_thread_count()); //make sure there is at least one thread per CPU + + dummy_occlusion_culling = memnew(RendererSceneOcclusionCull); } RendererSceneCull::~RendererSceneCull() { instance_cull_result.reset(); - mesh_instance_cull_result.reset(); instance_shadow_cull_result.reset(); - instance_sdfgi_cull_result.reset(); - light_cull_result.reset(); - geometry_instances_to_render.reset(); - geometry_instances_to_shadow_render.reset(); - lightmap_cull_result.reset(); - - reflection_probe_instance_cull_result.reset(); - light_instance_cull_result.reset(); - gi_probe_instance_cull_result.reset(); - decal_instance_cull_result.reset(); - - for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { - for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { - cull.shadows[i].cascades[j].cull_result.reset(); - } + for (uint32_t i = 0; i < MAX_UPDATE_SHADOWS; i++) { + render_shadow_data[i].instances.reset(); + } + for (uint32_t i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { + render_sdfgi_data[i].instances.reset(); } - for (int i = 0; i < SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE; i++) { - cull.sdfgi.region_cull_result[i].reset(); + scene_cull_result.reset(); + for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { + scene_cull_result_threads[i].reset(); } + scene_cull_result_threads.clear(); - for (int i = 0; i < SDFGI_MAX_CASCADES; i++) { - cull.sdfgi.cascade_lights[i].reset(); + if (dummy_occlusion_culling) { + memdelete(dummy_occlusion_culling); } } |