Skip to content

Commit 46544f8

Browse files
authored
Incorporate skinned meshes (#76)
* Move Topology to Mesh::Primitive - Prepare for `MorphMesh`. * Add hash_combine, Pipeline::VertType (placeholder) * WIP: SkinnedMesh, skin.vert, gltf2cpp update, etc * WIP: Refactor Shader - `Shader` represents a single SPIR-V shader. - `Shader::Program` comprises vert and frag shaders. - This will enable a mesh to provide its vertex layout + vertex shader ID. * WIP: non-interleaved geometry * Use SSBO for joints * Revert Geometry; add Geometry::Packed Groundwork for `MeshPrimitive` and support for both packed / interleaved data. * Incorporate VertexLayout into Pipeline selection - `MeshPrimitive` will provide this info later. * Consolidate SkinnedMesh buffers * Make SkinnedMesh generalized * Hash VertexLayout - Remove `VertexLayout::Db`. - Use binding numbers 6-9 instead of 4-7 for instance mats. This reserves 0-5 for vertex / joint buffers. * Add VertexInput, Buffer::Pool, Buffer:VecPool<T> - Improve scene rendering flow. * Use Buffer::VecPool in SceneRenderer * Add MeshPrimitive, use in Scene - Cleanup `SceneRenderer`. * Remove StaticMesh, SkinnedMesh - Fix embed shader custom commands: isolating skinned.vert fixes the problem of the command being invoked on every build. * Fixup all skinning issues - Fix order of quaternion components from GLTF. - Fix joints: use global transform instead of node's local transform. TODO: Optimize global transform matrix computation / tree traversal per primitive. * Memoify global mats, fixup animations - Each animation has multiple animators. * Add MeshPrimitive::instance_binding() - Use in `SceneRenderer`. * Fix GLTF 1:N image => textures - Store loaded images for multiple textures to be able to reuse. - Inspect animations in editor. - Engine: invoke `on_loaded` even when no multi-threading. * Store a variant of Interpolators in an Animator * Fix shader changes not triggering recompile - Revert isolation of skinned.vert, better to eat some build time and ensure shaders are up to date. * Cleanup - Rename `MeshPrimitive::Builder` to `Uploader`, make internal. - Add `Geometry` overloads in `MeshPrimitive`, `Scene`.
1 parent e74c4a5 commit 46544f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1238
-541
lines changed

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,20 @@ if(FACADE_BUILD_EXE AND FACADE_BUILD_SHADERS)
3838
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/unlit.frag
3939
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/lit.frag
4040
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/skybox.frag
41+
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/skinned.vert
4142

4243
OUTPUT
4344
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/default_vert.spv.hpp
4445
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/unlit_frag.spv.hpp
4546
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/lit_frag.spv.hpp
4647
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/skybox_frag.spv.hpp
48+
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/skinned.vert.hpp
4749

4850
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/default.vert > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/default_vert.spv.hpp
4951
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/unlit.frag > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/unlit_frag.spv.hpp
5052
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/lit.frag > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/lit_frag.spv.hpp
5153
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/skybox.frag > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/skybox_frag.spv.hpp
54+
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/skinned.vert > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/skinned_vert.spv.hpp
5255
)
5356
endif()
5457

@@ -73,6 +76,9 @@ if(FACADE_BUILD_EXE)
7376

7477
src/bin/default_vert.spv.hpp
7578
src/bin/unlit_frag.spv.hpp
79+
src/bin/lit_frag.spv.hpp
80+
src/bin/skybox_frag.spv.hpp
81+
src/bin/skinned_vert.spv.hpp
7682
)
7783

