diff options
Diffstat (limited to 'servers/rendering/rendering_light_culler.h')
-rw-r--r-- | servers/rendering/rendering_light_culler.h | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h new file mode 100644 index 0000000000..602543850a --- /dev/null +++ b/servers/rendering/rendering_light_culler.h @@ -0,0 +1,248 @@ +/**************************************************************************/ +/* rendering_light_culler.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef RENDERING_LIGHT_CULLER_H +#define RENDERING_LIGHT_CULLER_H + +#include "core/math/plane.h" +#include "core/math/vector3.h" +#include "renderer_scene_cull.h" + +struct Projection; +struct Transform3D; + +// For testing performance improvements from the LightCuller: +// Uncomment LIGHT_CULLER_DEBUG_FLASH and it will turn the culler +// on and off every LIGHT_CULLER_DEBUG_FLASH_FREQUENCY camera prepares. +// Uncomment LIGHT_CULLER_DEBUG_LOGGING to get periodic print of the number of casters culled before / after. +// Uncomment LIGHT_CULLER_DEBUG_DIRECTIONAL_LIGHT to get periodic print of the number of casters culled for the directional light.. + +// #define LIGHT_CULLER_DEBUG_LOGGING +// #define LIGHT_CULLER_DEBUG_DIRECTIONAL_LIGHT +// #define LIGHT_CULLER_DEBUG_REGULAR_LIGHT +// #define LIGHT_CULLER_DEBUG_FLASH +#define LIGHT_CULLER_DEBUG_FLASH_FREQUENCY 1024 +//////////////////////////////////////////////////////////////////////////////////////////////// + +// The code to generate the lookup table is included but commented out. +// This may be useful for debugging / regenerating the LUT in the future, +// especially if the order of planes changes. +// When this define is set, the generated lookup table will be printed to debug output. +// The generated lookup table can be copy pasted +// straight to LUT_entry_sizes and LUT_entries. +// See the referenced article for explanation. +// #define RENDERING_LIGHT_CULLER_CALCULATE_LUT + +//////////////////////////////////////////////////////////////////////////////////////////////// +// This define will be set automatically depending on earlier defines, you can leave this as is. +#if defined(LIGHT_CULLER_DEBUG_LOGGING) || defined(RENDERING_LIGHT_CULLER_CALCULATE_LUT) +#define RENDERING_LIGHT_CULLER_DEBUG_STRINGS +#endif + +// Culls shadow casters that can't cast shadows into the camera frustum. +class RenderingLightCuller { +public: + RenderingLightCuller(); + +private: + class LightSource { + public: + enum SourceType { + ST_UNKNOWN, + ST_DIRECTIONAL, + ST_SPOTLIGHT, + ST_OMNI, + }; + + LightSource() { + type = ST_UNKNOWN; + angle = 0.0f; + range = FLT_MAX; + } + + // All in world space, culling done in world space. + Vector3 pos; + Vector3 dir; + SourceType type; + + float angle; // For spotlight. + float range; + }; + + // Same order as godot. + enum PlaneOrder { + PLANE_NEAR, + PLANE_FAR, + PLANE_LEFT, + PLANE_TOP, + PLANE_RIGHT, + PLANE_BOTTOM, + PLANE_TOTAL, + }; + + // Same order as godot. + enum PointOrder { + PT_FAR_LEFT_TOP, + PT_FAR_LEFT_BOTTOM, + PT_FAR_RIGHT_TOP, + PT_FAR_RIGHT_BOTTOM, + PT_NEAR_LEFT_TOP, + PT_NEAR_LEFT_BOTTOM, + PT_NEAR_RIGHT_TOP, + PT_NEAR_RIGHT_BOTTOM, + }; + + // 6 bits, 6 planes. + enum { + NUM_CAM_PLANES = 6, + NUM_CAM_POINTS = 8, + MAX_CULL_PLANES = 17, + LUT_SIZE = 64, + }; + +public: + // Before each pass with a different camera, you must call this so the culler can pre-create + // the camera frustum planes and corner points in world space which are used for the culling. + bool prepare_camera(const Transform3D &p_cam_transform, const Projection &p_cam_matrix); + + // REGULAR LIGHTS (SPOT, OMNI). + // These are prepared then used for culling one by one, single threaded. + // prepare_regular_light() returns false if the entire light is culled (i.e. there is no intersection between the light and the view frustum). + bool prepare_regular_light(const RendererSceneCull::Instance &p_instance) { return _prepare_light(p_instance, -1); } + + // Cull according to the regular light planes that were setup in the previous call to prepare_regular_light. + void cull_regular_light(PagedArray<RendererSceneCull::Instance *> &r_instance_shadow_cull_result); + + // Directional lights are prepared in advance, and can be culled multithreaded chopping and changing between + // different directional_light_id. + void prepare_directional_light(const RendererSceneCull::Instance *p_instance, int32_t p_directional_light_id); + + // Return false if the instance is to be culled. + bool cull_directional_light(const RendererSceneCull::InstanceBounds &p_bound, int32_t p_directional_light_id); + + // Can turn on and off from the engine if desired. + void set_caster_culling_active(bool p_active) { data.caster_culling_active = p_active; } + void set_light_culling_active(bool p_active) { data.light_culling_active = p_active; } + +private: + struct LightCullPlanes { + void add_cull_plane(const Plane &p); + Plane cull_planes[MAX_CULL_PLANES]; + int num_cull_planes = 0; +#ifdef LIGHT_CULLER_DEBUG_DIRECTIONAL_LIGHT + uint32_t rejected_count = 0; +#endif + }; + + bool _prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id = -1); + + // Internal version uses LightSource. + bool _add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source); + + // Directional light gives parallel culling planes (as opposed to point lights). + bool add_light_camera_planes_directional(LightCullPlanes &r_cull_planes, const LightSource &p_light_source); + + // Is the light culler active? maybe not in the editor... + bool is_caster_culling_active() const { return data.caster_culling_active; } + bool is_light_culling_active() const { return data.light_culling_active; } + + // Do we want to log some debug output? + bool is_logging() const { return data.debug_count == 0; } + + struct Data { + // Camera frustum planes (world space) - order ePlane. + Vector<Plane> frustum_planes; + + // Camera frustum corners (world space) - order ePoint. + Vector3 frustum_points[NUM_CAM_POINTS]; + + // Master can have multiple directional lights. + // These need to store their own cull planes individually, as master + // chops and changes between culling different lights + // instead of doing one by one, and we don't want to prepare + // lights multiple times per frame. + LocalVector<LightCullPlanes> directional_cull_planes; + + // Single threaded cull planes for regular lights + // (OMNI, SPOT). These lights reuse the same set of cull plane data. + LightCullPlanes regular_cull_planes; + +#ifdef LIGHT_CULLER_DEBUG_REGULAR_LIGHT + uint32_t regular_rejected_count = 0; +#endif + // The whole regular light can be out of range of the view frustum, in which case all casters should be culled. + bool out_of_range = false; + +#ifdef RENDERING_LIGHT_CULLER_DEBUG_STRINGS + static String plane_bitfield_to_string(unsigned int BF); + // Names of the plane and point enums, useful for debugging. + static const char *string_planes[]; + static const char *string_points[]; +#endif + + // Precalculated look up table. + static uint8_t LUT_entry_sizes[LUT_SIZE]; + static uint8_t LUT_entries[LUT_SIZE][8]; + + bool caster_culling_active = true; + bool light_culling_active = true; + + // Light culling is a basic on / off switch. + // Caster culling only works if light culling is also on. + bool is_active() const { return light_culling_active; } + + // Ideally a frame counter, but for ease of implementation + // this is just incremented on each prepare_camera. + // used to turn on and off debugging features. + int debug_count = -1; + } data; + + // This functionality is not required in general use (and is compiled out), + // as the lookup table can normally be hard coded + // (provided order of planes etc does not change). + // It is provided for debugging / future maintenance. +#ifdef RENDERING_LIGHT_CULLER_CALCULATE_LUT + void get_neighbouring_planes(PlaneOrder p_plane, PlaneOrder r_neigh_planes[4]) const; + void get_corners_of_planes(PlaneOrder p_plane_a, PlaneOrder p_plane_b, PointOrder r_points[2]) const; + void create_LUT(); + void compact_LUT_entry(uint32_t p_entry_id); + void debug_print_LUT(); + void debug_print_LUT_as_table(); + void add_LUT(int p_plane_0, int p_plane_1, PointOrder p_pts[2]); + void add_LUT_entry(uint32_t p_entry_id, PointOrder p_pts[2]); + String debug_string_LUT_entry(const LocalVector<uint8_t> &p_entry, bool p_pair = false); + String string_LUT_entry(const LocalVector<uint8_t> &p_entry); + + // Contains a list of points for each combination of plane facing directions. + LocalVector<uint8_t> _calculated_LUT[LUT_SIZE]; +#endif +}; + +#endif // RENDERING_LIGHT_CULLER_H |