Antkeeper  0.0.1
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
cascaded-shadow-map-stage.cpp
Go to the documentation of this file.
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 
22 #include <engine/gl/pipeline.hpp>
28 #include <engine/scene/camera.hpp>
30 #include <engine/scene/light.hpp>
33 #include <engine/math/vector.hpp>
34 #include <engine/math/matrix.hpp>
38 #include <cmath>
39 #include <algorithm>
40 #include <execution>
41 #include <mutex>
42 
43 namespace render {
44 
45 static bool operation_compare(const render::operation* a, const render::operation* b);
46 
48  m_pipeline(&pipeline)
49 {
50  // Init shader template definitions
51  m_shader_template_definitions["VERTEX_POSITION"] = std::to_string(vertex_attribute_location::position);
52  m_shader_template_definitions["VERTEX_UV"] = std::to_string(vertex_attribute_location::uv);
53  m_shader_template_definitions["VERTEX_NORMAL"] = std::to_string(vertex_attribute_location::normal);
54  m_shader_template_definitions["VERTEX_TANGENT"] = std::to_string(vertex_attribute_location::tangent);
55  m_shader_template_definitions["VERTEX_COLOR"] = std::to_string(vertex_attribute_location::color);
56  m_shader_template_definitions["VERTEX_BONE_INDEX"] = std::to_string(vertex_attribute_location::bone_index);
57  m_shader_template_definitions["VERTEX_BONE_WEIGHT"] = std::to_string(vertex_attribute_location::bone_weight);
58  m_shader_template_definitions["VERTEX_BONE_WEIGHT"] = std::to_string(vertex_attribute_location::bone_weight);
59  m_shader_template_definitions["MAX_BONE_COUNT"] = std::to_string(m_max_bone_count);
60 
61  // Static mesh shader
62  {
63  // Load static mesh shader template
64  m_static_mesh_shader_template = resource_manager.load<gl::shader_template>("shadow-cascade-static-mesh.glsl");
65 
66  // Build static mesh shader program
67  rebuild_static_mesh_shader_program();
68  }
69 
70  // Skeletal mesh shader
71  {
72  // Load skeletal mesh shader template
73  m_skeletal_mesh_shader_template = resource_manager.load<gl::shader_template>("shadow-cascade-skeletal-mesh.glsl");
74 
75  // Build static mesh shader program
76  rebuild_skeletal_mesh_shader_program();
77  }
78 }
79 
81 {
82  // For each light
83  const auto& lights = ctx.collection->get_objects(scene::light::object_type_id);
84  for (scene::object_base* object: lights)
85  {
86  // Ignore non-directional lights
87  auto& light = static_cast<scene::light&>(*object);
88  if (light.get_light_type() != scene::light_type::directional)
89  {
90  continue;
91  }
92 
93  // Ignore non-shadow casters
94  auto& directional_light = static_cast<scene::directional_light&>(light);
95  if (!directional_light.is_shadow_caster())
96  {
97  continue;
98  }
99 
100  // Ignore lights that don't share a common layer with the camera
101  if (!(directional_light.get_layer_mask() & ctx.camera->get_layer_mask()))
102  {
103  return;
104  }
105 
106  // Ignore improperly-configured lights
107  if (!directional_light.get_shadow_framebuffer())
108  {
109  continue;
110  }
111 
112  // Render shadow atlas
113  render_shadow_atlas(ctx, directional_light);
114  }
115 
116  ctx.operations.clear();
117 }
118 
120 {
121  if (m_max_bone_count != bone_count)
122  {
123  m_max_bone_count = bone_count;
124 
125  // Update max bone count shader template definition
126  m_shader_template_definitions["MAX_BONE_COUNT"] = std::to_string(m_max_bone_count);
127 
128  // Rebuild skeletal mesh shader
129  rebuild_skeletal_mesh_shader_program();
130  }
131 }
132 
133 void cascaded_shadow_map_stage::queue(render::context& ctx, scene::directional_light& light, const math::fmat4& light_view_projection)
134 {
135  // Clear pre-existing render operations
136  ctx.operations.clear();
137 
138  // Combine camera and light layer masks
139  const auto camera_light_layer_mask = ctx.camera->get_layer_mask() & light.get_layer_mask();
140 
141  // Build light view frustum from light view projection matrix
142  const geom::view_frustum<float> light_view_frustum(light_view_projection);
143 
144  // Tests whether a box is completely outside a plane
145  auto box_outside_plane = [](const geom::box<float>& box, const geom::plane<float>& plane) -> bool
146  {
147  const math::fvec3 p =
148  {
149  (plane.normal.x() > 0.0f) ? box.max.x() : box.min.x(),
150  (plane.normal.y() > 0.0f) ? box.max.y() : box.min.y(),
151  (plane.normal.z() > 0.0f) ? box.max.z() : box.min.z()
152  };
153 
154  return plane.distance(p) < 0.0f;
155  };
156 
157  // For each object in the scene collection
158  const auto& objects = ctx.collection->get_objects();
159  std::for_each
160  (
161  std::execution::seq,
162  std::begin(objects),
163  std::end(objects),
164  [&](scene::object_base* object)
165  {
166  // Cull object if it doesn't share a common layer with the camera and light
167  if (!(object->get_layer_mask() & camera_light_layer_mask))
168  {
169  return;
170  }
171 
172  // Ignore cameras and lights
174  {
175  return;
176  }
177 
178  // Cull object if it's outside of the light view frustum (excluding near plane [reverse-z, so far=near])
179  const auto& object_bounds = object->get_bounds();
180  if (box_outside_plane(object_bounds, light_view_frustum.left()) ||
181  box_outside_plane(object_bounds, light_view_frustum.right()) ||
182  box_outside_plane(object_bounds, light_view_frustum.bottom()) ||
183  box_outside_plane(object_bounds, light_view_frustum.top()) ||
184  box_outside_plane(object_bounds, light_view_frustum.near()))
185  {
186  return;
187  }
188 
189  // Add object render operations to render context
190  object->render(ctx);
191  }
192  );
193 }
194 
195 void cascaded_shadow_map_stage::render_shadow_atlas(render::context& ctx, scene::directional_light& light)
196 {
197  // Disable blending
198  m_pipeline->set_color_blend_enabled(false);
199 
200  // Enable depth testing
201  m_pipeline->set_depth_test_enabled(true);
202  m_pipeline->set_depth_write_enabled(true);
204 
205  // Enable depth clamping ("pancaking")
206  m_pipeline->set_depth_clamp_enabled(true);
207 
208  // Enable back-face culling
209  m_pipeline->set_cull_mode(gl::cull_mode::back);
210  bool two_sided = false;
211 
212  // Bind and clear shadow atlas framebuffer
213  m_pipeline->bind_framebuffer(light.get_shadow_framebuffer().get());
214  m_pipeline->clear_attachments(gl::depth_clear_bit, {});
215 
216  // Get camera
217  const scene::camera& camera = *ctx.camera;
218 
219  // Get light shadow cascade distances and matrices
220  const auto cascade_count = light.get_shadow_cascade_count();
221  auto& cascade_distances = light.get_shadow_cascade_distances();
222  const auto cascade_matrices = light.get_shadow_cascade_matrices();
223 
224  // Calculate cascade far clipping plane distances
225  cascade_distances[cascade_count - 1] = light.get_shadow_max_distance();
226  for (unsigned int i = 0; i < cascade_count - 1; ++i)
227  {
228  const float weight = static_cast<float>(i + 1) / static_cast<float>(cascade_count);
229 
230  // Calculate linear and logarithmic split distances
231  const float linear_distance = math::lerp(camera.get_clip_near(), camera.get_clip_near() + light.get_shadow_max_distance(), weight);
232  const float log_distance = math::log_lerp(camera.get_clip_near(), camera.get_clip_near() + light.get_shadow_max_distance(), weight);
233 
234  // Interpolate between linear and logarithmic split distances
235  cascade_distances[i] = math::lerp(linear_distance, log_distance, light.get_shadow_cascade_distribution());
236  }
237 
238  // Determine resolution of shadow atlas and cascades
239  const auto atlas_resolution = static_cast<int>(light.get_shadow_framebuffer()->width());
240  const auto cascade_resolution = atlas_resolution >> 1;
241 
242  // Sort render operations
243  std::sort(std::execution::par_unseq, ctx.operations.begin(), ctx.operations.end(), operation_compare);
244 
245  gl::shader_program* active_shader_program = nullptr;
246 
247  for (unsigned int i = 0; i < cascade_count; ++i)
248  {
249  // Get distances to near and far clipping planes of camera subfrustum
250  const auto subfrustum_near = i ? cascade_distances[i - 1] : camera.get_clip_near();
251  const auto subfrustum_far = cascade_distances[i];
252 
253  // Find centroid of camera subfrustum
254  const auto subfrustum_centroid = camera.get_translation() + camera.get_forward() * ((subfrustum_near + subfrustum_far) * 0.5f);
255 
256  // Construct light view matrix
257  const auto light_view = math::look_at_rh(subfrustum_centroid, subfrustum_centroid + light.get_direction(), light.get_rotation() * math::fvec3{0, 1, 0});
258 
259  // Construct subfrustum inverse view-projection matrix
260  const auto [subfrustum_projection, subfrustum_inv_projection] = math::perspective_half_z_inv(camera.get_vertical_fov(), camera.get_aspect_ratio(), subfrustum_far, subfrustum_near);
261  const auto subfrustum_inv_view_projection = camera.get_inv_view() * subfrustum_inv_projection;
262 
263  // Construct matrix which transforms clip space coordinates to light view space
264  const auto ndc_to_light_view = light_view * subfrustum_inv_view_projection;
265 
266  // Construct AABB containing subfrustum corners in light view space
267  geom::box<float> light_projection_bounds = {math::fvec3::infinity(), -math::fvec3::infinity()};
268  for (std::size_t j = 0; j < 8; ++j)
269  {
270  // Reverse half z clip-space coordinates of a cube
271  constexpr math::fvec4 ndc_cube[8] =
272  {
273  {-1, -1, 1, 1}, // NBL
274  { 1, -1, 1, 1}, // NBR
275  {-1, 1, 1, 1}, // NTL
276  { 1, 1, 1, 1}, // NTR
277  {-1, -1, 0, 1}, // FBL
278  { 1, -1, 0, 1}, // FBR
279  {-1, 1, 0, 1}, // FTL
280  { 1, 1, 0, 1} // FTR
281  };
282 
283  // Find light view space coordinates of subfrustum corner
284  const auto corner = ndc_to_light_view * ndc_cube[j];
285 
286  // Expand light projection bounds to contain corner
287  light_projection_bounds.extend(math::fvec3(corner) / corner[3]);
288  }
289 
290  // Construct light projection matrix
291  const auto light_projection = math::ortho_half_z
292  (
293  light_projection_bounds.min.x(), light_projection_bounds.max.x(),
294  light_projection_bounds.min.y(), light_projection_bounds.max.y(),
295  -light_projection_bounds.min.z(), -light_projection_bounds.max.z()
296  );
297 
298  // Construct light view-projection matrix
299  const auto light_view_projection = light_projection * light_view;
300  const auto light_view_translation = math::fvec4(subfrustum_centroid);
301  const auto light_view_rotation = math::fmat4(math::fmat3(light_view));
302 
303  // Update view-space to cascade texture-space transformation matrix
304  {
305  const auto vs_subfrustum_centroid = math::fvec3{0.0f, 0.0f, ((subfrustum_near + subfrustum_far) * -0.5f)};
306  const auto vs_light_direction = light.get_direction() * camera.get_rotation();
307  const auto vs_light_up = (light.get_rotation() * math::fvec3{0, 1, 0}) * camera.get_rotation();
308 
309  const auto vs_light_view = math::look_at_rh(vs_subfrustum_centroid, vs_subfrustum_centroid + vs_light_direction, vs_light_up);
310  const auto vs_light_view_projection = light_projection * vs_light_view;
311 
312  cascade_matrices[i] = light.get_shadow_scale_bias_matrices()[i] * vs_light_view_projection;
313  }
314 
315  // Queue render operations
316  queue(ctx, light, light_view_projection);
317  if (ctx.operations.empty())
318  {
319  continue;
320  }
321 
322  // Set viewport for this cascade
323  const gl::viewport viewport[1] =
324  {{
325  static_cast<float>(static_cast<int>(i % 2) * cascade_resolution),
326  static_cast<float>(static_cast<int>(i >> 1) * cascade_resolution),
327  static_cast<float>(cascade_resolution),
328  static_cast<float>(cascade_resolution)
329  }};
330  m_pipeline->set_viewport(0, viewport);
331 
332  // Render geometry
333  for (const render::operation* operation: ctx.operations)
334  {
335  const render::material* material = operation->material.get();
336  if (material)
337  {
338  // Skip materials which don't cast shadows
339  if (material->get_shadow_mode() == material_shadow_mode::none)
340  {
341  continue;
342  }
343 
344  if (material->is_two_sided() != two_sided)
345  {
346  if (material->is_two_sided())
347  {
348  m_pipeline->set_cull_mode(gl::cull_mode::none);
349  }
350  else
351  {
352  m_pipeline->set_cull_mode(gl::cull_mode::back);
353  }
354 
355  two_sided = material->is_two_sided();
356  }
357  }
358 
359  // Switch shader programs if necessary
360  gl::shader_program* shader_program = (operation->matrix_palette.empty()) ? m_static_mesh_shader_program.get() : m_skeletal_mesh_shader_program.get();
361  if (active_shader_program != shader_program)
362  {
363  active_shader_program = shader_program;
364  m_pipeline->bind_shader_program(active_shader_program);
365  }
366 
367  // Calculate model-view-projection matrix
368  // @see Persson, E., & Studios, A. (2012). Creating vast game worlds: Experiences from avalanche studios. In ACM SIGGRAPH 2012 Talks (pp. 1-1).
369  auto model_view = operation->transform;
370  model_view[3] -= light_view_translation;
371  model_view = light_view_rotation * model_view;
372  const auto model_view_projection = light_projection * model_view;
373 
374  // Upload operation-dependent parameters to shader program
375  if (active_shader_program == m_static_mesh_shader_program.get())
376  {
377  m_static_mesh_model_view_projection_var->update(model_view_projection);
378  }
379  else if (active_shader_program == m_skeletal_mesh_shader_program.get())
380  {
381  m_skeletal_mesh_model_view_projection_var->update(model_view_projection);
382  m_skeletal_mesh_matrix_palette_var->update(operation->matrix_palette);
383  }
384 
385  // Draw geometry
386  m_pipeline->set_primitive_topology(operation->primitive_topology);
387  m_pipeline->bind_vertex_array(operation->vertex_array);
388  m_pipeline->bind_vertex_buffers(0, {&operation->vertex_buffer, 1}, {&operation->vertex_offset, 1}, {&operation->vertex_stride, 1});
389  m_pipeline->draw(operation->vertex_count, 1, 0, 0);
390  }
391  }
392 
393  // Disable depth clamping ("pancaking")
394  m_pipeline->set_depth_clamp_enabled(false);
395 }
396 
397 void cascaded_shadow_map_stage::rebuild_static_mesh_shader_program()
398 {
399  m_static_mesh_shader_program = m_static_mesh_shader_template->build(m_shader_template_definitions);
400  if (!m_static_mesh_shader_program->linked())
401  {
402  debug::log_error("Failed to build cascaded shadow map shader program for static meshes: {}", m_static_mesh_shader_program->info());
403  debug::log_warning("{}", m_static_mesh_shader_template->configure(gl::shader_stage::vertex));
404 
405  m_static_mesh_model_view_projection_var = nullptr;
406  }
407  else
408  {
409  m_static_mesh_model_view_projection_var = m_static_mesh_shader_program->variable("model_view_projection");
410  }
411 }
412 
413 void cascaded_shadow_map_stage::rebuild_skeletal_mesh_shader_program()
414 {
415  m_skeletal_mesh_shader_program = m_skeletal_mesh_shader_template->build(m_shader_template_definitions);
416  if (!m_skeletal_mesh_shader_program->linked())
417  {
418  debug::log_error("Failed to build cascaded shadow map shader program for skeletal meshes: {}", m_skeletal_mesh_shader_program->info());
419  debug::log_warning("{}", m_skeletal_mesh_shader_template->configure(gl::shader_stage::vertex));
420 
421  m_skeletal_mesh_model_view_projection_var = nullptr;
422  m_skeletal_mesh_matrix_palette_var = nullptr;
423  }
424  else
425  {
426  m_skeletal_mesh_model_view_projection_var = m_skeletal_mesh_shader_program->variable("model_view_projection");
427  m_skeletal_mesh_matrix_palette_var = m_skeletal_mesh_shader_program->variable("matrix_palette");
428  }
429 }
430 
431 bool operation_compare(const render::operation* a, const render::operation* b)
432 {
433  const bool skinned_a = !a->matrix_palette.empty();
434  const bool skinned_b = !b->matrix_palette.empty();
435  const bool two_sided_a = (a->material) ? a->material->is_two_sided() : false;
436  const bool two_sided_b = (b->material) ? b->material->is_two_sided() : false;
437 
438  if (skinned_a)
439  {
440  if (skinned_b)
441  {
442  // A and B are both skinned, sort by two-sided
443  if (two_sided_a)
444  {
445  if (two_sided_b)
446  {
447  // A and B are both two-sided, sort by VAO
448  return (a->vertex_array < b->vertex_array);
449  }
450  else
451  {
452  // A is two-sided, B is one-sided. Render B first
453  return false;
454  }
455  }
456  else
457  {
458  if (two_sided_b)
459  {
460  // A is one-sided, B is two-sided. Render A first
461  return true;
462  }
463  else
464  {
465  // A and B are both one-sided, sort by VAO
466  return (a->vertex_array < b->vertex_array);
467  }
468  }
469  }
470  else
471  {
472  // A is skinned, B is unskinned. Render B first
473  return false;
474  }
475  }
476  else
477  {
478  if (skinned_b)
479  {
480  // A is unskinned, B is skinned. Render A first
481  return true;
482  }
483  else
484  {
485  // A and B are both unskinned, sort by two-sided
486  if (two_sided_a)
487  {
488  if (two_sided_b)
489  {
490  // A and B are both two-sided, sort by VAO
491  return (a->vertex_array < b->vertex_array);
492  }
493  else
494  {
495  // A is two-sided, B is one-sided. Render B first
496  return false;
497  }
498  }
499  else
500  {
501  if (two_sided_b)
502  {
503  // A is one-sided, B is two-sided. Render A first
504  return true;
505  }
506  else
507  {
508  // A and B are both one-sided, sort by VAO
509  return (a->vertex_array < b->vertex_array);
510  }
511  }
512  }
513  }
514 }
515 
516 } // namespace render
Graphics pipeline interface.
Definition: pipeline.hpp:48
void set_primitive_topology(primitive_topology topology)
Sets the primitive topology to use for drawing.
Definition: pipeline.cpp:356
void clear_attachments(std::uint8_t mask, const clear_value &value)
Clears the color, depth, or stencil buffers of current attachments.
Definition: pipeline.cpp:1053
void bind_shader_program(const gl::shader_program *shader_program)
Sets the vertex input.
Definition: pipeline.cpp:292
void bind_framebuffer(const gl::framebuffer *framebuffer)
Sets the vertex input.
Definition: pipeline.cpp:275
void set_depth_clamp_enabled(bool enabled)
Controls whether depth clamping is enabled.
Definition: pipeline.cpp:585
void set_color_blend_enabled(bool enabled)
Controls whether blending is enabled for the corresponding color attachment.
Definition: pipeline.cpp:953
void set_cull_mode(cull_mode mode)
Sets the triangle culling mode.
Definition: pipeline.cpp:503
void set_viewport(std::uint32_t first_viewport, std::span< const viewport > viewports)
Sets one or more viewports.
Definition: pipeline.cpp:381
void set_depth_write_enabled(bool enabled)
Controls whether depth writes are enabled.
Definition: pipeline.cpp:666
void bind_vertex_buffers(std::uint32_t first_binding, std::span< const vertex_buffer *const > buffers, std::span< const std::size_t > offsets, std::span< const std::size_t > strides)
Binds vertex buffers.
Definition: pipeline.cpp:326
void set_depth_compare_op(gl::compare_op compare_op)
Sets the depth comparison operator.
Definition: pipeline.cpp:675
void draw(std::uint32_t vertex_count, std::uint32_t instance_count, std::uint32_t first_vertex, std::uint32_t first_instance)
Draws primitives.
Definition: pipeline.cpp:1028
void set_depth_test_enabled(bool enabled)
Controls whether depth testing is enabled.
Definition: pipeline.cpp:649
void bind_vertex_array(const vertex_array *array)
Binds a vertex array.
Definition: pipeline.cpp:309
Shader program which can be linked to shader objects and executed.
Template used to for generating one or more shader variants from a single source.
virtual void update(bool value) const
Updates the value of the variable.
void execute(render::context &ctx) override
Executes the render stage.
void set_max_bone_count(std::size_t bone_count)
Sets the maximum bone count for shadow-casting skeletal meshes.
cascaded_shadow_map_stage(gl::pipeline &pipeline, ::resource_manager &resource_manager)
Constructs a cascaded shadow map stage.
A material is associated with exactly one shader program and contains a set of material properties wh...
Definition: material.hpp:37
material_shadow_mode get_shadow_mode() const noexcept
Returns the material shadow mode.
Definition: material.hpp:108
bool is_two_sided() const noexcept
Returns true if the material surface is two-sided, and false otherwise.
Definition: material.hpp:96
Manages the loading, caching, and saving of resources.
std::shared_ptr< T > load(const std::filesystem::path &path)
Loads and caches a resource.
constexpr float get_aspect_ratio() const noexcept
Returns the camera's aspect ratio.
Definition: camera.hpp:205
constexpr const math::fvec3 & get_forward() const noexcept
Returns the camera's forward vector.
Definition: camera.hpp:259
constexpr float get_clip_near() const noexcept
Returns the signed distance to the camera's near clipping plane.
Definition: camera.hpp:187
constexpr float get_vertical_fov() const noexcept
Returns the camera's vertical field of view, in radians.
Definition: camera.hpp:199
constexpr const math::fmat4 & get_inv_view() const noexcept
Returns the inverse of the camera's view matrix.
Definition: camera.hpp:229
const std::vector< object_base * > & get_objects() const noexcept
Returns all objects in the collection.
Definition: collection.hpp:56
Light source with parallel rays and constant intensity.
constexpr const std::shared_ptr< gl::framebuffer > & get_shadow_framebuffer() const noexcept
Returns the shadow map framebuffer, of nullptr if no shadow map framebuffer is set.
constexpr const math::fvec4 & get_shadow_cascade_distances() const noexcept
Returns the array of shadow cascade far clipping plane distances.
constexpr float get_shadow_max_distance() const noexcept
Returns the maximum distance from a camera's near clipping plane up to which shadows are visible.
constexpr std::span< const math::fmat4 > get_shadow_cascade_matrices() const noexcept
Returns the array of world-space to cascade texture-space transformation matrices.
constexpr const math::fvec3 & get_direction() const noexcept
Returns a unit vector pointing in the light direction.
constexpr unsigned int get_shadow_cascade_count() const noexcept
Returns the number of shadow cascades.
constexpr float get_shadow_cascade_distribution() const noexcept
Returns the shadow cascade distribution weight.
constexpr std::span< const math::fmat4 > get_shadow_scale_bias_matrices() const noexcept
Returns the array of shadow cascade scale-bias matrices.
Abstract base class for light objects.
Definition: scene/light.hpp:32
Abstract base class for scene objects.
Definition: object.hpp:37
virtual const aabb_type & get_bounds() const noexcept=0
Returns the bounds of the object.
constexpr std::uint32_t get_layer_mask() const noexcept
Returns the layer mask of the object.
Definition: object.hpp:121
virtual const std::size_t get_object_type_id() const noexcept=0
Returns the type ID for this scene object type.
constexpr const vector_type & get_translation() const noexcept
Returns the translation of the object.
Definition: object.hpp:133
virtual void render(render::context &ctx) const
Adds render operations to a render context.
Definition: object.hpp:52
constexpr const quaternion_type & get_rotation() const noexcept
Returns the rotation of the object.
Definition: object.hpp:139
static const std::atomic< std::size_t > object_type_id
Unique type ID for this scene object type.
Definition: object.hpp:175
log_message< log_message_severity::warning, Args... > log_warning
Formats and logs a warning message.
Definition: log.hpp:130
log_message< log_message_severity::error, Args... > log_error
Formats and logs an error message.
Definition: log.hpp:144
@ a
Vertex A region.
@ b
Vertex B region.
@ none
No triangles are discarded.
@ back
Back-facing triangles are discarded.
@ vertex
Vertex shader stage.
@ depth_clear_bit
Indicates the depth buffer should be cleared.
Definition: clear-bits.hpp:34
@ greater
Comparison evaluates reference > test.
constexpr mat4< T > look_at_rh(const vec3< T > &position, const vec3< T > &target, const vec3< T > &up)
Constructs a right-handed viewing transformation matrix.
constexpr mat4< T > ortho_half_z(T left, T right, T bottom, T top, T near, T far) noexcept
Constructs an orthographic projection matrix which will transform the near and far clipping planes to...
T log_lerp(const T &x, const T &y, S a)
Logarithmically interpolates between x and y.
constexpr T lerp(const T &x, const T &y, S a) noexcept
Linearly interpolates between x and y.
std::tuple< mat4< T >, mat4< T > > perspective_half_z_inv(T vertical_fov, T aspect_ratio, T near, T far)
Constructs a perspective projection matrix which will transform the near and far clipping planes to [...
@ uv
Vertex UV texture coordinates (vec2)
High-level rendering.
@ none
Material does not cast shadows.
@ directional
Directional light.
n-dimensional plane.
Definition: hyperplane.hpp:36
n-dimensional axis-aligned rectangle.
vector_type min
Minimum extent of the hyperrectangle.
vector_type max
Maximum extent of the hyperrectangle.
void extend(const vector_type &point) noexcept
Extends the hyperrectangle to include a point.
Viewport position, dimensions, and depth range.
Definition: viewport.hpp:31
n by m column-major matrix.
Definition: math/matrix.hpp:44
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180
static constexpr vector infinity() noexcept
Returns a vector of infinities, where every element is equal to infinity.
Definition: vector.hpp:342
constexpr element_type & z() noexcept
Returns a reference to the third element.
Definition: vector.hpp:196
Context of a renderer.
Definition: context.hpp:40
const scene::camera * camera
Pointer to the camera.
Definition: context.hpp:42
scene::collection * collection
Collection of scene objects being rendered.
Definition: context.hpp:45
std::vector< const operation * > operations
Render operations generated by visible objects.
Definition: context.hpp:60
Atomic render operation.
Definition: operation.hpp:38
std::uint32_t vertex_count
Definition: operation.hpp:45
std::span< const math::fmat4 > matrix_palette
Definition: operation.hpp:54
std::size_t vertex_offset
Definition: operation.hpp:42
std::size_t vertex_stride
Definition: operation.hpp:43
math::fmat4 transform
Definition: operation.hpp:51
gl::primitive_topology primitive_topology
Definition: operation.hpp:39
const gl::vertex_buffer * vertex_buffer
Definition: operation.hpp:41
std::shared_ptr< render::material > material
Definition: operation.hpp:49
const gl::vertex_array * vertex_array
Definition: operation.hpp:40