diff options
Diffstat (limited to 'servers/rendering/renderer_scene_cull.h')
-rw-r--r-- | servers/rendering/renderer_scene_cull.h | 226 |
1 files changed, 200 insertions, 26 deletions
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 8bf262d7c0..b755efd877 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -52,7 +52,8 @@ public: RendererSceneRender *scene_render; enum { - SDFGI_MAX_CASCADES = 8 + SDFGI_MAX_CASCADES = 8, + SDFGI_MAX_REGIONS_PER_CASCADE = 3 }; uint64_t render_pass; @@ -108,6 +109,153 @@ public: struct Instance; + struct PlaneSign { + _ALWAYS_INLINE_ PlaneSign() {} + _ALWAYS_INLINE_ PlaneSign(const Plane &p_plane) { + if (p_plane.normal.x > 0) { + signs[0] = 0; + } else { + signs[0] = 3; + } + if (p_plane.normal.y > 0) { + signs[1] = 1; + } else { + signs[1] = 4; + } + if (p_plane.normal.z > 0) { + signs[2] = 2; + } else { + signs[2] = 5; + } + } + + uint32_t signs[3]; + }; + + struct Frustum { + Vector<Plane> planes; + Vector<PlaneSign> plane_signs; + const Plane *planes_ptr; + const PlaneSign *plane_signs_ptr; + uint32_t plane_count; + + _ALWAYS_INLINE_ Frustum() {} + _ALWAYS_INLINE_ Frustum(const Frustum &p_frustum) { + planes = p_frustum.planes; + plane_signs = p_frustum.plane_signs; + + planes_ptr = planes.ptr(); + plane_signs_ptr = plane_signs.ptr(); + plane_count = p_frustum.plane_count; + } + _ALWAYS_INLINE_ void operator=(const Frustum &p_frustum) { + planes = p_frustum.planes; + plane_signs = p_frustum.plane_signs; + + planes_ptr = planes.ptr(); + plane_signs_ptr = plane_signs.ptr(); + plane_count = p_frustum.plane_count; + } + _ALWAYS_INLINE_ Frustum(const Vector<Plane> &p_planes) { + planes = p_planes; + planes_ptr = planes.ptrw(); + plane_count = planes.size(); + for (int i = 0; i < planes.size(); i++) { + PlaneSign ps(p_planes[i]); + plane_signs.push_back(ps); + } + + plane_signs_ptr = plane_signs.ptr(); + } + }; + + struct InstanceBounds { + // Efficiently store instance bounds. + // Because bounds checking is performed first, + // keep it separated from data. + + real_t bounds[6]; + _ALWAYS_INLINE_ InstanceBounds() {} + + _ALWAYS_INLINE_ InstanceBounds(const AABB &p_aabb) { + bounds[0] = p_aabb.position.x; + bounds[1] = p_aabb.position.y; + bounds[2] = p_aabb.position.z; + bounds[3] = p_aabb.position.x + p_aabb.size.x; + bounds[4] = p_aabb.position.y + p_aabb.size.y; + bounds[5] = p_aabb.position.z + p_aabb.size.z; + } + _ALWAYS_INLINE_ bool in_frustum(const Frustum &p_frustum) const { + // This is not a full SAT check and the possibility of false positives exist, + // but the tradeoff vs performance is still very good. + + for (uint32_t i = 0; i < p_frustum.plane_count; i++) { + Vector3 min( + bounds[p_frustum.plane_signs_ptr[i].signs[0]], + bounds[p_frustum.plane_signs_ptr[i].signs[1]], + bounds[p_frustum.plane_signs_ptr[i].signs[2]]); + + if (p_frustum.planes_ptr[i].distance_to(min) >= 0.0) { + return false; + } + } + + return true; + } + _ALWAYS_INLINE_ bool in_aabb(const AABB &p_aabb) const { + Vector3 end = p_aabb.position + p_aabb.size; + + if (bounds[0] >= end.x) { + return false; + } + if (bounds[3] <= p_aabb.position.x) { + return false; + } + if (bounds[1] >= end.y) { + return false; + } + if (bounds[4] <= p_aabb.position.y) { + return false; + } + if (bounds[2] >= end.z) { + return false; + } + if (bounds[5] <= p_aabb.position.z) { + return false; + } + + return true; + } + }; + + struct InstanceData { + // Store instance pointer as well as common instance processing information, + // to make processing more cache friendly. + enum Flags { + FLAG_BASE_TYPE_MASK = 0xFF, + FLAG_CAST_SHADOWS = (1 << 8), + FLAG_CAST_SHADOWS_ONLY = (1 << 9), + FLAG_REDRAW_IF_VISIBLE = (1 << 10), + FLAG_GEOM_LIGHTING_DIRTY = (1 << 11), + FLAG_GEOM_REFLECTION_DIRTY = (1 << 12), + FLAG_GEOM_DECAL_DIRTY = (1 << 13), + FLAG_GEOM_GI_PROBE_DIRTY = (1 << 14), + FLAG_LIGHTMAP_CAPTURE = (1 << 15), + FLAG_USES_BAKED_LIGHT = (1 << 16), + FLAG_USES_MESH_INSTANCE = (1 << 17), + FLAG_REFLECTION_PROBE_DIRTY = (1 << 18), + }; + + uint32_t flags = 0; + uint32_t layer_mask = 0; //for fast layer-mask discard + RID base_rid; + RID instance_data_rid; + Instance *instance = nullptr; + }; + + PagedArrayPool<InstanceBounds> instance_aabb_page_pool; + PagedArrayPool<InstanceData> instance_data_page_pool; + struct Scenario { enum IndexerType { INDEXER_GEOMETRY, //for geometry @@ -131,6 +279,9 @@ public: LocalVector<RID> dynamic_lights; + PagedArray<InstanceBounds> instance_aabbs; + PagedArray<InstanceData> instance_data; + Scenario() { indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY); indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES); @@ -178,6 +329,7 @@ public: RID self; //scenario stuff DynamicBVH::ID indexer_id; + int32_t array_index; Scenario *scenario; SelfList<Instance> scenario_item; @@ -199,7 +351,6 @@ public: Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior - uint64_t last_render_pass; uint64_t last_frame_pass; uint64_t version; // changes to this, and changes to base increase version @@ -240,7 +391,6 @@ public: lod_begin_hysteresis = 0; lod_end_hysteresis = 0; - last_render_pass = 0; last_frame_pass = 0; version = 1; base_data = nullptr; @@ -248,6 +398,7 @@ public: custom_aabb = nullptr; pair_check = 0; + array_index = -1; } ~Instance() { @@ -265,28 +416,17 @@ public: struct InstanceGeometryData : public InstanceBaseData { Set<Instance *> lights; - bool lighting_dirty; bool can_cast_shadows; bool material_is_animated; Set<Instance *> decals; - bool decal_dirty; - Set<Instance *> reflection_probes; - bool reflection_dirty; - Set<Instance *> gi_probes; - bool gi_probes_dirty; - Set<Instance *> lightmap_captures; InstanceGeometryData() { - lighting_dirty = false; - reflection_dirty = true; can_cast_shadows = true; material_is_animated = true; - gi_probes_dirty = true; - decal_dirty = true; } }; @@ -296,14 +436,12 @@ public: Set<Instance *> geometries; RID instance; - bool reflection_dirty; SelfList<InstanceReflectionProbeData> update_list; int render_step; InstanceReflectionProbeData() : update_list(this) { - reflection_dirty = true; render_step = -1; } }; @@ -334,8 +472,6 @@ public: RS::LightBakeMode bake_mode; uint32_t max_sdfgi_cascade = 2; - uint64_t sdfgi_cascade_light_pass = 0; - InstanceLightData() { bake_mode = RS::LIGHT_BAKE_DISABLED; shadow_dirty = true; @@ -468,25 +604,19 @@ public: PagedArrayPool<RID> rid_cull_page_pool; PagedArray<Instance *> instance_cull_result; + PagedArray<RID> mesh_instance_cull_result; PagedArray<RendererSceneRender::InstanceBase *> geometry_instances_to_render; PagedArray<Instance *> instance_shadow_cull_result; PagedArray<RendererSceneRender::InstanceBase *> geometry_instances_to_shadow_render; PagedArray<Instance *> instance_sdfgi_cull_result; - PagedArray<RendererSceneRender::InstanceBase *> geometry_instances_to_sdfgi_render; PagedArray<Instance *> light_cull_result; PagedArray<RendererSceneRender::InstanceBase *> lightmap_cull_result; - PagedArray<Instance *> directional_shadow_cull_result; PagedArray<RID> reflection_probe_instance_cull_result; PagedArray<RID> light_instance_cull_result; - PagedArray<RID> directional_light_cull_result; + PagedArray<RID> gi_probe_instance_cull_result; PagedArray<RID> decal_instance_cull_result; - PagedArray<RID> sdfgi_cascade_lights[SDFGI_MAX_CASCADES]; - - uint64_t sdfgi_light_cull_pass = 0; - int directional_light_count; - RID_PtrOwner<Instance> instance_owner; bool pair_volumes_to_mesh; // used in traditional forward, unnecesary on clustered @@ -536,10 +666,54 @@ public: _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); void _unpair_instance(Instance *p_instance); + void _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); + _FORCE_INLINE_ bool _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_scren_lod_threshold); RID _render_get_environment(RID p_camera, RID p_scenario); + struct Cull { + struct Shadow { + RID light_instance; + struct Cascade { + Frustum frustum; + + CameraMatrix projection; + Transform transform; + real_t zfar; + real_t split; + real_t shadow_texel_size; + real_t bias_scale; + real_t range_begin; + Vector2 uv_scale; + + PagedArray<RendererSceneRender::InstanceBase *> cull_result; + + } cascades[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; //max 4 cascades + uint32_t cascade_count; + + } shadows[RendererSceneRender::MAX_DIRECTIONAL_LIGHTS]; + + uint32_t shadow_count; + + struct SDFGI { + //have arrays here because SDFGI functions expects this, plus regions can have areas + PagedArray<RendererSceneRender::InstanceBase *> region_cull_result[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; + AABB region_aabb[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade + uint32_t region_cascade[SDFGI_MAX_CASCADES * SDFGI_MAX_REGIONS_PER_CASCADE]; //max 3 regions per cascade + uint32_t region_count = 0; + + PagedArray<RID> cascade_lights[SDFGI_MAX_CASCADES]; + uint32_t cascade_light_index[SDFGI_MAX_CASCADES]; + uint32_t cascade_light_count = 0; + + } sdfgi; + + SpinLock lock; + + Frustum frustum; + } cull; + bool _render_reflection_probe_step(Instance *p_instance, int p_step); void _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 = true); void _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); |