7884
target_link_libraries(${PROJECT_NAME} PRIVATE

lib/engine/include/facade/engine/editor/drag_drop_id.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
#include <typeinfo>
88

99
namespace facade::editor {
10+
template <typename T>
11+
char const* truncated_name(T const&) {
12+
static constexpr std::string_view trim{"facade"};
13+
auto ret = std::string_view{typeid(T).name()};
14+
if (auto it = ret.find(trim); it != std::string_view::npos) { ret = ret.substr(it + trim.size()); }
15+
return ret.data();
16+
}
17+
1018
///
1119
/// \brief Initiate dragging an Id<T> drag-drop payload.
1220
/// \param out Id to store as the drag-drop payload
@@ -16,7 +24,7 @@ namespace facade::editor {
1624
template <typename T>
1725
bool drag_payload(Id<T> id, char const* label) {
1826
if (ImGui::BeginDragDropSource()) {
19-
ImGui::SetDragDropPayload(typeid(id).name(), &id, sizeof(id));
27+
ImGui::SetDragDropPayload(truncated_name(id), &id, sizeof(id));
2028
if (label && *label) { ImGui::Text("%s", label); }
2129
ImGui::EndDragDropSource();
2230
return true;
@@ -32,7 +40,7 @@ bool drag_payload(Id<T> id, char const* label) {
3240
template <typename T>
3341
bool accept_drop(Id<T>& out) {
3442
if (ImGui::BeginDragDropTarget()) {
35-
if (ImGuiPayload const* payload = ImGui::AcceptDragDropPayload(typeid(out).name())) {
43+
if (ImGuiPayload const* payload = ImGui::AcceptDragDropPayload(truncated_name(out))) {
3644
assert(payload->DataSize == sizeof(out));
3745
out = *reinterpret_cast<Id<T>*>(payload->Data);
3846
return true;

lib/engine/include/facade/engine/editor/inspector.hpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ class ResourceInspector : public Inspector {
4040
///
4141
void view(Texture const& texture, Id<Texture> id) const;
4242
///
43-
/// \brief Inspect a StaticMesh (read-only).
44-
/// \param mesh the StaticMesh to inspect
45-
/// \param id Id of the StaticMesh being inspected (used to create unique labels and drag payloads)
43+
/// \brief Inspect a MeshPrimitive (read-only).
44+
/// \param mesh the MeshPrimitive to inspect
45+
/// \param id Id of the MeshPrimitive being inspected (used to create unique labels and drag payloads)
4646
///
47-
void view(StaticMesh const& mesh, Id<StaticMesh> id) const;
47+
void view(MeshPrimitive const& mesh, Id<MeshPrimitive> id) const;
4848

4949
///
5050
/// \brief Inspect a Material.
@@ -58,6 +58,12 @@ class ResourceInspector : public Inspector {
5858
/// \param id Id of the Mesh being inspected (used to create unique labels and drag payloads)
5959
///
6060
void edit(Mesh& out_mesh, Id<Mesh> id) const;
61+
///
62+
/// \brief Inspect an Animation.
63+
/// \param out_mesh Animation to inspect
64+
/// \param id Id of the Animation being inspected (used to create unique labels and drag payloads)
65+
///
66+
void edit(Animation& out_animation, Id<Animation> id) const;
6167
};
6268

6369
///

lib/engine/include/facade/engine/editor/resource_browser.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ResourceBrowser {
2525
private:
2626
void add_mesh(bool trigger);
2727
void add_material(bool trigger);
28-
void add_static_mesh(bool trigger);
28+
void add_mesh_primitive(bool trigger);
2929

3030
enum class SmType { eCube, eSphere, eCone, eCylinder, eArrow };
3131

@@ -61,7 +61,7 @@ class ResourceBrowser {
6161
float stalk_height{1.0f};
6262
int xz_points{128};
6363
} arrow{};
64-
} static_mesh{};
64+
} primitive{};
6565
} m_data{};
6666

6767
Scene* m_scene{};

lib/engine/include/facade/engine/engine.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <facade/vk/shader.hpp>
1010

1111
namespace facade {
12-
struct Gfx;
1312
class Renderer;
1413
class Scene;
1514
struct Window;
@@ -52,10 +51,18 @@ class Engine {
5251
explicit Engine(CreateInfo const& create_info = {}) noexcept(false);
5352

5453
///
55-
/// \brief Register a shader for the renderer to look up during draws
54+
/// \brief Register a shader for the renderer to look up during draws.
5655
///
5756
void add_shader(Shader shader);
5857

58+
///
59+
/// \brief Register shaders for the renderer to look up during draws.
60+
///
61+
template <std::convertible_to<Shader>... T>
62+
void add_shaders(T... shaders) {
63+
(add_shader(shaders), ...);
64+
}
65+
5966
///
6067
/// \brief Show the window
6168
///

lib/engine/include/facade/engine/scene_renderer.hpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,28 @@ class SceneRenderer {
2121
private:
2222
void write_view(glm::vec2 const extent);
2323
void update_view(Pipeline& out_pipeline) const;
24-
std::span<glm::mat4x4 const> make_instance_mats(Node const& node, glm::mat4x4 const& parent);
24+
BufferView make_instance_mats(std::span<Transform const> instances, glm::mat4x4 const& parent);
25+
DescriptorBuffer make_joint_mats(Skin const& skin, glm::mat4x4 const& parent);
26+
glm::mat4x4 compute_global_mat(Node const& node) const;
27+
glm::mat4x4 const& get_global_mat(Node const& node);
2528

2629
void render(Renderer& renderer, vk::CommandBuffer cb, Skybox const& skybox);
27-
void render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4 parent = matrix_identity_v);
28-
void draw(vk::CommandBuffer cb, StaticMesh const& static_mesh, std::span<glm::mat4x4 const> mats);
29-
30-
BufferView next_instances(std::span<glm::mat4x4 const> mats);
31-
32-
struct Instances {
33-
std::vector<Buffer> buffers{};
34-
std::size_t index{};
35-
36-
void rotate();
37-
};
30+
void render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4x4 parent = matrix_identity_v);
31+
void draw(Renderer& renderer, vk::CommandBuffer cb, Node const& node, Mesh::Primitive const& primitive);
32+
void draw(vk::CommandBuffer cb, MeshPrimitive const& mesh, BufferView instances);
3833

3934
Gfx m_gfx;
40-
Instances m_instances{};
35+
Material m_material;
36+
Buffer::VecPool<glm::mat4x4> m_instances;
37+
Buffer::VecPool<glm::mat4x4> m_joints;
4138
Sampler m_sampler;
4239
Buffer m_view_proj;
4340
Buffer m_dir_lights;
4441
Texture m_white;
4542
Texture m_black;
4643
Info m_info{};
44+
std::unordered_map<Id<Node>, glm::mat4x4, std::hash<std::size_t>> m_global_mats{};
4745

48-
std::vector<glm::mat4x4> m_instance_mats{};
4946
Scene const* m_scene{};
5047
};
5148
} // namespace facade

lib/engine/src/editor/inspector.cpp

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,20 @@ void edit_material(NotClosed<Window> target, SceneResources const& resources, Li
2626
make_id_slot(lit.emissive, "Emissive", name.c_str(), {true});
2727
}
2828

29-
void edit_material(SceneResources const& resources, UnlitMaterial& unlit) {
29+
void edit_material(NotClosed<Window>, SceneResources const& resources, UnlitMaterial& unlit) {
3030
auto name = FixedString<128>{};
3131
if (unlit.texture) { name = FixedString<128>{"{} ({})", resources.textures[*unlit.texture].name(), *unlit.texture}; }
3232
make_id_slot(unlit.texture, "Texture", name.c_str(), {true});
3333
}
3434

35-
constexpr std::string_view to_str(vk::PrimitiveTopology const topo) {
35+
constexpr std::string_view to_str(Topology const topo) {
3636
switch (topo) {
37-
case vk::PrimitiveTopology::ePointList: return "Point list";
38-
case vk::PrimitiveTopology::eLineList: return "Line list";
39-
case vk::PrimitiveTopology::eLineStrip: return "Line strip";
40-
case vk::PrimitiveTopology::eTriangleList: return "Triangle list";
41-
case vk::PrimitiveTopology::eTriangleStrip: return "Triangle strip";
42-
case vk::PrimitiveTopology::eTriangleFan: return "Triangle fan";
37+
case Topology::ePoints: return "Points";
38+
case Topology::eLines: return "Lines";
39+
case Topology::eLineStrip: return "Line strip";
40+
case Topology::eTriangles: return "Triangles";
41+
case Topology::eTriangleStrip: return "Triangle strip";
42+
case Topology::eTriangleFan: return "Triangle fan";
4343
default: return "(Unsupported)";
4444
}
4545
}
@@ -58,26 +58,23 @@ void ResourceInspector::view(Texture const& texture, Id<Texture> id) const {
5858
}
5959
}
6060

61-
void ResourceInspector::view(StaticMesh const& mesh, Id<StaticMesh> id) const {
61+
void ResourceInspector::view(MeshPrimitive const& mesh, Id<MeshPrimitive> id) const {
6262
auto const name = FixedString<128>{"{} ({})", mesh.name(), id};
6363
auto tn = TreeNode{name.c_str()};
6464
drag_payload(id, name.c_str());
6565
if (tn) {
6666
auto const info = mesh.info();
6767
ImGui::Text("%s", FixedString{"Vertices: {}", info.vertices}.c_str());
6868
ImGui::Text("%s", FixedString{"Indices: {}", info.indices}.c_str());
69-
ImGui::Text("%s", FixedString{"Topology: {}", to_str(mesh.topology())}.c_str());
7069
}
7170
}
7271

7372
void ResourceInspector::edit(Material& out_material, Id<Material> id) const {
74-
auto const name = FixedString<128>{"{} ({})", out_material.name(), id};
73+
auto const name = FixedString<128>{"{} ({})", out_material.name, id};
7574
auto tn = TreeNode{name.c_str()};
7675
drag_payload(id, name.c_str());
7776
if (tn) {
78-
auto& mat = out_material.base();
79-
if (auto* lit = dynamic_cast<LitMaterial*>(&mat)) { return edit_material(m_target, m_resources, *lit); }
80-
if (auto* unlit = dynamic_cast<UnlitMaterial*>(&mat)) { return edit_material(m_resources, *unlit); }
77+
std::visit([&](auto& mat) { edit_material(m_target, m_resources, mat); }, out_material.instance);
8178
}
8279
}
8380

@@ -89,27 +86,40 @@ void ResourceInspector::edit(Mesh& out_mesh, Id<Mesh> id) const {
8986
auto to_erase = std::optional<std::size_t>{};
9087
for (auto [primitive, index] : enumerate(out_mesh.primitives)) {
9188
if (auto tn = TreeNode{FixedString{"Primitive [{}]", index}.c_str()}) {
92-
name = FixedString<128>{"{} ({})", m_resources.static_meshes[primitive.static_mesh].name(), primitive.static_mesh};
93-
make_id_slot(primitive.static_mesh, "Static Mesh", name.c_str());
89+
name = FixedString<128>{"{} ({})", m_resources.primitives[primitive.primitive].name(), primitive.primitive};
90+
make_id_slot(primitive.primitive, "Mesh Primitive", name.c_str());
9491

9592
name = {};
96-
if (primitive.material) { name = FixedString<128>{"{} ({})", m_resources.materials[*primitive.material].name(), *primitive.material}; }
93+
if (primitive.material) { name = FixedString<128>{"{} ({})", m_resources.materials[*primitive.material].name, *primitive.material}; }
9794
make_id_slot(primitive.material, "Material", name.c_str(), {true});
9895

96+
ImGui::Text("%s", FixedString{"Topology: {}", to_str(primitive.topology)}.c_str());
97+
9998
if (small_button_red("x###remove_primitive")) { to_erase = index; }
10099
}
101100
}
102101
if (to_erase) { out_mesh.primitives.erase(out_mesh.primitives.begin() + static_cast<std::ptrdiff_t>(*to_erase)); }
103102
if (ImGui::SmallButton("+###add_primitive")) {
104103
if (!out_mesh.primitives.empty()) {
105104
out_mesh.primitives.push_back(out_mesh.primitives.front());
106-
} else if (!m_resources.static_meshes.empty()) {
105+
} else if (!m_resources.primitives.empty()) {
107106
out_mesh.primitives.push_back({});
108107
}
109108
}
110109
}
111110
}
112111

112+
void ResourceInspector::edit(Animation& out_animation, Id<Animation> id) const {
113+
auto name = FixedString<128>{"{} ({})", m_resources.animations[id].name, id};
114+
auto tn = TreeNode{name.c_str()};
115+
drag_payload(id, name.c_str());
116+
if (tn) {
117+
ImGui::ProgressBar(out_animation.elapsed / out_animation.duration());
118+
ImGui::Text("%s", FixedString{"Duration: {:.2f}s", out_animation.duration()}.c_str());
119+
ImGui::SliderFloat("Speed", &out_animation.time_scale, 0.0f, 10.0f);
120+
}
121+
}
122+
113123
void SceneInspector::camera() const {
114124
auto& node = m_scene.camera();
115125
auto id = node.find<Camera>();

lib/engine/src/editor/reflector.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,16 @@ bool Reflector::operator()(Rgb& out_rgb) const {
9898
bool Reflector::operator()(Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const {
9999
auto ret = Modified{};
100100
auto vec3 = out_transform.position();
101-
if (ret((*this)("Position", vec3, 0.1f))) { out_transform.set_position(vec3); }
101+
if (ret((*this)("Position", vec3, 0.01f))) { out_transform.set_position(vec3); }
102102
auto quat = out_transform.orientation();
103103
if (ret((*this)("Orientation", quat))) { out_transform.set_orientation(quat); }
104104
ImGui::SameLine();
105105
if (ImGui::SmallButton("Reset")) { out_transform.set_orientation(quat_identity_v); }
106106
vec3 = out_transform.scale();
107107
if (out_unified_scaling) {
108-
if (ret(ImGui::DragFloat("Scale", &vec3.x, 0.05f))) { out_transform.set_scale({vec3.x, vec3.x, vec3.x}); }
108+
if (ret(ImGui::DragFloat("Scale", &vec3.x, 0.01f))) { out_transform.set_scale({vec3.x, vec3.x, vec3.x}); }
109109
} else {
110-
if (ret((*this)("Scale", vec3, 0.05f))) { out_transform.set_scale(vec3); }
110+
if (ret((*this)("Scale", vec3, 0.01f))) { out_transform.set_scale(vec3); }
111111
}
112112
if (scaling_toggle) {
113113
ImGui::SameLine();

0 commit comments

Comments
 (0)