debug_effects.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /**************************************************************************/
  2. /* debug_effects.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 "debug_effects.h"
  31. #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
  32. #include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
  33. #include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
  34. #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
  35. using namespace RendererRD;
  36. DebugEffects::DebugEffects() {
  37. {
  38. // Shadow Frustum debug shader
  39. Vector<String> modes;
  40. modes.push_back("");
  41. shadow_frustum.shader.initialize(modes);
  42. shadow_frustum.shader_version = shadow_frustum.shader.version_create();
  43. RD::PipelineRasterizationState raster_state = RD::PipelineRasterizationState();
  44. shadow_frustum.pipelines[SFP_TRANSPARENT].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0);
  45. raster_state.wireframe = true;
  46. shadow_frustum.pipelines[SFP_WIREFRAME].setup(shadow_frustum.shader.version_get_shader(shadow_frustum.shader_version, 0), RD::RENDER_PRIMITIVE_LINES, raster_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
  47. }
  48. }
  49. void DebugEffects::_create_frustum_arrays() {
  50. if (frustum.vertex_buffer.is_null()) {
  51. // Create vertex buffer, but don't put data in it yet
  52. frustum.vertex_buffer = RD::get_singleton()->vertex_buffer_create(8 * sizeof(float) * 3, Vector<uint8_t>(), false);
  53. Vector<RD::VertexAttribute> attributes;
  54. Vector<RID> buffers;
  55. RD::VertexAttribute vd;
  56. vd.location = 0;
  57. vd.stride = sizeof(float) * 3;
  58. vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT;
  59. attributes.push_back(vd);
  60. buffers.push_back(frustum.vertex_buffer);
  61. frustum.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
  62. frustum.vertex_array = RD::get_singleton()->vertex_array_create(8, frustum.vertex_format, buffers);
  63. }
  64. if (frustum.index_buffer.is_null()) {
  65. uint32_t indices[6 * 2 * 3] = {
  66. // Far
  67. 0, 1, 2, // FLT, FLB, FRT
  68. 1, 3, 2, // FLB, FRB, FRT
  69. // Near
  70. 4, 6, 5, // NLT, NRT, NLB
  71. 6, 7, 5, // NRT, NRB, NLB
  72. // Left
  73. 0, 4, 1, // FLT, NLT, FLB
  74. 4, 5, 1, // NLT, NLB, FLB
  75. // Right
  76. 6, 2, 7, // NRT, FRT, NRB
  77. 2, 3, 7, // FRT, FRB, NRB
  78. // Top
  79. 0, 2, 4, // FLT, FRT, NLT
  80. 2, 6, 4, // FRT, NRT, NLT
  81. // Bottom
  82. 5, 7, 1, // NLB, NRB, FLB,
  83. 7, 3, 1, // NRB, FRB, FLB
  84. };
  85. // Create our index_array
  86. PackedByteArray data;
  87. data.resize(6 * 2 * 3 * 4);
  88. {
  89. uint8_t *w = data.ptrw();
  90. int *p32 = (int *)w;
  91. for (int i = 0; i < 6 * 2 * 3; i++) {
  92. *p32 = indices[i];
  93. p32++;
  94. }
  95. }
  96. frustum.index_buffer = RD::get_singleton()->index_buffer_create(6 * 2 * 3, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data);
  97. frustum.index_array = RD::get_singleton()->index_array_create(frustum.index_buffer, 0, 6 * 2 * 3);
  98. }
  99. if (frustum.lines_buffer.is_null()) {
  100. uint32_t indices[12 * 2] = {
  101. 0, 1, // FLT - FLB
  102. 1, 3, // FLB - FRB
  103. 3, 2, // FRB - FRT
  104. 2, 0, // FRT - FLT
  105. 4, 6, // NLT - NRT
  106. 6, 7, // NRT - NRB
  107. 7, 5, // NRB - NLB
  108. 5, 4, // NLB - NLT
  109. 0, 4, // FLT - NLT
  110. 1, 5, // FLB - NLB
  111. 2, 6, // FRT - NRT
  112. 3, 7, // FRB - NRB
  113. };
  114. // Create our lines_array
  115. PackedByteArray data;
  116. data.resize(12 * 2 * 4);
  117. {
  118. uint8_t *w = data.ptrw();
  119. int *p32 = (int *)w;
  120. for (int i = 0; i < 12 * 2; i++) {
  121. *p32 = indices[i];
  122. p32++;
  123. }
  124. }
  125. frustum.lines_buffer = RD::get_singleton()->index_buffer_create(12 * 2, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, data);
  126. frustum.lines_array = RD::get_singleton()->index_array_create(frustum.lines_buffer, 0, 12 * 2);
  127. }
  128. }
  129. DebugEffects::~DebugEffects() {
  130. shadow_frustum.shader.version_free(shadow_frustum.shader_version);
  131. // Destroy vertex buffer and array.
  132. if (frustum.vertex_buffer.is_valid()) {
  133. RD::get_singleton()->free(frustum.vertex_buffer); // Array gets freed as dependency.
  134. }
  135. // Destroy index buffer and array,
  136. if (frustum.index_buffer.is_valid()) {
  137. RD::get_singleton()->free(frustum.index_buffer); // Array gets freed as dependency.
  138. }
  139. // Destroy lines buffer and array.
  140. if (frustum.lines_buffer.is_valid()) {
  141. RD::get_singleton()->free(frustum.lines_buffer); // Array gets freed as dependency.
  142. }
  143. }
  144. void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_projection, const Transform3D &p_cam_transform, RID p_dest_fb, const Rect2 p_rect) {
  145. RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
  146. RID base = light_storage->light_instance_get_base_light(p_light);
  147. ERR_FAIL_COND(light_storage->light_get_type(base) != RS::LIGHT_DIRECTIONAL);
  148. // Make sure our buffers and arrays exist.
  149. _create_frustum_arrays();
  150. // Setup a points buffer for our view frustum.
  151. PackedByteArray points;
  152. points.resize(8 * sizeof(float) * 3);
  153. // Get info about our splits.
  154. RS::LightDirectionalShadowMode shadow_mode = light_storage->light_directional_get_shadow_mode(base);
  155. bool overlap = light_storage->light_directional_get_blend_splits(base);
  156. int splits = 1;
  157. if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
  158. splits = 4;
  159. } else if (shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
  160. splits = 2;
  161. }
  162. // Setup our camera info (this is mostly a duplicate of the logic found in RendererSceneCull::_light_instance_setup_directional_shadow).
  163. bool is_orthogonal = p_cam_projection.is_orthogonal();
  164. real_t aspect = p_cam_projection.get_aspect();
  165. real_t fov = 0.0;
  166. Vector2 vp_he;
  167. if (is_orthogonal) {
  168. vp_he = p_cam_projection.get_viewport_half_extents();
  169. } else {
  170. fov = p_cam_projection.get_fov(); //this is actually yfov, because set aspect tries to keep it
  171. }
  172. real_t min_distance = p_cam_projection.get_z_near();
  173. real_t max_distance = p_cam_projection.get_z_far();
  174. real_t shadow_max = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_MAX_DISTANCE);
  175. if (shadow_max > 0 && !is_orthogonal) {
  176. max_distance = MIN(shadow_max, max_distance);
  177. }
  178. // Make sure we've not got bad info coming in.
  179. max_distance = MAX(max_distance, min_distance + 0.001);
  180. min_distance = MIN(min_distance, max_distance);
  181. real_t range = max_distance - min_distance;
  182. real_t distances[5];
  183. distances[0] = min_distance;
  184. for (int i = 0; i < splits; i++) {
  185. distances[i + 1] = min_distance + RSG::light_storage->light_get_param(base, RS::LightParam(RS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range;
  186. };
  187. distances[splits] = max_distance;
  188. Color colors[4] = {
  189. Color(1.0, 0.0, 0.0, 0.1),
  190. Color(0.0, 1.0, 0.0, 0.1),
  191. Color(0.0, 0.0, 1.0, 0.1),
  192. Color(1.0, 1.0, 0.0, 0.1),
  193. };
  194. for (int split = 0; split < splits; split++) {
  195. // Load frustum points into vertex buffer.
  196. uint8_t *w = points.ptrw();
  197. Vector3 *vw = (Vector3 *)w;
  198. Projection projection;
  199. if (is_orthogonal) {
  200. projection.set_orthogonal(vp_he.y * 2.0, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], false);
  201. } else {
  202. projection.set_perspective(fov, aspect, distances[(split == 0 || !overlap) ? split : split - 1], distances[split + 1], true);
  203. }
  204. bool res = projection.get_endpoints(p_cam_transform, vw);
  205. ERR_CONTINUE(!res);
  206. RD::get_singleton()->buffer_update(frustum.vertex_buffer, 0, 8 * sizeof(float) * 3, w);
  207. // Get our light projection info.
  208. Projection light_projection = light_storage->light_instance_get_shadow_camera(p_light, split);
  209. Transform3D light_transform = light_storage->light_instance_get_shadow_transform(p_light, split);
  210. Rect2 atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, split);
  211. if (!is_orthogonal) {
  212. light_transform.orthogonalize();
  213. }
  214. // Setup our push constant.
  215. ShadowFrustumPushConstant push_constant;
  216. MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
  217. push_constant.color[0] = colors[split].r;
  218. push_constant.color[1] = colors[split].g;
  219. push_constant.color[2] = colors[split].b;
  220. push_constant.color[3] = colors[split].a;
  221. // Adjust our rect to our atlas position.
  222. Rect2 rect = p_rect;
  223. rect.position.x += atlas_rect_norm.position.x * rect.size.x;
  224. rect.position.y += atlas_rect_norm.position.y * rect.size.y;
  225. rect.size.x *= atlas_rect_norm.size.x;
  226. rect.size.y *= atlas_rect_norm.size.y;
  227. // And draw our frustum.
  228. RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb);
  229. RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
  230. RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
  231. RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
  232. RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
  233. RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
  234. RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
  235. RD::get_singleton()->draw_list_draw(draw_list, true);
  236. pipeline = shadow_frustum.pipelines[SFP_WIREFRAME].get_render_pipeline(frustum.vertex_format, fb_format_id);
  237. RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
  238. RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
  239. RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.lines_array);
  240. RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
  241. RD::get_singleton()->draw_list_draw(draw_list, true);
  242. RD::get_singleton()->draw_list_end();
  243. if (split < (splits - 1) && splits > 1) {
  244. // Also draw it in the last split so we get a proper overview of the whole view frustum...
  245. // Get our light projection info.
  246. light_projection = light_storage->light_instance_get_shadow_camera(p_light, (splits - 1));
  247. light_transform = light_storage->light_instance_get_shadow_transform(p_light, (splits - 1));
  248. atlas_rect_norm = light_storage->light_instance_get_directional_shadow_atlas_rect(p_light, (splits - 1));
  249. if (!is_orthogonal) {
  250. light_transform.orthogonalize();
  251. }
  252. // Update our push constant.
  253. MaterialStorage::store_camera(light_projection * Projection(light_transform.inverse()), push_constant.mvp);
  254. push_constant.color[0] = colors[split].r;
  255. push_constant.color[1] = colors[split].g;
  256. push_constant.color[2] = colors[split].b;
  257. push_constant.color[3] = colors[split].a;
  258. // Adjust our rect to our atlas position.
  259. rect = p_rect;
  260. rect.position.x += atlas_rect_norm.position.x * rect.size.x;
  261. rect.position.y += atlas_rect_norm.position.y * rect.size.y;
  262. rect.size.x *= atlas_rect_norm.size.x;
  263. rect.size.y *= atlas_rect_norm.size.y;
  264. draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
  265. pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
  266. RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
  267. RD::get_singleton()->draw_list_bind_vertex_array(draw_list, frustum.vertex_array);
  268. RD::get_singleton()->draw_list_bind_index_array(draw_list, frustum.index_array);
  269. RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ShadowFrustumPushConstant));
  270. RD::get_singleton()->draw_list_draw(draw_list, true);
  271. RD::get_singleton()->draw_list_end();
  272. }
  273. }
  274. }