sandbox
Loading...
Searching...
No Matches
skinned_mesh_material_draw_list.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_ANIMATIONS_SKINNED_MESH_DRAW_LIST_HPP_
3#define LIBSBX_ANIMATIONS_SKINNED_MESH_DRAW_LIST_HPP_
4
5#include <filesystem>
6#include <unordered_set>
7#include <ranges>
8#include <algorithm>
9#include <iterator>
10
11#include <easy/profiler.h>
12
13#include <range/v3/view/enumerate.hpp>
14
15#include <libsbx/core/engine.hpp>
16
17#include <libsbx/graphics/graphics_module.hpp>
18#include <libsbx/graphics/subrenderer.hpp>
19#include <libsbx/graphics/pipeline/pipeline.hpp>
20#include <libsbx/graphics/pipeline/graphics_pipeline.hpp>
21#include <libsbx/graphics/descriptor/descriptor_handler.hpp>
22
23#include <libsbx/assets/assets_module.hpp>
24
25#include <libsbx/scenes/scenes_module.hpp>
26#include <libsbx/scenes/scene.hpp>
27
28#include <libsbx/scenes/components/skinned_mesh.hpp>
29
30#include <libsbx/models/material_draw_list.hpp>
31
32#include <libsbx/animations/mesh.hpp>
33#include <libsbx/animations/animator.hpp>
34
35namespace sbx::animations {
36
38
40
42 std::uint32_t skinned_vertex_offset{0u};
43 }; // struct instance_payload
44
45 struct skinning_job {
46 graphics::buffer::address_type pre_vertices;
47 graphics::buffer::address_type post_vertices;
48 std::uint32_t vertex_count;
49 std::uint32_t bone_offset;
50 }; // struct skinning_job
51
52 inline static const auto bone_matrices_buffer_name = utility::hashed_string{"bone_matrices"};
53
54 template<typename DrawList>
55 static auto create_shared_buffers(DrawList& draw_list) -> void {
56 draw_list.create_buffer(bone_matrices_buffer_name, graphics::storage_buffer::min_size, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
57 }
58
59 template<typename DrawList>
60 static auto destroy_shared_buffers([[maybe_unused]] DrawList& draw_list) -> void {
61 draw_list.destroy_buffer(bone_matrices_buffer_name);
62 }
63
64 template<typename DrawList>
65 static auto update_shared_buffers(DrawList& draw_list) -> void {
66 draw_list.update_buffer(_bone_matrices, bone_matrices_buffer_name);
67
68 _bone_matrices.clear();
69 }
70
71 template<typename Callable>
72 static auto for_each_submission(scenes::scene& scene, Callable&& callable) -> void {
73 auto& assets_module = core::engine::get_module<assets::assets_module>();
74
75 auto& graph = scene.graph();
76
77 _skinning_jobs.clear();
78
79 const auto query = graph.query<const scenes::skinned_mesh, animations::animator>();
80
81 auto vertex_cursor = std::uint32_t{0u};
82
83 for (auto&& [node, skinned_mesh, animator] : query.each()) {
84 const auto transform_data = models::transform_data{graph.world_transform(node), graph.world_normal(node)};
85
86 const auto& pose = skinned_mesh.pose();
87
88 const auto bone_offset = static_cast<std::uint32_t>(_bone_matrices.size());
89
90 utility::append(_bone_matrices, pose);
91
92 const auto& mesh_id = skinned_mesh.mesh_id();
93
94 auto& mesh = assets_module.get_asset<animations::mesh>(mesh_id);
95
96 _skinning_jobs.emplace_back(skinning_job{
97 .pre_vertices = mesh.address(),
98 .post_vertices = 0,
99 .vertex_count = mesh.vertex_count(),
100 .bone_offset = bone_offset
101 });
102
103 const auto entity_vertex_offset = vertex_cursor;
104 vertex_cursor += mesh.vertex_count();
105
106 for (const auto& submesh : skinned_mesh.submeshes()) {
107 std::invoke(callable, node, mesh_id, submesh.index, submesh.material, transform_data, instance_payload{entity_vertex_offset});
108 }
109 }
110 }
111
112 static auto make_instance_data(const scenes::node node, const std::uint32_t transform_index, std::uint32_t material_index, const instance_payload& payload) -> models::instance_data {
113 return models::instance_data{transform_index, material_index, static_cast<std::uint32_t>(node), payload.skinned_vertex_offset};
114 }
115
116 template<typename Mesh, typename Emitter>
117 static auto build_draw_commands(const Mesh& mesh, std::uint32_t submesh_index, std::vector<models::instance_data>&& instances, Emitter&& emitter) -> std::uint32_t {
118 const auto& submesh = mesh.submesh(submesh_index);
119
120 for (auto i = std::uint32_t{0u}; i < static_cast<std::uint32_t>(instances.size()); ++i) {
121 auto command = VkDrawIndexedIndirectCommand{};
122 command.indexCount = submesh.index_count;
123 command.instanceCount = 1u;
124 command.firstIndex = submesh.index_offset;
125 command.vertexOffset = static_cast<std::int32_t>(instances[i].payload + submesh.vertex_offset);
126 command.firstInstance = emitter.base_instance;
127
128 emitter.emit_single(command, instances[i]);
129 }
130
131 return static_cast<std::uint32_t>(instances.size());
132 }
133
134 static auto skinning_jobs() -> std::vector<skinning_job>& {
135 return _skinning_jobs;
136 }
137
138private:
139
140 inline static auto _bone_matrices = std::vector<math::matrix4x4>{};
141 inline static auto _skinning_jobs = std::vector<skinning_job>{};
142
143}; // struct skinned_mesh_traits
144
145using skinned_mesh_material_draw_list = models::basic_material_draw_list<skinned_mesh_traits>;
146
147} // namespace sbx::animations
148
149#endif // LIBSBX_ANIMATIONS_SKINNED_MESH_DRAW_LIST_HPP_
Definition: tests.cpp:6
Definition: mesh.hpp:21
Definition: hashed_string.hpp:17
Definition: skinned_mesh_material_draw_list.hpp:41
Definition: skinned_mesh_material_draw_list.hpp:45
Definition: skinned_mesh_material_draw_list.hpp:37