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 struct instance_payload { };
41
42 struct skinning_job {
43 graphics::buffer::address_type pre_vertices;
44 graphics::buffer::address_type post_vertices;
45 std::uint32_t vertex_count;
46 std::uint32_t bone_offset;
47 }; // struct skinning_job
48
49 inline static const auto bone_matrices_buffer_name = utility::hashed_string{"bone_matrices"};
50
51 template<typename DrawList>
52 static auto create_shared_buffers(DrawList& draw_list) -> void {
53 draw_list.create_buffer(bone_matrices_buffer_name, graphics::storage_buffer::min_size, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
54 }
55
56 template<typename DrawList>
57 static auto destroy_shared_buffers([[maybe_unused]] DrawList& draw_list) -> void {
58 draw_list.destroy_buffer(bone_matrices_buffer_name);
59 }
60
61 template<typename DrawList>
62 static auto update_shared_buffers(DrawList& draw_list) -> void {
63 draw_list.update_buffer(_bone_matrices, bone_matrices_buffer_name);
64
65 _bone_matrices.clear();
66 }
67
68 template<typename Callable>
69 static auto for_each_submission(scenes::scene& scene, Callable&& callable) -> void {
70 auto& assets_module = core::engine::get_module<assets::assets_module>();
71
72 _skinning_jobs.clear();
73
74 const auto query = scene.query<const scenes::skinned_mesh, animations::animator>();
75
76 for (auto&& [node, skinned_mesh, animator] : query.each()) {
77 const auto transform_data = models::transform_data{scene.world_transform(node), scene.world_normal(node)};
78
79 const auto& pose = skinned_mesh.pose();
80
81 const auto bone_offset = static_cast<std::uint32_t>(_bone_matrices.size());
82
83 utility::append(_bone_matrices, pose);
84
85 const auto& mesh_id = skinned_mesh.mesh_id();
86
87 auto& mesh = assets_module.get_asset<animations::mesh>(mesh_id);
88
89 _skinning_jobs.emplace_back(skinning_job{
90 .pre_vertices = mesh.address(),
91 .post_vertices = 0,
92 .vertex_count = mesh.vertex_count(),
93 .bone_offset = bone_offset
94 });
95
96 for (const auto& submesh : skinned_mesh.submeshes()) {
97 std::invoke(callable, node, mesh_id, submesh.index, submesh.material, transform_data, instance_payload{});
98 }
99 }
100 }
101
102 static auto make_instance_data(const scenes::node node, const std::uint32_t transform_index, std::uint32_t material_index, [[maybe_unused]] const instance_payload& payload) -> models::instance_data {
103 return models::instance_data{transform_index, material_index, static_cast<std::uint32_t>(node), 0u};
104 }
105
106 template<typename Mesh, typename Emitter>
107 static auto build_draw_commands(const Mesh& mesh, std::uint32_t submesh_index, std::vector<models::instance_data>&& instances, Emitter&& emitter) -> std::uint32_t {
108 auto base_instance_offset = std::uint32_t{0};
109
110 const auto& submesh = mesh.submesh(submesh_index);
111
112 for (const auto& instance : instances) {
113 const auto instance_index = emitter.base_instance + base_instance_offset;
114
115 auto command = VkDrawIndexedIndirectCommand{};
116 command.indexCount = submesh.index_count;
117 command.instanceCount = 1u;
118 command.firstIndex = submesh.index_offset;
119 command.vertexOffset = static_cast<std::int32_t>(instance_index * mesh.vertex_count());
120 command.firstInstance = instance_index;
121
122 emitter.emit_single(command, instance);
123
124 base_instance_offset++;
125 }
126
127 return base_instance_offset;
128 }
129
130 static auto skinning_jobs() -> std::vector<skinning_job>& {
131 return _skinning_jobs;
132 }
133
134private:
135
136 inline static auto _bone_matrices = std::vector<math::matrix4x4>{};
137 inline static auto _skinning_jobs = std::vector<skinning_job>{};
138
139}; // struct skinned_mesh_traits
140
141using skinned_mesh_material_draw_list = models::basic_material_draw_list<skinned_mesh_traits>;
142
143} // namespace sbx::animations
144
145#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:40
Definition: skinned_mesh_material_draw_list.hpp:42
Definition: skinned_mesh_material_draw_list.hpp:37