💿🐜 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.

396 lines
13 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 <engine/render/passes/shadow-map-pass.hpp>
  20. #include <engine/resources/resource-manager.hpp>
  21. #include <engine/gl/rasterizer.hpp>
  22. #include <engine/gl/framebuffer.hpp>
  23. #include <engine/gl/shader-program.hpp>
  24. #include <engine/gl/drawing-mode.hpp>
  25. #include <engine/render/context.hpp>
  26. #include <engine/render/material.hpp>
  27. #include <engine/render/vertex-attribute.hpp>
  28. #include <engine/gl/shader-template.hpp>
  29. #include <engine/scene/camera.hpp>
  30. #include <engine/scene/collection.hpp>
  31. #include <engine/scene/light.hpp>
  32. #include <engine/geom/primitives/view-frustum.hpp>
  33. #include <engine/math/interpolation.hpp>
  34. #include <engine/math/vector.hpp>
  35. #include <engine/math/matrix.hpp>
  36. #include <engine/math/quaternion.hpp>
  37. #include <engine/math/projection.hpp>
  38. #include <cmath>
  39. #include <glad/glad.h>
  40. #include <execution>
  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. std::unordered_map<std::string, std::string> definitions;
  47. definitions["VERTEX_POSITION"] = std::to_string(vertex_attribute::position);
  48. definitions["VERTEX_UV"] = std::to_string(vertex_attribute::uv);
  49. definitions["VERTEX_NORMAL"] = std::to_string(vertex_attribute::normal);
  50. definitions["VERTEX_TANGENT"] = std::to_string(vertex_attribute::tangent);
  51. definitions["VERTEX_COLOR"] = std::to_string(vertex_attribute::color);
  52. definitions["VERTEX_BONE_INDEX"] = std::to_string(vertex_attribute::bone_index);
  53. definitions["VERTEX_BONE_WEIGHT"] = std::to_string(vertex_attribute::bone_weight);
  54. definitions["VERTEX_BONE_WEIGHT"] = std::to_string(vertex_attribute::bone_weight);
  55. definitions["MAX_BONE_COUNT"] = std::to_string(64);
  56. // Load unskinned shader template
  57. auto unskinned_shader_template = resource_manager->load<gl::shader_template>("depth-unskinned.glsl");
  58. // Build unskinned shader program
  59. unskinned_shader_program = unskinned_shader_template->build(definitions);
  60. if (!unskinned_shader_program->linked())
  61. {
  62. debug::log::error("Failed to build unskinned shadow map shader program: {}", unskinned_shader_program->info());
  63. debug::log::warning("{}", unskinned_shader_template->configure(gl::shader_stage::vertex));
  64. }
  65. unskinned_model_view_projection_var = unskinned_shader_program->variable("model_view_projection");
  66. // Load skinned shader template
  67. auto skinned_shader_template = resource_manager->load<gl::shader_template>("depth-skinned.glsl");
  68. // Build skinned shader program
  69. skinned_shader_program = skinned_shader_template->build(definitions);
  70. if (!skinned_shader_program->linked())
  71. {
  72. debug::log::error("Failed to build skinned shadow map shader program: {}", skinned_shader_program->info());
  73. debug::log::warning("{}", skinned_shader_template->configure(gl::shader_stage::vertex));
  74. }
  75. skinned_model_view_projection_var = skinned_shader_program->variable("model_view_projection");
  76. skinned_matrix_palette_var = skinned_shader_program->variable("matrix_palette");
  77. }
  78. void shadow_map_pass::render(render::context& ctx)
  79. {
  80. // For each light
  81. const auto& lights = ctx.collection->get_objects(scene::light::object_type_id);
  82. for (scene::object_base* object: lights)
  83. {
  84. // Ignore non-directional lights
  85. auto& light = static_cast<scene::light&>(*object);
  86. if (light.get_light_type() != scene::light_type::directional)
  87. {
  88. continue;
  89. }
  90. // Ignore non-shadow casters
  91. auto& directional_light = static_cast<scene::directional_light&>(light);
  92. if (!directional_light.is_shadow_caster())
  93. {
  94. continue;
  95. }
  96. // Ignore improperly-configured lights
  97. if (!directional_light.get_shadow_framebuffer() || !directional_light.get_shadow_cascade_count())
  98. {
  99. continue;
  100. }
  101. // Render cascaded shadow maps
  102. render_csm(directional_light, ctx);
  103. }
  104. }
  105. void shadow_map_pass::render_csm(scene::directional_light& light, render::context& ctx)
  106. {
  107. // Get light layer mask
  108. const auto light_layer_mask = light.get_layer_mask();
  109. if (!light_layer_mask & ctx.camera->get_layer_mask())
  110. {
  111. return;
  112. }
  113. rasterizer->use_framebuffer(*light.get_shadow_framebuffer());
  114. // Disable blending
  115. glDisable(GL_BLEND);
  116. // Enable depth testing
  117. glEnable(GL_DEPTH_TEST);
  118. glDepthFunc(GL_GREATER);
  119. glDepthMask(GL_TRUE);
  120. // Enable back-face culling
  121. glEnable(GL_CULL_FACE);
  122. glCullFace(GL_BACK);
  123. bool two_sided = false;
  124. // For half-z buffer
  125. glDepthRange(-1.0f, 1.0f);
  126. // Get camera
  127. const scene::camera& camera = *ctx.camera;
  128. // Calculate distance to shadow cascade depth clipping planes
  129. const float shadow_clip_far = math::lerp(camera.get_clip_near(), camera.get_clip_far(), light.get_shadow_cascade_coverage());
  130. // Get light shadow cascade distances and matrices
  131. const auto cascade_count = light.get_shadow_cascade_count();
  132. const auto cascade_distances = light.get_shadow_cascade_distances();
  133. const auto cascade_matrices = light.get_shadow_cascade_matrices();
  134. // Calculate cascade far clipping plane distances
  135. cascade_distances[cascade_count - 1] = shadow_clip_far;
  136. for (unsigned int i = 0; i < cascade_count - 1; ++i)
  137. {
  138. const float weight = static_cast<float>(i + 1) / static_cast<float>(cascade_count);
  139. // Calculate linear and logarithmic distribution distances
  140. const float linear_distance = math::lerp(camera.get_clip_near(), shadow_clip_far, weight);
  141. const float log_distance = math::log_lerp(camera.get_clip_near(), shadow_clip_far, weight);
  142. // Interpolate between linear and logarithmic distribution distances
  143. cascade_distances[i] = math::lerp(linear_distance, log_distance, light.get_shadow_cascade_distribution());
  144. }
  145. // Calculate viewports for each shadow map
  146. const int shadow_map_resolution = static_cast<int>(light.get_shadow_framebuffer()->get_depth_attachment()->get_width());
  147. const int cascade_resolution = shadow_map_resolution >> 1;
  148. math::ivec4 shadow_map_viewports[4];
  149. for (int i = 0; i < 4; ++i)
  150. {
  151. int x = i % 2;
  152. int y = i / 2;
  153. math::ivec4& viewport = shadow_map_viewports[i];
  154. viewport[0] = x * cascade_resolution;
  155. viewport[1] = y * cascade_resolution;
  156. viewport[2] = cascade_resolution;
  157. viewport[3] = cascade_resolution;
  158. }
  159. // Sort render operations
  160. std::sort(std::execution::par_unseq, ctx.operations.begin(), ctx.operations.end(), operation_compare);
  161. gl::shader_program* active_shader_program = nullptr;
  162. // Precalculate frustum minimal bounding sphere terms
  163. const auto k = std::sqrt(1.0f + camera.get_aspect_ratio() * camera.get_aspect_ratio()) * std::tan(camera.get_vertical_fov() * 0.5f);
  164. const auto k2 = k * k;
  165. const auto k4 = k2 * k2;
  166. for (unsigned int i = 0; i < cascade_count; ++i)
  167. {
  168. // Set viewport for this shadow map
  169. const math::ivec4& viewport = shadow_map_viewports[i];
  170. rasterizer->set_viewport(viewport[0], viewport[1], viewport[2], viewport[3]);
  171. // Find minimal bounding sphere of subfrustum in view-space
  172. // @see https://lxjk.github.io/2017/04/15/Calculate-Minimal-Bounding-Sphere-of-Frustum.html
  173. geom::sphere<float> subfrustum_bounds;
  174. {
  175. // Get subfrustum near and far distances
  176. const auto n = (i) ? cascade_distances[i - 1] : camera.get_clip_near();
  177. const auto f = cascade_distances[i];
  178. if (k2 >= (f - n) / (f + n))
  179. {
  180. subfrustum_bounds.center = {0, 0, -f};
  181. subfrustum_bounds.radius = f * k;
  182. }
  183. else
  184. {
  185. subfrustum_bounds.center = {0, 0, -0.5f * (f + n) * (1.0f + k2)};
  186. subfrustum_bounds.radius = 0.5f * std::sqrt((k4 + 2.0f * k2 + 1.0f) * (f * f + n * n) + 2.0f * f * (k4 - 1.0f) * n);
  187. }
  188. }
  189. // Transform subfrustum bounds into world-space
  190. subfrustum_bounds.center = camera.get_translation() + camera.get_rotation() * subfrustum_bounds.center;
  191. // Discretize view-space subfrustum bounds
  192. const auto texel_scale = static_cast<float>(cascade_resolution) / (subfrustum_bounds.radius * 2.0f);
  193. subfrustum_bounds.center = math::conjugate(light.get_rotation()) * subfrustum_bounds.center;
  194. subfrustum_bounds.center = math::floor(subfrustum_bounds.center * texel_scale) / texel_scale;
  195. subfrustum_bounds.center = light.get_rotation() * subfrustum_bounds.center;
  196. // Construct light view matrix
  197. const auto light_view = math::look_at(subfrustum_bounds.center, subfrustum_bounds.center + light.get_direction(), light.get_rotation() * math::fvec3{0, 1, 0});
  198. // Construct light projection matrix (reversed half-z)
  199. const auto light_projection = math::ortho_half_z
  200. (
  201. -subfrustum_bounds.radius, subfrustum_bounds.radius,
  202. -subfrustum_bounds.radius, subfrustum_bounds.radius,
  203. subfrustum_bounds.radius, -subfrustum_bounds.radius
  204. );
  205. // Construct light view-projection matrix
  206. const auto light_view_projection = light_projection * light_view;
  207. // Update world-space to cascade texture-space transformation matrix
  208. cascade_matrices[i] = light.get_shadow_bias_scale_matrices()[i] * light_view_projection;
  209. for (const render::operation* operation: ctx.operations)
  210. {
  211. // Skip operations which don't share any layers with the shadow-casting light
  212. if (!(operation->layer_mask & light_layer_mask))
  213. {
  214. continue;
  215. }
  216. const render::material* material = operation->material.get();
  217. if (material)
  218. {
  219. // Skip materials which don't cast shadows
  220. if (material->get_shadow_mode() == material_shadow_mode::none)
  221. {
  222. continue;
  223. }
  224. if (material->is_two_sided() != two_sided)
  225. {
  226. if (material->is_two_sided())
  227. {
  228. glDisable(GL_CULL_FACE);
  229. }
  230. else
  231. {
  232. glEnable(GL_CULL_FACE);
  233. }
  234. two_sided = material->is_two_sided();
  235. }
  236. }
  237. // Switch shader programs if necessary
  238. gl::shader_program* shader_program = (operation->matrix_palette.empty()) ? unskinned_shader_program.get() : skinned_shader_program.get();
  239. if (active_shader_program != shader_program)
  240. {
  241. active_shader_program = shader_program;
  242. rasterizer->use_program(*active_shader_program);
  243. }
  244. // Calculate model-view-projection matrix
  245. math::fmat4 model_view_projection = light_view_projection * operation->transform;
  246. // Upload operation-dependent parameters to shader program
  247. if (active_shader_program == unskinned_shader_program.get())
  248. {
  249. unskinned_model_view_projection_var->update(model_view_projection);
  250. }
  251. else if (active_shader_program == skinned_shader_program.get())
  252. {
  253. skinned_model_view_projection_var->update(model_view_projection);
  254. skinned_matrix_palette_var->update(operation->matrix_palette);
  255. }
  256. // Draw geometry
  257. rasterizer->draw_arrays(*operation->vertex_array, operation->drawing_mode, operation->start_index, operation->index_count);
  258. }
  259. }
  260. }
  261. bool operation_compare(const render::operation* a, const render::operation* b)
  262. {
  263. const bool skinned_a = !a->matrix_palette.empty();
  264. const bool skinned_b = !b->matrix_palette.empty();
  265. const bool two_sided_a = (a->material) ? a->material->is_two_sided() : false;
  266. const bool two_sided_b = (b->material) ? b->material->is_two_sided() : false;
  267. if (skinned_a)
  268. {
  269. if (skinned_b)
  270. {
  271. // A and B are both skinned, sort by two-sided
  272. if (two_sided_a)
  273. {
  274. if (two_sided_b)
  275. {
  276. // A and B are both two-sided, sort by VAO
  277. return (a->vertex_array < b->vertex_array);
  278. }
  279. else
  280. {
  281. // A is two-sided, B is one-sided. Render B first
  282. return false;
  283. }
  284. }
  285. else
  286. {
  287. if (two_sided_b)
  288. {
  289. // A is one-sided, B is two-sided. Render A first
  290. return true;
  291. }
  292. else
  293. {
  294. // A and B are both one-sided, sort by VAO
  295. return (a->vertex_array < b->vertex_array);
  296. }
  297. }
  298. }
  299. else
  300. {
  301. // A is skinned, B is unskinned. Render B first
  302. return false;
  303. }
  304. }
  305. else
  306. {
  307. if (skinned_b)
  308. {
  309. // A is unskinned, B is skinned. Render A first
  310. return true;
  311. }
  312. else
  313. {
  314. // A and B are both unskinned, sort by two-sided
  315. if (two_sided_a)
  316. {
  317. if (two_sided_b)
  318. {
  319. // A and B are both two-sided, sort by VAO
  320. return (a->vertex_array < b->vertex_array);
  321. }
  322. else
  323. {
  324. // A is two-sided, B is one-sided. Render B first
  325. return false;
  326. }
  327. }
  328. else
  329. {
  330. if (two_sided_b)
  331. {
  332. // A is one-sided, B is two-sided. Render A first
  333. return true;
  334. }
  335. else
  336. {
  337. // A and B are both one-sided, sort by VAO
  338. return (a->vertex_array < b->vertex_array);
  339. }
  340. }
  341. }
  342. }
  343. }
  344. } // namespace render