💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
12 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "render/passes/shadow-map-pass.hpp"
  20. #include "resources/resource-manager.hpp"
  21. #include "gl/rasterizer.hpp"
  22. #include "gl/framebuffer.hpp"
  23. #include "gl/shader-program.hpp"
  24. #include "gl/shader-input.hpp"
  25. #include "gl/drawing-mode.hpp"
  26. #include "render/context.hpp"
  27. #include "render/material.hpp"
  28. #include "scene/camera.hpp"
  29. #include "scene/collection.hpp"
  30. #include "scene/light.hpp"
  31. #include "geom/view-frustum.hpp"
  32. #include "geom/aabb.hpp"
  33. #include "config.hpp"
  34. #include "math/interpolation.hpp"
  35. #include "math/vector.hpp"
  36. #include "math/matrix.hpp"
  37. #include "math/quaternion.hpp"
  38. #include "math/projection.hpp"
  39. #include <cmath>
  40. #include <glad/glad.h>
  41. namespace render {
  42. static bool operation_compare(const render::operation& a, const render::operation& b);
  43. shadow_map_pass::shadow_map_pass(gl::rasterizer* rasterizer, resource_manager* resource_manager):
  44. pass(rasterizer, nullptr)
  45. {
  46. // Load skinned shader program
  47. unskinned_shader_program = resource_manager->load<gl::shader_program>("depth-unskinned.glsl");
  48. unskinned_model_view_projection_input = unskinned_shader_program->get_input("model_view_projection");
  49. // Load unskinned shader program
  50. skinned_shader_program = resource_manager->load<gl::shader_program>("depth-skinned.glsl");
  51. skinned_model_view_projection_input = skinned_shader_program->get_input("model_view_projection");
  52. // Calculate bias-tile matrices
  53. float4x4 bias_matrix = math::translate(math::matrix4<float>::identity(), float3{0.5f, 0.5f, 0.5f}) * math::scale(math::matrix4<float>::identity(), float3{0.5f, 0.5f, 0.5f});
  54. float4x4 tile_scale = math::scale(math::matrix4<float>::identity(), float3{0.5f, 0.5f, 1.0f});
  55. for (int i = 0; i < 4; ++i)
  56. {
  57. float x = static_cast<float>(i % 2) * 0.5f;
  58. float y = static_cast<float>(i / 2) * 0.5f;
  59. float4x4 tile_matrix = math::translate(math::matrix4<float>::identity(), float3{x, y, 0.0f}) * tile_scale;
  60. bias_tile_matrices[i] = tile_matrix * bias_matrix;
  61. }
  62. }
  63. shadow_map_pass::~shadow_map_pass()
  64. {}
  65. void shadow_map_pass::render(const render::context& ctx, render::queue& queue) const
  66. {
  67. // Collect lights
  68. const std::list<scene::object_base*>* lights = ctx.collection->get_objects(scene::light::object_type_id);
  69. for (const scene::object_base* object: *lights)
  70. {
  71. // Ignore inactive lights
  72. if (!object->is_active())
  73. continue;
  74. // Ignore non-directional lights
  75. const scene::light* light = static_cast<const scene::light*>(object);
  76. if (light->get_light_type() != scene::light_type::directional)
  77. continue;
  78. // Ignore non-shadow casters
  79. const scene::directional_light* directional_light = static_cast<const scene::directional_light*>(light);
  80. if (!directional_light->is_shadow_caster())
  81. continue;
  82. // Ignore improperly-configured lights
  83. if (!directional_light->get_shadow_cascade_count() || !directional_light->get_shadow_framebuffer())
  84. continue;
  85. // Render cascaded shadow maps for light
  86. render_csm(*directional_light, ctx, queue);
  87. }
  88. }
  89. void shadow_map_pass::render_csm(const scene::directional_light& light, const render::context& ctx, render::queue& queue) const
  90. {
  91. rasterizer->use_framebuffer(*light.get_shadow_framebuffer());
  92. // Disable blending
  93. glDisable(GL_BLEND);
  94. // Enable depth testing
  95. glEnable(GL_DEPTH_TEST);
  96. glDepthFunc(GL_LESS);
  97. glDepthMask(GL_TRUE);
  98. // Enable back-face culling
  99. glEnable(GL_CULL_FACE);
  100. glCullFace(GL_BACK);
  101. bool two_sided = false;
  102. // For half-z buffer
  103. glDepthRange(-1.0f, 1.0f);
  104. // Get camera
  105. const scene::camera& camera = *ctx.camera;
  106. // Get tweened camera parameters
  107. const float camera_fov = camera.get_fov_tween().interpolate(ctx.alpha);
  108. const float camera_aspect_ratio = camera.get_aspect_ratio_tween().interpolate(ctx.alpha);
  109. const float camera_clip_near = camera.get_clip_near_tween().interpolate(ctx.alpha);
  110. const float camera_clip_far = camera.get_clip_far_tween().interpolate(ctx.alpha);
  111. // Calculate distance to shadow cascade depth clipping planes
  112. const float shadow_clip_far = math::lerp(camera_clip_near, camera_clip_far, light.get_shadow_cascade_coverage());
  113. const unsigned int cascade_count = light.get_shadow_cascade_count();
  114. float* cascade_distances = light.get_shadow_cascade_distances();
  115. float4x4* cascade_matrices = light.get_shadow_cascade_matrices();
  116. // Calculate cascade far clipping plane distances
  117. cascade_distances[cascade_count - 1] = shadow_clip_far;
  118. for (unsigned int i = 0; i < cascade_count - 1; ++i)
  119. {
  120. const float weight = static_cast<float>(i + 1) / static_cast<float>(cascade_count);
  121. // Calculate linear and logarithmic distribution distances
  122. const float linear_distance = math::lerp(camera_clip_near, shadow_clip_far, weight);
  123. const float log_distance = math::log_lerp(camera_clip_near, shadow_clip_far, weight);
  124. // Interpolate between linear and logarithmic distribution distances
  125. cascade_distances[i] = math::lerp(linear_distance, log_distance, light.get_shadow_cascade_distribution());
  126. }
  127. // Calculate viewports for each shadow map
  128. const int shadow_map_resolution = static_cast<int>(light.get_shadow_framebuffer()->get_depth_attachment()->get_width());
  129. const int cascade_resolution = shadow_map_resolution / 2;
  130. int4 shadow_map_viewports[4];
  131. for (int i = 0; i < 4; ++i)
  132. {
  133. int x = i % 2;
  134. int y = i / 2;
  135. int4& viewport = shadow_map_viewports[i];
  136. viewport[0] = x * cascade_resolution;
  137. viewport[1] = y * cascade_resolution;
  138. viewport[2] = cascade_resolution;
  139. viewport[3] = cascade_resolution;
  140. }
  141. // Calculate a view-projection matrix from the directional light's transform
  142. math::transform<float> light_transform = light.get_transform_tween().interpolate(ctx.alpha);
  143. float3 forward = light_transform.rotation * config::global_forward;
  144. float3 up = light_transform.rotation * config::global_up;
  145. float4x4 light_view = math::look_at(light_transform.translation, light_transform.translation + forward, up);
  146. float4x4 light_projection = math::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
  147. float4x4 light_view_projection = light_projection * light_view;
  148. float4x4 cropped_view_projection;
  149. float4x4 model_view_projection;
  150. // Sort render queue
  151. queue.sort(operation_compare);
  152. gl::shader_program* active_shader_program = nullptr;
  153. for (unsigned int i = 0; i < cascade_count; ++i)
  154. {
  155. // Set viewport for this shadow map
  156. const int4& viewport = shadow_map_viewports[i];
  157. rasterizer->set_viewport(viewport[0], viewport[1], viewport[2], viewport[3]);
  158. // Calculate projection matrix for view camera subfrustum
  159. const float subfrustum_near = (i) ? cascade_distances[i - 1] : camera_clip_near;
  160. const float subfrustum_far = cascade_distances[i];
  161. float4x4 subfrustum_projection = math::perspective_half_z(camera_fov, camera_aspect_ratio, subfrustum_near, subfrustum_far);
  162. // Calculate view camera subfrustum
  163. geom::view_frustum<float> subfrustum(subfrustum_projection * ctx.view);
  164. // Create AABB containing the view camera subfrustum corners
  165. const std::array<float3, 8>& subfrustum_corners = subfrustum.get_corners();
  166. geom::aabb<float> subfrustum_aabb = {subfrustum_corners[0], subfrustum_corners[0]};
  167. for (int j = 1; j < 8; ++j)
  168. {
  169. subfrustum_aabb.min_point = math::min(subfrustum_aabb.min_point, subfrustum_corners[j]);
  170. subfrustum_aabb.max_point = math::max(subfrustum_aabb.max_point, subfrustum_corners[j]);
  171. }
  172. // Transform subfrustum AABB into the light clip-space
  173. geom::aabb<float> cropping_bounds = geom::aabb<float>::transform(subfrustum_aabb, light_view_projection);
  174. // Quantize clip-space coordinates
  175. const float texel_scale_x = (cropping_bounds.max_point.x() - cropping_bounds.min_point.x()) / static_cast<float>(cascade_resolution);
  176. const float texel_scale_y = (cropping_bounds.max_point.y() - cropping_bounds.min_point.y()) / static_cast<float>(cascade_resolution);
  177. cropping_bounds.min_point.x() = std::floor(cropping_bounds.min_point.x() / texel_scale_x) * texel_scale_x;
  178. cropping_bounds.max_point.x() = std::floor(cropping_bounds.max_point.x() / texel_scale_x) * texel_scale_x;
  179. cropping_bounds.min_point.y() = std::floor(cropping_bounds.min_point.y() / texel_scale_y) * texel_scale_y;
  180. cropping_bounds.max_point.y() = std::floor(cropping_bounds.max_point.y() / texel_scale_y) * texel_scale_y;
  181. // Recalculate light projection matrix with quantized coordinates
  182. light_projection = math::ortho_half_z
  183. (
  184. cropping_bounds.min_point.x(), cropping_bounds.max_point.x(),
  185. cropping_bounds.min_point.y(), cropping_bounds.max_point.y(),
  186. cropping_bounds.min_point.z(), cropping_bounds.max_point.z()
  187. );
  188. // Calculate cropped view projection matrix
  189. cropped_view_projection = light_projection * light_view;
  190. // Calculate world-space to cascade texture-space transformation matrix
  191. cascade_matrices[i] = bias_tile_matrices[i] * cropped_view_projection;
  192. for (const render::operation& operation: queue)
  193. {
  194. const render::material* material = operation.material;
  195. if (material)
  196. {
  197. // Skip materials which don't cast shadows
  198. if (material->get_shadow_mode() == shadow_mode::none)
  199. continue;
  200. if (material->is_two_sided() != two_sided)
  201. {
  202. if (material->is_two_sided())
  203. {
  204. glDisable(GL_CULL_FACE);
  205. }
  206. else
  207. {
  208. glEnable(GL_CULL_FACE);
  209. }
  210. two_sided = material->is_two_sided();
  211. }
  212. }
  213. // Switch shader programs if necessary
  214. gl::shader_program* shader_program = (operation.bone_count) ? skinned_shader_program : unskinned_shader_program;
  215. if (active_shader_program != shader_program)
  216. {
  217. active_shader_program = shader_program;
  218. rasterizer->use_program(*active_shader_program);
  219. }
  220. // Calculate model-view-projection matrix
  221. model_view_projection = cropped_view_projection * operation.transform;
  222. // Upload operation-dependent parameters to shader program
  223. if (active_shader_program == unskinned_shader_program)
  224. {
  225. unskinned_model_view_projection_input->upload(model_view_projection);
  226. }
  227. else if (active_shader_program == skinned_shader_program)
  228. {
  229. skinned_model_view_projection_input->upload(model_view_projection);
  230. }
  231. // Draw geometry
  232. rasterizer->draw_arrays(*operation.vertex_array, operation.drawing_mode, operation.start_index, operation.index_count);
  233. }
  234. }
  235. }
  236. bool operation_compare(const render::operation& a, const render::operation& b)
  237. {
  238. const bool skinned_a = (a.bone_count);
  239. const bool skinned_b = (b.bone_count);
  240. const bool two_sided_a = (a.material) ? a.material->is_two_sided() : false;
  241. const bool two_sided_b = (b.material) ? b.material->is_two_sided() : false;
  242. if (skinned_a)
  243. {
  244. if (skinned_b)
  245. {
  246. // A and B are both skinned, sort by two-sided
  247. if (two_sided_a)
  248. {
  249. if (two_sided_b)
  250. {
  251. // A and B are both two-sided, sort by VAO
  252. return (a.vertex_array < b.vertex_array);
  253. }
  254. else
  255. {
  256. // A is two-sided, B is one-sided. Render B first
  257. return false;
  258. }
  259. }
  260. else
  261. {
  262. if (two_sided_b)
  263. {
  264. // A is one-sided, B is two-sided. Render A first
  265. return true;
  266. }
  267. else
  268. {
  269. // A and B are both one-sided, sort by VAO
  270. return (a.vertex_array < b.vertex_array);
  271. }
  272. }
  273. }
  274. else
  275. {
  276. // A is skinned, B is unskinned. Render B first
  277. return false;
  278. }
  279. }
  280. else
  281. {
  282. if (skinned_b)
  283. {
  284. // A is unskinned, B is skinned. Render A first
  285. return true;
  286. }
  287. else
  288. {
  289. // A and B are both unskinned, sort by two-sided
  290. if (two_sided_a)
  291. {
  292. if (two_sided_b)
  293. {
  294. // A and B are both two-sided, sort by VAO
  295. return (a.vertex_array < b.vertex_array);
  296. }
  297. else
  298. {
  299. // A is two-sided, B is one-sided. Render B first
  300. return false;
  301. }
  302. }
  303. else
  304. {
  305. if (two_sided_b)
  306. {
  307. // A is one-sided, B is two-sided. Render A first
  308. return true;
  309. }
  310. else
  311. {
  312. // A and B are both one-sided, sort by VAO
  313. return (a.vertex_array < b.vertex_array);
  314. }
  315. }
  316. }
  317. }
  318. }
  319. } // namespace render