rendering_light_culler.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /**************************************************************************/
  2. /* rendering_light_culler.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "rendering_light_culler.h"
  31. #include "core/math/plane.h"
  32. #include "core/math/projection.h"
  33. #include "rendering_server_globals.h"
  34. #ifdef RENDERING_LIGHT_CULLER_DEBUG_STRINGS
  35. const char *RenderingLightCuller::Data::string_planes[] = {
  36. "NEAR",
  37. "FAR",
  38. "LEFT",
  39. "TOP",
  40. "RIGHT",
  41. "BOTTOM",
  42. };
  43. const char *RenderingLightCuller::Data::string_points[] = {
  44. "FAR_LEFT_TOP",
  45. "FAR_LEFT_BOTTOM",
  46. "FAR_RIGHT_TOP",
  47. "FAR_RIGHT_BOTTOM",
  48. "NEAR_LEFT_TOP",
  49. "NEAR_LEFT_BOTTOM",
  50. "NEAR_RIGHT_TOP",
  51. "NEAR_RIGHT_BOTTOM",
  52. };
  53. String RenderingLightCuller::Data::plane_bitfield_to_string(unsigned int BF) {
  54. String sz;
  55. for (int n = 0; n < 6; n++) {
  56. unsigned int bit = 1 << n;
  57. if (BF & bit) {
  58. sz += String(string_planes[n]) + ", ";
  59. }
  60. }
  61. return sz;
  62. }
  63. #endif
  64. void RenderingLightCuller::prepare_directional_light(const RendererSceneCull::Instance *p_instance, int32_t p_directional_light_id) {
  65. //data.directional_light = p_instance;
  66. // Something is probably going wrong, we shouldn't have this many directional lights...
  67. ERR_FAIL_COND(p_directional_light_id > 512);
  68. DEV_ASSERT(p_directional_light_id >= 0);
  69. // First make sure we have enough directional lights to hold this one.
  70. if (p_directional_light_id >= (int32_t)data.directional_cull_planes.size()) {
  71. data.directional_cull_planes.resize(p_directional_light_id + 1);
  72. }
  73. _prepare_light(*p_instance, p_directional_light_id);
  74. }
  75. bool RenderingLightCuller::_prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id) {
  76. if (!data.is_active()) {
  77. return true;
  78. }
  79. LightSource lsource;
  80. switch (RSG::light_storage->light_get_type(p_instance.base)) {
  81. case RS::LIGHT_SPOT:
  82. lsource.type = LightSource::ST_SPOTLIGHT;
  83. lsource.angle = RSG::light_storage->light_get_param(p_instance.base, RS::LIGHT_PARAM_SPOT_ANGLE);
  84. lsource.range = RSG::light_storage->light_get_param(p_instance.base, RS::LIGHT_PARAM_RANGE);
  85. break;
  86. case RS::LIGHT_OMNI:
  87. lsource.type = LightSource::ST_OMNI;
  88. lsource.range = RSG::light_storage->light_get_param(p_instance.base, RS::LIGHT_PARAM_RANGE);
  89. break;
  90. case RS::LIGHT_DIRECTIONAL:
  91. lsource.type = LightSource::ST_DIRECTIONAL;
  92. // Could deal with a max directional shadow range here? NYI
  93. // LIGHT_PARAM_SHADOW_MAX_DISTANCE
  94. break;
  95. }
  96. lsource.pos = p_instance.transform.origin;
  97. lsource.dir = -p_instance.transform.basis.get_column(2);
  98. lsource.dir.normalize();
  99. bool visible;
  100. if (p_directional_light_id == -1) {
  101. visible = _add_light_camera_planes(data.regular_cull_planes, lsource);
  102. } else {
  103. visible = _add_light_camera_planes(data.directional_cull_planes[p_directional_light_id], lsource);
  104. }
  105. if (data.light_culling_active) {
  106. return visible;
  107. }
  108. return true;
  109. }
  110. bool RenderingLightCuller::cull_directional_light(const RendererSceneCull::InstanceBounds &p_bound, int32_t p_directional_light_id) {
  111. if (!data.is_active() || !is_caster_culling_active()) {
  112. return true;
  113. }
  114. ERR_FAIL_INDEX_V(p_directional_light_id, (int32_t)data.directional_cull_planes.size(), true);
  115. LightCullPlanes &cull_planes = data.directional_cull_planes[p_directional_light_id];
  116. Vector3 mins = Vector3(p_bound.bounds[0], p_bound.bounds[1], p_bound.bounds[2]);
  117. Vector3 maxs = Vector3(p_bound.bounds[3], p_bound.bounds[4], p_bound.bounds[5]);
  118. AABB bb(mins, maxs - mins);
  119. real_t r_min, r_max;
  120. for (int p = 0; p < cull_planes.num_cull_planes; p++) {
  121. bb.project_range_in_plane(cull_planes.cull_planes[p], r_min, r_max);
  122. if (r_min > 0.0f) {
  123. #ifdef LIGHT_CULLER_DEBUG_DIRECTIONAL_LIGHT
  124. cull_planes.rejected_count++;
  125. #endif
  126. return false;
  127. }
  128. }
  129. return true;
  130. }
  131. void RenderingLightCuller::cull_regular_light(PagedArray<RendererSceneCull::Instance *> &r_instance_shadow_cull_result) {
  132. if (!data.is_active() || !is_caster_culling_active()) {
  133. return;
  134. }
  135. // If the light is out of range, no need to check anything, just return 0 casters.
  136. // Ideally an out of range light should not even be drawn AT ALL (no shadow map, no PCF etc).
  137. if (data.out_of_range) {
  138. return;
  139. }
  140. // Shorter local alias.
  141. PagedArray<RendererSceneCull::Instance *> &list = r_instance_shadow_cull_result;
  142. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  143. uint32_t count_before = r_instance_shadow_cull_result.size();
  144. #endif
  145. // Go through all the casters in the list (the list will hopefully shrink as we go).
  146. for (int n = 0; n < (int)list.size(); n++) {
  147. // World space aabb.
  148. const AABB &bb = list[n]->transformed_aabb;
  149. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  150. if (is_logging()) {
  151. print_line("bb : " + String(bb));
  152. }
  153. #endif
  154. real_t r_min, r_max;
  155. bool show = true;
  156. for (int p = 0; p < data.regular_cull_planes.num_cull_planes; p++) {
  157. // As we only need r_min, could this be optimized?
  158. bb.project_range_in_plane(data.regular_cull_planes.cull_planes[p], r_min, r_max);
  159. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  160. if (is_logging()) {
  161. print_line("\tplane " + itos(p) + " : " + String(data.regular_cull_planes.cull_planes[p]) + " r_min " + String(Variant(r_min)) + " r_max " + String(Variant(r_max)));
  162. }
  163. #endif
  164. if (r_min > 0.0f) {
  165. show = false;
  166. break;
  167. }
  168. }
  169. // Remove.
  170. if (!show) {
  171. list.remove_at_unordered(n);
  172. // Repeat this element next iteration of the loop as it has been removed and replaced by the last.
  173. n--;
  174. #ifdef LIGHT_CULLER_DEBUG_REGULAR_LIGHT
  175. data.regular_rejected_count++;
  176. #endif
  177. }
  178. }
  179. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  180. uint32_t removed = r_instance_shadow_cull_result.size() - count_before;
  181. if (removed) {
  182. if (((data.debug_count) % 60) == 0) {
  183. print_line("[" + itos(data.debug_count) + "] linear cull before " + itos(count_before) + " after " + itos(r_instance_shadow_cull_result.size()));
  184. }
  185. }
  186. #endif
  187. }
  188. void RenderingLightCuller::LightCullPlanes::add_cull_plane(const Plane &p) {
  189. ERR_FAIL_COND(num_cull_planes >= MAX_CULL_PLANES);
  190. cull_planes[num_cull_planes++] = p;
  191. }
  192. // Directional lights are different to points, as the origin is infinitely in the distance, so the plane third
  193. // points are derived differently.
  194. bool RenderingLightCuller::add_light_camera_planes_directional(LightCullPlanes &r_cull_planes, const LightSource &p_light_source) {
  195. uint32_t lookup = 0;
  196. r_cull_planes.num_cull_planes = 0;
  197. // Directional light, we will use dot against the light direction to determine back facing planes.
  198. for (int n = 0; n < 6; n++) {
  199. float dot = data.frustum_planes[n].normal.dot(p_light_source.dir);
  200. if (dot > 0.0f) {
  201. lookup |= 1 << n;
  202. // Add backfacing camera frustum planes.
  203. r_cull_planes.add_cull_plane(data.frustum_planes[n]);
  204. }
  205. }
  206. ERR_FAIL_COND_V(lookup >= LUT_SIZE, true);
  207. // Deal with special case... if the light is INSIDE the view frustum (i.e. all planes face away)
  208. // then we will add the camera frustum planes to clip the light volume .. there is no need to
  209. // render shadow casters outside the frustum as shadows can never re-enter the frustum.
  210. // Should never happen with directional light?? This may be able to be removed.
  211. if (lookup == 63) {
  212. r_cull_planes.num_cull_planes = 0;
  213. for (int n = 0; n < data.frustum_planes.size(); n++) {
  214. r_cull_planes.add_cull_plane(data.frustum_planes[n]);
  215. }
  216. return true;
  217. }
  218. // Each edge forms a plane.
  219. #ifdef RENDERING_LIGHT_CULLER_CALCULATE_LUT
  220. const LocalVector<uint8_t> &entry = _calculated_LUT[lookup];
  221. // each edge forms a plane
  222. int n_edges = entry.size() - 1;
  223. #else
  224. uint8_t *entry = &data.LUT_entries[lookup][0];
  225. int n_edges = data.LUT_entry_sizes[lookup] - 1;
  226. #endif
  227. for (int e = 0; e < n_edges; e++) {
  228. int i0 = entry[e];
  229. int i1 = entry[e + 1];
  230. const Vector3 &pt0 = data.frustum_points[i0];
  231. const Vector3 &pt1 = data.frustum_points[i1];
  232. // Create a third point from the light direction.
  233. Vector3 pt2 = pt0 - p_light_source.dir;
  234. if (!_is_colinear_tri(pt0, pt1, pt2)) {
  235. // Create plane from 3 points.
  236. Plane p(pt0, pt1, pt2);
  237. r_cull_planes.add_cull_plane(p);
  238. }
  239. }
  240. // Last to 0 edge.
  241. if (n_edges) {
  242. int i0 = entry[n_edges]; // Last.
  243. int i1 = entry[0]; // First.
  244. const Vector3 &pt0 = data.frustum_points[i0];
  245. const Vector3 &pt1 = data.frustum_points[i1];
  246. // Create a third point from the light direction.
  247. Vector3 pt2 = pt0 - p_light_source.dir;
  248. if (!_is_colinear_tri(pt0, pt1, pt2)) {
  249. // Create plane from 3 points.
  250. Plane p(pt0, pt1, pt2);
  251. r_cull_planes.add_cull_plane(p);
  252. }
  253. }
  254. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  255. if (is_logging()) {
  256. print_line("lcam.pos is " + String(p_light_source.pos));
  257. }
  258. #endif
  259. return true;
  260. }
  261. bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source) {
  262. if (!data.is_active()) {
  263. return true;
  264. }
  265. // We should have called prepare_camera before this.
  266. ERR_FAIL_COND_V(data.frustum_planes.size() != 6, true);
  267. switch (p_light_source.type) {
  268. case LightSource::ST_SPOTLIGHT:
  269. case LightSource::ST_OMNI:
  270. break;
  271. case LightSource::ST_DIRECTIONAL:
  272. return add_light_camera_planes_directional(r_cull_planes, p_light_source);
  273. break;
  274. default:
  275. return false; // not yet supported
  276. break;
  277. }
  278. // Start with 0 cull planes.
  279. r_cull_planes.num_cull_planes = 0;
  280. data.out_of_range = false;
  281. uint32_t lookup = 0;
  282. // Find which of the camera planes are facing away from the light.
  283. // We can also test for the situation where the light max range means it cannot
  284. // affect the camera frustum. This is absolutely worth doing because it is relatively
  285. // cheap, and if the entire light can be culled this can vastly improve performance
  286. // (much more than just culling casters).
  287. // POINT LIGHT (spotlight, omni)
  288. // Instead of using dot product to compare light direction to plane, we can simply
  289. // find out which side of the plane the camera is on. By definition this marks the point at which the plane
  290. // becomes invisible.
  291. // OMNIS
  292. if (p_light_source.type == LightSource::ST_OMNI) {
  293. for (int n = 0; n < 6; n++) {
  294. float dist = data.frustum_planes[n].distance_to(p_light_source.pos);
  295. if (dist < 0.0f) {
  296. lookup |= 1 << n;
  297. // Add backfacing camera frustum planes.
  298. r_cull_planes.add_cull_plane(data.frustum_planes[n]);
  299. } else {
  300. // Is the light out of range?
  301. // This is one of the tests. If the point source is more than range distance from a frustum plane, it can't
  302. // be seen.
  303. if (dist >= p_light_source.range) {
  304. // If the light is out of range, no need to do anything else, everything will be culled.
  305. data.out_of_range = true;
  306. return false;
  307. }
  308. }
  309. }
  310. } else {
  311. // SPOTLIGHTs, more complex to cull.
  312. Vector3 pos_end = p_light_source.pos + (p_light_source.dir * p_light_source.range);
  313. // This is the radius of the cone at distance 1.
  314. float radius_at_dist_one = Math::tan(Math::deg_to_rad(p_light_source.angle));
  315. // The worst case radius of the cone at the end point can be calculated
  316. // (the radius will scale linearly with length along the cone).
  317. float end_cone_radius = radius_at_dist_one * p_light_source.range;
  318. for (int n = 0; n < 6; n++) {
  319. float dist = data.frustum_planes[n].distance_to(p_light_source.pos);
  320. if (dist < 0.0f) {
  321. // Either the plane is backfacing or we are inside the frustum.
  322. lookup |= 1 << n;
  323. // Add backfacing camera frustum planes.
  324. r_cull_planes.add_cull_plane(data.frustum_planes[n]);
  325. } else {
  326. // The light is in front of the plane.
  327. // Is the light out of range?
  328. if (dist >= p_light_source.range) {
  329. data.out_of_range = true;
  330. return false;
  331. }
  332. // For a spotlight, we can use an extra test
  333. // at this point the cone start is in front of the plane...
  334. // If the cone end point is further than the maximum possible distance to the plane
  335. // we can guarantee that the cone does not cross the plane, and hence the cone
  336. // is outside the frustum.
  337. float dist_end = data.frustum_planes[n].distance_to(pos_end);
  338. if (dist_end >= end_cone_radius) {
  339. data.out_of_range = true;
  340. return false;
  341. }
  342. }
  343. }
  344. }
  345. // The lookup should be within the LUT, logic should prevent this.
  346. ERR_FAIL_COND_V(lookup >= LUT_SIZE, true);
  347. // Deal with special case... if the light is INSIDE the view frustum (i.e. all planes face away)
  348. // then we will add the camera frustum planes to clip the light volume .. there is no need to
  349. // render shadow casters outside the frustum as shadows can never re-enter the frustum.
  350. if (lookup == 63) {
  351. r_cull_planes.num_cull_planes = 0;
  352. for (int n = 0; n < data.frustum_planes.size(); n++) {
  353. r_cull_planes.add_cull_plane(data.frustum_planes[n]);
  354. }
  355. return true;
  356. }
  357. // Each edge forms a plane.
  358. uint8_t *entry = &data.LUT_entries[lookup][0];
  359. int n_edges = data.LUT_entry_sizes[lookup] - 1;
  360. const Vector3 &pt2 = p_light_source.pos;
  361. for (int e = 0; e < n_edges; e++) {
  362. int i0 = entry[e];
  363. int i1 = entry[e + 1];
  364. const Vector3 &pt0 = data.frustum_points[i0];
  365. const Vector3 &pt1 = data.frustum_points[i1];
  366. if (!_is_colinear_tri(pt0, pt1, pt2)) {
  367. // Create plane from 3 points.
  368. Plane p(pt0, pt1, pt2);
  369. r_cull_planes.add_cull_plane(p);
  370. }
  371. }
  372. // Last to 0 edge.
  373. if (n_edges) {
  374. int i0 = entry[n_edges]; // Last.
  375. int i1 = entry[0]; // First.
  376. const Vector3 &pt0 = data.frustum_points[i0];
  377. const Vector3 &pt1 = data.frustum_points[i1];
  378. if (!_is_colinear_tri(pt0, pt1, pt2)) {
  379. // Create plane from 3 points.
  380. Plane p(pt0, pt1, pt2);
  381. r_cull_planes.add_cull_plane(p);
  382. }
  383. }
  384. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  385. if (is_logging()) {
  386. print_line("lsource.pos is " + String(p_light_source.pos));
  387. }
  388. #endif
  389. return true;
  390. }
  391. bool RenderingLightCuller::prepare_camera(const Transform3D &p_cam_transform, const Projection &p_cam_matrix) {
  392. data.debug_count++;
  393. if (data.debug_count >= 120) {
  394. data.debug_count = 0;
  395. }
  396. // For debug flash off and on.
  397. #ifdef LIGHT_CULLER_DEBUG_FLASH
  398. if (!Engine::get_singleton()->is_editor_hint()) {
  399. int dc = Engine::get_singleton()->get_process_frames() / LIGHT_CULLER_DEBUG_FLASH_FREQUENCY;
  400. bool bnew_active;
  401. bnew_active = (dc % 2) == 0;
  402. if (bnew_active != data.light_culling_active) {
  403. data.light_culling_active = bnew_active;
  404. print_line("switching light culler " + String(Variant(data.light_culling_active)));
  405. }
  406. }
  407. #endif
  408. if (!data.is_active()) {
  409. return false;
  410. }
  411. // Get the camera frustum planes in world space.
  412. data.frustum_planes = p_cam_matrix.get_projection_planes(p_cam_transform);
  413. DEV_CHECK_ONCE(data.frustum_planes.size() == 6);
  414. data.regular_cull_planes.num_cull_planes = 0;
  415. #ifdef LIGHT_CULLER_DEBUG_DIRECTIONAL_LIGHT
  416. if (is_logging()) {
  417. for (uint32_t n = 0; n < data.directional_cull_planes.size(); n++) {
  418. print_line("LightCuller directional light " + itos(n) + " rejected " + itos(data.directional_cull_planes[n].rejected_count) + " instances.");
  419. }
  420. }
  421. #endif
  422. #ifdef LIGHT_CULLER_DEBUG_REGULAR_LIGHT
  423. if (data.regular_rejected_count) {
  424. print_line("LightCuller regular lights rejected " + itos(data.regular_rejected_count) + " instances.");
  425. }
  426. data.regular_rejected_count = 0;
  427. #endif
  428. data.directional_cull_planes.resize(0);
  429. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  430. if (is_logging()) {
  431. for (int p = 0; p < 6; p++) {
  432. print_line("plane " + itos(p) + " : " + String(data.frustum_planes[p]));
  433. }
  434. }
  435. #endif
  436. // We want to calculate the frustum corners in a specific order.
  437. const Projection::Planes intersections[8][3] = {
  438. { Projection::PLANE_FAR, Projection::PLANE_LEFT, Projection::PLANE_TOP },
  439. { Projection::PLANE_FAR, Projection::PLANE_LEFT, Projection::PLANE_BOTTOM },
  440. { Projection::PLANE_FAR, Projection::PLANE_RIGHT, Projection::PLANE_TOP },
  441. { Projection::PLANE_FAR, Projection::PLANE_RIGHT, Projection::PLANE_BOTTOM },
  442. { Projection::PLANE_NEAR, Projection::PLANE_LEFT, Projection::PLANE_TOP },
  443. { Projection::PLANE_NEAR, Projection::PLANE_LEFT, Projection::PLANE_BOTTOM },
  444. { Projection::PLANE_NEAR, Projection::PLANE_RIGHT, Projection::PLANE_TOP },
  445. { Projection::PLANE_NEAR, Projection::PLANE_RIGHT, Projection::PLANE_BOTTOM },
  446. };
  447. for (int i = 0; i < 8; i++) {
  448. // 3 plane intersection, gives us a point.
  449. bool res = data.frustum_planes[intersections[i][0]].intersect_3(data.frustum_planes[intersections[i][1]], data.frustum_planes[intersections[i][2]], &data.frustum_points[i]);
  450. // What happens with a zero frustum? NYI - deal with this.
  451. ERR_FAIL_COND_V(!res, false);
  452. #ifdef LIGHT_CULLER_DEBUG_LOGGING
  453. if (is_logging()) {
  454. print_line("point " + itos(i) + " -> " + String(data.frustum_points[i]));
  455. }
  456. #endif
  457. }
  458. return true;
  459. }
  460. RenderingLightCuller::RenderingLightCuller() {
  461. // Used to determine which frame to give debug output.
  462. data.debug_count = -1;
  463. // Uncomment below to switch off light culler in the editor.
  464. // data.caster_culling_active = Engine::get_singleton()->is_editor_hint() == false;
  465. #ifdef RENDERING_LIGHT_CULLER_CALCULATE_LUT
  466. create_LUT();
  467. #endif
  468. }
  469. /* clang-format off */
  470. uint8_t RenderingLightCuller::Data::LUT_entry_sizes[LUT_SIZE] = {0, 4, 4, 0, 4, 6, 6, 8, 4, 6, 6, 8, 6, 6, 6, 6, 4, 6, 6, 8, 0, 8, 8, 0, 6, 6, 6, 6, 8, 6, 6, 4, 4, 6, 6, 8, 6, 6, 6, 6, 0, 8, 8, 0, 8, 6, 6, 4, 6, 6, 6, 6, 8, 6, 6, 4, 8, 6, 6, 4, 0, 4, 4, 0, };
  471. // The lookup table used to determine which edges form the silhouette of the camera frustum,
  472. // depending on the viewing angle (defined by which camera planes are backward facing).
  473. uint8_t RenderingLightCuller::Data::LUT_entries[LUT_SIZE][8] = {
  474. {0, 0, 0, 0, 0, 0, 0, 0, },
  475. {7, 6, 4, 5, 0, 0, 0, 0, },
  476. {1, 0, 2, 3, 0, 0, 0, 0, },
  477. {0, 0, 0, 0, 0, 0, 0, 0, },
  478. {1, 5, 4, 0, 0, 0, 0, 0, },
  479. {1, 5, 7, 6, 4, 0, 0, 0, },
  480. {4, 0, 2, 3, 1, 5, 0, 0, },
  481. {5, 7, 6, 4, 0, 2, 3, 1, },
  482. {0, 4, 6, 2, 0, 0, 0, 0, },
  483. {0, 4, 5, 7, 6, 2, 0, 0, },
  484. {6, 2, 3, 1, 0, 4, 0, 0, },
  485. {2, 3, 1, 0, 4, 5, 7, 6, },
  486. {0, 1, 5, 4, 6, 2, 0, 0, },
  487. {0, 1, 5, 7, 6, 2, 0, 0, },
  488. {6, 2, 3, 1, 5, 4, 0, 0, },
  489. {2, 3, 1, 5, 7, 6, 0, 0, },
  490. {2, 6, 7, 3, 0, 0, 0, 0, },
  491. {2, 6, 4, 5, 7, 3, 0, 0, },
  492. {7, 3, 1, 0, 2, 6, 0, 0, },
  493. {3, 1, 0, 2, 6, 4, 5, 7, },
  494. {0, 0, 0, 0, 0, 0, 0, 0, },
  495. {2, 6, 4, 0, 1, 5, 7, 3, },
  496. {7, 3, 1, 5, 4, 0, 2, 6, },
  497. {0, 0, 0, 0, 0, 0, 0, 0, },
  498. {2, 0, 4, 6, 7, 3, 0, 0, },
  499. {2, 0, 4, 5, 7, 3, 0, 0, },
  500. {7, 3, 1, 0, 4, 6, 0, 0, },
  501. {3, 1, 0, 4, 5, 7, 0, 0, },
  502. {2, 0, 1, 5, 4, 6, 7, 3, },
  503. {2, 0, 1, 5, 7, 3, 0, 0, },
  504. {7, 3, 1, 5, 4, 6, 0, 0, },
  505. {3, 1, 5, 7, 0, 0, 0, 0, },
  506. {3, 7, 5, 1, 0, 0, 0, 0, },
  507. {3, 7, 6, 4, 5, 1, 0, 0, },
  508. {5, 1, 0, 2, 3, 7, 0, 0, },
  509. {7, 6, 4, 5, 1, 0, 2, 3, },
  510. {3, 7, 5, 4, 0, 1, 0, 0, },
  511. {3, 7, 6, 4, 0, 1, 0, 0, },
  512. {5, 4, 0, 2, 3, 7, 0, 0, },
  513. {7, 6, 4, 0, 2, 3, 0, 0, },
  514. {0, 0, 0, 0, 0, 0, 0, 0, },
  515. {3, 7, 6, 2, 0, 4, 5, 1, },
  516. {5, 1, 0, 4, 6, 2, 3, 7, },
  517. {0, 0, 0, 0, 0, 0, 0, 0, },
  518. {3, 7, 5, 4, 6, 2, 0, 1, },
  519. {3, 7, 6, 2, 0, 1, 0, 0, },
  520. {5, 4, 6, 2, 3, 7, 0, 0, },
  521. {7, 6, 2, 3, 0, 0, 0, 0, },
  522. {3, 2, 6, 7, 5, 1, 0, 0, },
  523. {3, 2, 6, 4, 5, 1, 0, 0, },
  524. {5, 1, 0, 2, 6, 7, 0, 0, },
  525. {1, 0, 2, 6, 4, 5, 0, 0, },
  526. {3, 2, 6, 7, 5, 4, 0, 1, },
  527. {3, 2, 6, 4, 0, 1, 0, 0, },
  528. {5, 4, 0, 2, 6, 7, 0, 0, },
  529. {6, 4, 0, 2, 0, 0, 0, 0, },
  530. {3, 2, 0, 4, 6, 7, 5, 1, },
  531. {3, 2, 0, 4, 5, 1, 0, 0, },
  532. {5, 1, 0, 4, 6, 7, 0, 0, },
  533. {1, 0, 4, 5, 0, 0, 0, 0, },
  534. {0, 0, 0, 0, 0, 0, 0, 0, },
  535. {3, 2, 0, 1, 0, 0, 0, 0, },
  536. {5, 4, 6, 7, 0, 0, 0, 0, },
  537. {0, 0, 0, 0, 0, 0, 0, 0, },
  538. };
  539. /* clang-format on */
  540. #ifdef RENDERING_LIGHT_CULLER_CALCULATE_LUT
  541. // See e.g. http://lspiroengine.com/?p=153 for reference.
  542. // Principles are the same, but differences to the article:
  543. // * Order of planes / points is different in Godot.
  544. // * We use a lookup table at runtime.
  545. void RenderingLightCuller::create_LUT() {
  546. // Each pair of planes that are opposite can have an edge.
  547. for (int plane_0 = 0; plane_0 < PLANE_TOTAL; plane_0++) {
  548. // For each neighbor of the plane.
  549. PlaneOrder neighs[4];
  550. get_neighbouring_planes((PlaneOrder)plane_0, neighs);
  551. for (int n = 0; n < 4; n++) {
  552. int plane_1 = neighs[n];
  553. // If these are opposite we need to add the 2 points they share.
  554. PointOrder pts[2];
  555. get_corners_of_planes((PlaneOrder)plane_0, (PlaneOrder)plane_1, pts);
  556. add_LUT(plane_0, plane_1, pts);
  557. }
  558. }
  559. for (uint32_t n = 0; n < LUT_SIZE; n++) {
  560. compact_LUT_entry(n);
  561. }
  562. debug_print_LUT();
  563. debug_print_LUT_as_table();
  564. }
  565. // we can pre-create the entire LUT and store it hard coded as a static inside the executable!
  566. // it is only small in size, 64 entries with max 8 bytes per entry
  567. void RenderingLightCuller::debug_print_LUT_as_table() {
  568. print_line("\nLIGHT VOLUME TABLE BEGIN\n");
  569. print_line("Copy this to LUT_entry_sizes:\n");
  570. String sz = "{";
  571. for (int n = 0; n < LUT_SIZE; n++) {
  572. const LocalVector<uint8_t> &entry = _calculated_LUT[n];
  573. sz += itos(entry.size()) + ", ";
  574. }
  575. sz += "}";
  576. print_line(sz);
  577. print_line("\nCopy this to LUT_entries:\n");
  578. for (int n = 0; n < LUT_SIZE; n++) {
  579. const LocalVector<uint8_t> &entry = _calculated_LUT[n];
  580. String sz = "{";
  581. // First is the number of points in the entry.
  582. int s = entry.size();
  583. for (int p = 0; p < 8; p++) {
  584. if (p < s) {
  585. sz += itos(entry[p]);
  586. } else {
  587. sz += "0"; // just a spacer
  588. }
  589. sz += ", ";
  590. }
  591. sz += "},";
  592. print_line(sz);
  593. }
  594. print_line("\nLIGHT VOLUME TABLE END\n");
  595. }
  596. void RenderingLightCuller::debug_print_LUT() {
  597. for (int n = 0; n < LUT_SIZE; n++) {
  598. String sz;
  599. sz = "LUT" + itos(n) + ":\t";
  600. sz += Data::plane_bitfield_to_string(n);
  601. print_line(sz);
  602. const LocalVector<uint8_t> &entry = _calculated_LUT[n];
  603. sz = "\t" + string_LUT_entry(entry);
  604. print_line(sz);
  605. }
  606. }
  607. String RenderingLightCuller::string_LUT_entry(const LocalVector<uint8_t> &p_entry) {
  608. String string;
  609. for (uint32_t n = 0; n < p_entry.size(); n++) {
  610. uint8_t val = p_entry[n];
  611. DEV_ASSERT(val < 8);
  612. const char *sz_point = Data::string_points[val];
  613. string += sz_point;
  614. string += ", ";
  615. }
  616. return string;
  617. }
  618. String RenderingLightCuller::debug_string_LUT_entry(const LocalVector<uint8_t> &p_entry, bool p_pair) {
  619. String string;
  620. for (uint32_t i = 0; i < p_entry.size(); i++) {
  621. int pt_order = p_entry[i];
  622. if (p_pair && ((i % 2) == 0)) {
  623. string += itos(pt_order) + "-";
  624. } else {
  625. string += itos(pt_order) + ", ";
  626. }
  627. }
  628. return string;
  629. }
  630. void RenderingLightCuller::add_LUT(int p_plane_0, int p_plane_1, PointOrder p_pts[2]) {
  631. // Note that some entries to the LUT will be "impossible" situations,
  632. // because it contains all combinations of plane flips.
  633. uint32_t bit0 = 1 << p_plane_0;
  634. uint32_t bit1 = 1 << p_plane_1;
  635. // All entries of the LUT that have plane 0 set and plane 1 not set.
  636. for (uint32_t n = 0; n < 64; n++) {
  637. // If bit0 not set...
  638. if (!(n & bit0)) {
  639. continue;
  640. }
  641. // If bit1 set...
  642. if (n & bit1) {
  643. continue;
  644. }
  645. // Meets criteria.
  646. add_LUT_entry(n, p_pts);
  647. }
  648. }
  649. void RenderingLightCuller::add_LUT_entry(uint32_t p_entry_id, PointOrder p_pts[2]) {
  650. DEV_ASSERT(p_entry_id < LUT_SIZE);
  651. LocalVector<uint8_t> &entry = _calculated_LUT[p_entry_id];
  652. entry.push_back(p_pts[0]);
  653. entry.push_back(p_pts[1]);
  654. }
  655. void RenderingLightCuller::compact_LUT_entry(uint32_t p_entry_id) {
  656. DEV_ASSERT(p_entry_id < LUT_SIZE);
  657. LocalVector<uint8_t> &entry = _calculated_LUT[p_entry_id];
  658. int num_pairs = entry.size() / 2;
  659. if (num_pairs == 0) {
  660. return;
  661. }
  662. LocalVector<uint8_t> temp;
  663. String string;
  664. string = "Compact LUT" + itos(p_entry_id) + ":\t";
  665. string += debug_string_LUT_entry(entry, true);
  666. print_line(string);
  667. // Add first pair.
  668. temp.push_back(entry[0]);
  669. temp.push_back(entry[1]);
  670. unsigned int BFpairs = 1;
  671. string = debug_string_LUT_entry(temp) + " -> ";
  672. print_line(string);
  673. // Attempt to add a pair each time.
  674. for (int done = 1; done < num_pairs; done++) {
  675. string = "done " + itos(done) + ": ";
  676. // Find a free pair.
  677. for (int p = 1; p < num_pairs; p++) {
  678. unsigned int bit = 1 << p;
  679. // Is it done already?
  680. if (BFpairs & bit) {
  681. continue;
  682. }
  683. // There must be at least 1 free pair.
  684. // Attempt to add.
  685. int a = entry[p * 2];
  686. int b = entry[(p * 2) + 1];
  687. string += "[" + itos(a) + "-" + itos(b) + "], ";
  688. int found_a = temp.find(a);
  689. int found_b = temp.find(b);
  690. // Special case, if they are both already in the list, no need to add
  691. // as this is a link from the tail to the head of the list.
  692. if ((found_a != -1) && (found_b != -1)) {
  693. string += "foundAB link " + itos(found_a) + ", " + itos(found_b) + " ";
  694. BFpairs |= bit;
  695. goto found;
  696. }
  697. // Find a.
  698. if (found_a != -1) {
  699. string += "foundA " + itos(found_a) + " ";
  700. temp.insert(found_a + 1, b);
  701. BFpairs |= bit;
  702. goto found;
  703. }
  704. // Find b.
  705. if (found_b != -1) {
  706. string += "foundB " + itos(found_b) + " ";
  707. temp.insert(found_b, a);
  708. BFpairs |= bit;
  709. goto found;
  710. }
  711. } // Check each pair for adding.
  712. // If we got here before finding a link, the whole set of planes is INVALID
  713. // e.g. far and near plane only, does not create continuous sillouhette of edges.
  714. print_line("\tINVALID");
  715. entry.clear();
  716. return;
  717. found:;
  718. print_line(string);
  719. string = "\ttemp now : " + debug_string_LUT_entry(temp);
  720. print_line(string);
  721. }
  722. // temp should now be the sorted entry .. delete the old one and replace by temp.
  723. entry.clear();
  724. entry = temp;
  725. }
  726. void RenderingLightCuller::get_neighbouring_planes(PlaneOrder p_plane, PlaneOrder r_neigh_planes[4]) const {
  727. // Table of neighboring planes to each.
  728. static const PlaneOrder neigh_table[PLANE_TOTAL][4] = {
  729. { // LSM_FP_NEAR
  730. PLANE_LEFT,
  731. PLANE_RIGHT,
  732. PLANE_TOP,
  733. PLANE_BOTTOM },
  734. { // LSM_FP_FAR
  735. PLANE_LEFT,
  736. PLANE_RIGHT,
  737. PLANE_TOP,
  738. PLANE_BOTTOM },
  739. { // LSM_FP_LEFT
  740. PLANE_TOP,
  741. PLANE_BOTTOM,
  742. PLANE_NEAR,
  743. PLANE_FAR },
  744. { // LSM_FP_TOP
  745. PLANE_LEFT,
  746. PLANE_RIGHT,
  747. PLANE_NEAR,
  748. PLANE_FAR },
  749. { // LSM_FP_RIGHT
  750. PLANE_TOP,
  751. PLANE_BOTTOM,
  752. PLANE_NEAR,
  753. PLANE_FAR },
  754. { // LSM_FP_BOTTOM
  755. PLANE_LEFT,
  756. PLANE_RIGHT,
  757. PLANE_NEAR,
  758. PLANE_FAR },
  759. };
  760. for (int n = 0; n < 4; n++) {
  761. r_neigh_planes[n] = neigh_table[p_plane][n];
  762. }
  763. }
  764. // Given two planes, returns the two points shared by those planes. The points are always
  765. // returned in counter-clockwise order, assuming the first input plane is facing towards
  766. // the viewer.
  767. // param p_plane_a The plane facing towards the viewer.
  768. // param p_plane_b A plane neighboring p_plane_a.
  769. // param r_points An array of exactly two elements to be filled with the indices of the points
  770. // on return.
  771. void RenderingLightCuller::get_corners_of_planes(PlaneOrder p_plane_a, PlaneOrder p_plane_b, PointOrder r_points[2]) const {
  772. static const PointOrder fp_table[PLANE_TOTAL][PLANE_TOTAL][2] = {
  773. {
  774. // LSM_FP_NEAR
  775. {
  776. // LSM_FP_NEAR
  777. PT_NEAR_LEFT_TOP, PT_NEAR_RIGHT_TOP, // Invalid combination.
  778. },
  779. {
  780. // LSM_FP_FAR
  781. PT_FAR_RIGHT_TOP, PT_FAR_LEFT_TOP, // Invalid combination.
  782. },
  783. {
  784. // LSM_FP_LEFT
  785. PT_NEAR_LEFT_TOP,
  786. PT_NEAR_LEFT_BOTTOM,
  787. },
  788. {
  789. // LSM_FP_TOP
  790. PT_NEAR_RIGHT_TOP,
  791. PT_NEAR_LEFT_TOP,
  792. },
  793. {
  794. // LSM_FP_RIGHT
  795. PT_NEAR_RIGHT_BOTTOM,
  796. PT_NEAR_RIGHT_TOP,
  797. },
  798. {
  799. // LSM_FP_BOTTOM
  800. PT_NEAR_LEFT_BOTTOM,
  801. PT_NEAR_RIGHT_BOTTOM,
  802. },
  803. },
  804. {
  805. // LSM_FP_FAR
  806. {
  807. // LSM_FP_NEAR
  808. PT_FAR_LEFT_TOP, PT_FAR_RIGHT_TOP, // Invalid combination.
  809. },
  810. {
  811. // LSM_FP_FAR
  812. PT_FAR_RIGHT_TOP, PT_FAR_LEFT_TOP, // Invalid combination.
  813. },
  814. {
  815. // LSM_FP_LEFT
  816. PT_FAR_LEFT_BOTTOM,
  817. PT_FAR_LEFT_TOP,
  818. },
  819. {
  820. // LSM_FP_TOP
  821. PT_FAR_LEFT_TOP,
  822. PT_FAR_RIGHT_TOP,
  823. },
  824. {
  825. // LSM_FP_RIGHT
  826. PT_FAR_RIGHT_TOP,
  827. PT_FAR_RIGHT_BOTTOM,
  828. },
  829. {
  830. // LSM_FP_BOTTOM
  831. PT_FAR_RIGHT_BOTTOM,
  832. PT_FAR_LEFT_BOTTOM,
  833. },
  834. },
  835. {
  836. // LSM_FP_LEFT
  837. {
  838. // LSM_FP_NEAR
  839. PT_NEAR_LEFT_BOTTOM,
  840. PT_NEAR_LEFT_TOP,
  841. },
  842. {
  843. // LSM_FP_FAR
  844. PT_FAR_LEFT_TOP,
  845. PT_FAR_LEFT_BOTTOM,
  846. },
  847. {
  848. // LSM_FP_LEFT
  849. PT_FAR_LEFT_BOTTOM, PT_FAR_LEFT_BOTTOM, // Invalid combination.
  850. },
  851. {
  852. // LSM_FP_TOP
  853. PT_NEAR_LEFT_TOP,
  854. PT_FAR_LEFT_TOP,
  855. },
  856. {
  857. // LSM_FP_RIGHT
  858. PT_FAR_LEFT_BOTTOM, PT_FAR_LEFT_BOTTOM, // Invalid combination.
  859. },
  860. {
  861. // LSM_FP_BOTTOM
  862. PT_FAR_LEFT_BOTTOM,
  863. PT_NEAR_LEFT_BOTTOM,
  864. },
  865. },
  866. {
  867. // LSM_FP_TOP
  868. {
  869. // LSM_FP_NEAR
  870. PT_NEAR_LEFT_TOP,
  871. PT_NEAR_RIGHT_TOP,
  872. },
  873. {
  874. // LSM_FP_FAR
  875. PT_FAR_RIGHT_TOP,
  876. PT_FAR_LEFT_TOP,
  877. },
  878. {
  879. // LSM_FP_LEFT
  880. PT_FAR_LEFT_TOP,
  881. PT_NEAR_LEFT_TOP,
  882. },
  883. {
  884. // LSM_FP_TOP
  885. PT_NEAR_LEFT_TOP, PT_FAR_LEFT_TOP, // Invalid combination.
  886. },
  887. {
  888. // LSM_FP_RIGHT
  889. PT_NEAR_RIGHT_TOP,
  890. PT_FAR_RIGHT_TOP,
  891. },
  892. {
  893. // LSM_FP_BOTTOM
  894. PT_FAR_LEFT_BOTTOM, PT_NEAR_LEFT_BOTTOM, // Invalid combination.
  895. },
  896. },
  897. {
  898. // LSM_FP_RIGHT
  899. {
  900. // LSM_FP_NEAR
  901. PT_NEAR_RIGHT_TOP,
  902. PT_NEAR_RIGHT_BOTTOM,
  903. },
  904. {
  905. // LSM_FP_FAR
  906. PT_FAR_RIGHT_BOTTOM,
  907. PT_FAR_RIGHT_TOP,
  908. },
  909. {
  910. // LSM_FP_LEFT
  911. PT_FAR_RIGHT_BOTTOM, PT_FAR_RIGHT_BOTTOM, // Invalid combination.
  912. },
  913. {
  914. // LSM_FP_TOP
  915. PT_FAR_RIGHT_TOP,
  916. PT_NEAR_RIGHT_TOP,
  917. },
  918. {
  919. // LSM_FP_RIGHT
  920. PT_FAR_RIGHT_BOTTOM, PT_FAR_RIGHT_BOTTOM, // Invalid combination.
  921. },
  922. {
  923. // LSM_FP_BOTTOM
  924. PT_NEAR_RIGHT_BOTTOM,
  925. PT_FAR_RIGHT_BOTTOM,
  926. },
  927. },
  928. // ==
  929. // P_NEAR,
  930. // P_FAR,
  931. // P_LEFT,
  932. // P_TOP,
  933. // P_RIGHT,
  934. // P_BOTTOM,
  935. {
  936. // LSM_FP_BOTTOM
  937. {
  938. // LSM_FP_NEAR
  939. PT_NEAR_RIGHT_BOTTOM,
  940. PT_NEAR_LEFT_BOTTOM,
  941. },
  942. {
  943. // LSM_FP_FAR
  944. PT_FAR_LEFT_BOTTOM,
  945. PT_FAR_RIGHT_BOTTOM,
  946. },
  947. {
  948. // LSM_FP_LEFT
  949. PT_NEAR_LEFT_BOTTOM,
  950. PT_FAR_LEFT_BOTTOM,
  951. },
  952. {
  953. // LSM_FP_TOP
  954. PT_NEAR_LEFT_BOTTOM, PT_FAR_LEFT_BOTTOM, // Invalid combination.
  955. },
  956. {
  957. // LSM_FP_RIGHT
  958. PT_FAR_RIGHT_BOTTOM,
  959. PT_NEAR_RIGHT_BOTTOM,
  960. },
  961. {
  962. // LSM_FP_BOTTOM
  963. PT_FAR_LEFT_BOTTOM, PT_NEAR_LEFT_BOTTOM, // Invalid combination.
  964. },
  965. },
  966. // ==
  967. };
  968. r_points[0] = fp_table[p_plane_a][p_plane_b][0];
  969. r_points[1] = fp_table[p_plane_a][p_plane_b][1];
  970. }
  971. #endif