Browse Source

Revise skeleton pose classes. Rename rigged_mesh to skeletal_mesh. Make model vertex bone indices uint16

master
C. J. Howard 1 year ago
parent
commit
47eb267484
16 changed files with 446 additions and 286 deletions
  1. +79
    -0
      src/engine/animation/animation-pose.cpp
  2. +63
    -0
      src/engine/animation/animation-pose.hpp
  3. +19
    -18
      src/engine/animation/bone.hpp
  4. +61
    -0
      src/engine/animation/pose.cpp
  5. +18
    -45
      src/engine/animation/pose.hpp
  6. +62
    -0
      src/engine/animation/rest-pose.cpp
  7. +66
    -0
      src/engine/animation/rest-pose.hpp
  8. +0
    -57
      src/engine/animation/skeleton-bind-pose.cpp
  9. +0
    -80
      src/engine/animation/skeleton-pose.cpp
  10. +5
    -5
      src/engine/animation/skeleton.cpp
  11. +10
    -16
      src/engine/animation/skeleton.hpp
  12. +7
    -7
      src/engine/render/model.cpp
  13. +9
    -9
      src/engine/scene/skeletal-mesh.cpp
  14. +13
    -13
      src/engine/scene/skeletal-mesh.hpp
  15. +27
    -29
      src/game/ant/ant-morphogenesis.cpp
  16. +7
    -7
      src/game/states/nest-selection-state.cpp

+ 79
- 0
src/engine/animation/animation-pose.cpp View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/animation/animation-pose.hpp>
#include <engine/animation/skeleton.hpp>
#include <algorithm>
#include <execution>
animation_pose::animation_pose(const skeleton& skeleton):
pose(skeleton),
m_matrix_palette(skeleton.get_bone_count())
{
reset();
}
void animation_pose::update(bone_index_type first_index, std::size_t bone_count)
{
// Update absolute transforms
pose::update(first_index, bone_count);
// Get skeleton rest pose
const auto& rest_pose = m_skeleton->get_rest_pose();
// Update skinning matrix palette
std::for_each
(
std::execution::par_unseq,
m_matrix_palette.begin() + first_index,
m_matrix_palette.begin() + bone_count,
[&](auto& skinning_matrix)
{
const bone_index_type bone_index = static_cast<bone_index_type>(&skinning_matrix - m_matrix_palette.data());
skinning_matrix = (m_absolute_transforms[bone_index] * rest_pose.get_inverse_absolute_transform(bone_index)).matrix();
}
);
}
void animation_pose::reset()
{
if (!m_skeleton)
{
return;
}
// Get skeleton rest pose
const auto& rest_pose = m_skeleton->get_rest_pose();
// Reset transforms and skinning matrix palette
std::for_each
(
std::execution::par_unseq,
m_relative_transforms.begin(),
m_relative_transforms.end(),
[&](auto& relative_transform)
{
const bone_index_type bone_index = static_cast<bone_index_type>(&relative_transform - m_relative_transforms.data());
relative_transform = rest_pose.get_relative_transform(bone_index);
m_absolute_transforms[bone_index] = rest_pose.get_absolute_transform(bone_index);
m_matrix_palette[bone_index] = bone_matrix_type::identity();
}
);
}

+ 63
- 0
src/engine/animation/animation-pose.hpp View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_ANIMATION_ANIMATION_POSE_HPP
#define ANTKEEPER_ANIMATION_ANIMATION_POSE_HPP
#include <engine/animation/pose.hpp>
#include <vector>
/**
* Animatable skeleton pose.
*/
class animation_pose: public pose
{
public:
/**
* Constructs an animation pose.
*
* @param skeleton Skeleton with which to associate the animation pose.
*/
explicit animation_pose(const skeleton& skeleton);
/// Constructs an empty animation pose.
animation_pose() noexcept = default;
using pose::update;
void update(bone_index_type first_index, std::size_t bone_count) override;
/**
* Resets the animation pose to the skeleton's rest pose.
*/
void reset();
/**
* Returns the skinning matrix palette of the animation pose.
*/
[[nodiscard]] inline const std::vector<bone_matrix_type>& get_matrix_palette() const noexcept
{
return m_matrix_palette;
}
private:
/// Skinning matrix palette.
std::vector<bone_matrix_type> m_matrix_palette;
};
#endif // ANTKEEPER_ANIMATION_ANIMATION_POSE_HPP

src/engine/animation/skeleton-bind-pose.hpp → src/engine/animation/bone.hpp View File

@ -17,26 +17,27 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP
#define ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP
#ifndef ANTKEEPER_ANIMATION_BONE_HPP
#define ANTKEEPER_ANIMATION_BONE_HPP
#include <engine/animation/skeleton-pose.hpp>
#include <engine/math/transform.hpp>
#include <cstdint>
/**
* Skeleton bind pose.
* Bone index type.
*
* @note The maximum number of bones per skeleton is 65,536.
*/
using bone_index_type = std::uint16_t;
/**
* Bone transform type.
*/
using bone_transform_type = math::transform<float>;
/**
* Bone skinning matrix type.
*/
class skeleton_bind_pose: public skeleton_pose
{
public:
/**
* Constructs a skeleton bind pose.
*
* @param skeleton Skeleton with which to associate the bind pose.
*/
skeleton_bind_pose(const skeleton& skeleton);
void update() override;
void reset_bone_transforms() override;
};
using bone_matrix_type = bone_transform_type::matrix_type;
#endif // ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP
#endif // ANTKEEPER_ANIMATION_BONE_HPP

+ 61
- 0
src/engine/animation/pose.cpp View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/animation/pose.hpp>
#include <engine/animation/skeleton.hpp>
#include <algorithm>
#include <execution>
pose::pose(const skeleton& skeleton):
m_skeleton(&skeleton),
m_relative_transforms(skeleton.get_bone_count(), bone_transform_type::identity()),
m_absolute_transforms(skeleton.get_bone_count(), bone_transform_type::identity())
{}
void pose::update()
{
update(0, m_absolute_transforms.size());
}
void pose::update(bone_index_type first_index, std::size_t bone_count)
{
bone_index_type child_index = first_index;
std::for_each
(
std::execution::seq,
m_absolute_transforms.begin() + first_index,
m_absolute_transforms.begin() + bone_count,
[&](auto& child_absolute_transform)
{
const bone_index_type parent_index = m_skeleton->get_bone_parent(child_index);
if (parent_index != child_index)
{
child_absolute_transform = m_absolute_transforms[parent_index] * m_relative_transforms[child_index];
}
else
{
child_absolute_transform = m_relative_transforms[child_index];
}
++child_index;
}
);
}

src/engine/animation/skeleton-pose.hpp → src/engine/animation/pose.hpp View File

@ -17,57 +17,44 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_ANIMATION_SKELETON_POSE_HPP
#define ANTKEEPER_ANIMATION_SKELETON_POSE_HPP
#ifndef ANTKEEPER_ANIMATION_POSE_HPP
#define ANTKEEPER_ANIMATION_POSE_HPP
#include <engine/math/transform.hpp>
#include <engine/math/matrix.hpp>
#include <cstdint>
#include <engine/animation/bone.hpp>
#include <vector>
class skeleton;
/**
* Skeleton pose.
* Base class for skeleton poses.
*/
class skeleton_pose
class pose
{
public:
/// Bone index type.
using bone_index_type = std::uint16_t;
/// Bone transform type.
using bone_transform_type = math::transform<float>;
/// Matrix type.
using bone_matrix_type = math::matrix<float, 4, 4>;
/**
* Constructs a skeleton pose.
* Constructs a pose.
*
* @param skeleton Skeleton with which to associate the pose.
*/
explicit skeleton_pose(const skeleton& skeleton);
/// Constructs an empty skeleton pose.
skeleton_pose() noexcept = default;
explicit pose(const skeleton& skeleton);
/**
* Updates the absolute transforms and matrix palette of the pose.
*/
virtual void update();
/// Constructs an empty pose.
pose() noexcept = default;
/**
* Resets all bone transforms to identity transforms.
* Updates the pose after one or more relative transforms have been changed.
*/
virtual void reset_bone_transforms();
void update();
/**
* Sets the number of bones in the pose.
* Updates a subset of the pose after one or more relative transforms have been changed.
*
* @param skeleton Skeleton with which to associate the pose.
* @param first_index Index of the first bone in the chain to update.
* @param bone_count Number of bones in the chain to update.
*
* @warning It's the caller's responsibility to ensure that any ancestors of the bone chain are up to date before the call, and any descendants are updated after the call.
*/
void set_skeleton(const skeleton* skeleton);
virtual void update(bone_index_type first_index, std::size_t bone_count);
/**
* Sets the relative transform describing a bone pose.
@ -110,17 +97,6 @@ public:
return m_absolute_transforms[index];
}
/**
* Returns the matrix palette of the pose.
*
* @note The matrix palette of a standard skeleton pose will contain its skinning matrices.
* @note The matrix palette of a skeleton bind pose will contain the inverses of its absolute transforms.
*/
[[nodiscard]] inline const std::vector<bone_matrix_type>& get_matrix_palette() const noexcept
{
return m_matrix_palette;
}
protected:
/// Skeleton with which the pose is associated.
const skeleton* m_skeleton{nullptr};
@ -130,9 +106,6 @@ protected:
/// Absolute transforms for each bone in a skeleton.
std::vector<bone_transform_type> m_absolute_transforms;
/// Skinning matrix palette.
std::vector<bone_matrix_type> m_matrix_palette;
};
#endif // ANTKEEPER_ANIMATION_SKELETON_POSE_HPP
#endif // ANTKEEPER_ANIMATION_POSE_HPP

+ 62
- 0
src/engine/animation/rest-pose.cpp View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/animation/rest-pose.hpp>
#include <engine/animation/skeleton.hpp>
#include <algorithm>
#include <execution>
rest_pose::rest_pose(const skeleton& skeleton):
pose(skeleton),
m_inverse_absolute_transforms(skeleton.get_bone_count(), bone_transform_type::identity())
{}
void rest_pose::update(bone_index_type first_index, std::size_t bone_count)
{
// Update absolute transforms
pose::update(first_index, bone_count);
// Update inverse absolute transforms
std::for_each
(
std::execution::par_unseq,
m_inverse_absolute_transforms.begin() + first_index,
m_inverse_absolute_transforms.begin() + bone_count,
[&](auto& inverse_absolute_transform)
{
bone_index_type bone_index = static_cast<bone_index_type>(&inverse_absolute_transform - m_inverse_absolute_transforms.data());
inverse_absolute_transform = math::inverse(m_absolute_transforms[bone_index]);
}
);
}
void rest_pose::resize()
{
if (m_skeleton)
{
const std::size_t bone_count = m_skeleton->get_bone_count();
if (bone_count != m_inverse_absolute_transforms.size())
{
m_relative_transforms.resize(bone_count);
m_absolute_transforms.resize(bone_count);
m_inverse_absolute_transforms.resize(bone_count);
}
}
}

+ 66
- 0
src/engine/animation/rest-pose.hpp View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_ANIMATION_REST_POSE_HPP
#define ANTKEEPER_ANIMATION_REST_POSE_HPP
#include <engine/animation/pose.hpp>
/**
* Skeleton rest pose.
*/
class rest_pose: public pose
{
public:
/**
* Constructs a rest pose.
*
* @param skeleton Skeleton with which to associate the rest pose.
*/
explicit rest_pose(const skeleton& skeleton);
/// Constructs an empty rest pose.
rest_pose() noexcept = default;
using pose::update;
void update(bone_index_type first_index, std::size_t bone_count) override;
/**
* Updates the number of bones in the rest pose if the skeleton has been modified.
*/
void resize();
/**
* Returns the inverse of the absolute transform describing a bone pose.
*
* @param index Index of a bone.
*
* @return Inverse of the absolute transform describing the bone pose.
*/
[[nodiscard]] inline const bone_transform_type& get_inverse_absolute_transform(bone_index_type index) const
{
return m_inverse_absolute_transforms[index];
}
private:
/// Inverse absolute transforms for each bone in the associated skeleton.
std::vector<bone_transform_type> m_inverse_absolute_transforms;
};
#endif // ANTKEEPER_ANIMATION_REST_POSE_HPP

+ 0
- 57
src/engine/animation/skeleton-bind-pose.cpp View File

@ -1,57 +0,0 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/animation/skeleton-bind-pose.hpp>
#include <engine/animation/skeleton.hpp>
skeleton_bind_pose::skeleton_bind_pose(const skeleton& skeleton):
skeleton_pose(skeleton)
{}
void skeleton_bind_pose::update()
{
const std::size_t bone_count = m_relative_transforms.size();
for (std::size_t i = 0; i < bone_count; ++i)
{
const bone_index_type parent_index = m_skeleton->get_bone_parent(static_cast<bone_index_type>(i));
if (parent_index != i)
{
m_absolute_transforms[i] = m_absolute_transforms[parent_index] * m_relative_transforms[i];
}
else
{
m_absolute_transforms[i] = m_relative_transforms[i];
}
m_matrix_palette[i] = math::inverse(m_absolute_transforms[i]).matrix();
}
}
void skeleton_bind_pose::reset_bone_transforms()
{
const std::size_t bone_count = m_relative_transforms.size();
for (std::size_t i = 0; i < bone_count; ++i)
{
m_relative_transforms[i] = bone_transform_type::identity();
m_absolute_transforms[i] = bone_transform_type::identity();
m_matrix_palette[i] = bone_matrix_type::identity();
}
}

+ 0
- 80
src/engine/animation/skeleton-pose.cpp View File

@ -1,80 +0,0 @@
/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/animation/skeleton-pose.hpp>
#include <engine/animation/skeleton.hpp>
skeleton_pose::skeleton_pose(const skeleton& skeleton):
m_skeleton(&skeleton),
m_relative_transforms(skeleton.get_bone_count()),
m_absolute_transforms(skeleton.get_bone_count()),
m_matrix_palette(skeleton.get_bone_count())
{}
void skeleton_pose::update()
{
const auto& bind_pose_inverse_absolute_transforms = m_skeleton->get_bind_pose().get_matrix_palette();
const std::size_t bone_count = m_relative_transforms.size();
for (std::size_t i = 0; i < bone_count; ++i)
{
const bone_index_type parent_index = m_skeleton->get_bone_parent(static_cast<bone_index_type>(i));
if (parent_index != i)
{
m_absolute_transforms[i] = m_absolute_transforms[parent_index] * m_relative_transforms[i];
}
else
{
m_absolute_transforms[i] = m_relative_transforms[i];
}
m_matrix_palette[i] = m_absolute_transforms[i].matrix() * bind_pose_inverse_absolute_transforms[i];
}
}
void skeleton_pose::reset_bone_transforms()
{
if (m_skeleton)
{
const auto& bind_pose = m_skeleton->get_bind_pose();
const auto& bind_pose_inverse_absolute_transforms = bind_pose.get_matrix_palette();
const std::size_t bone_count = m_relative_transforms.size();
for (std::size_t i = 0; i < bone_count; ++i)
{
m_relative_transforms[i] = bind_pose.get_relative_transform(static_cast<bone_index_type>(i));
m_absolute_transforms[i] = bind_pose.get_absolute_transform(static_cast<bone_index_type>(i));
m_matrix_palette[i] = bind_pose_inverse_absolute_transforms[i] * m_absolute_transforms[i].matrix();
}
}
}
void skeleton_pose::set_skeleton(const skeleton* skeleton)
{
m_skeleton = skeleton;
const std::size_t bone_count = (m_skeleton) ? m_skeleton->get_bone_count() : 0;
m_relative_transforms.resize(bone_count);
m_absolute_transforms.resize(bone_count);
m_matrix_palette.resize(bone_count);
reset_bone_transforms();
}

+ 5
- 5
src/engine/animation/skeleton.cpp View File

@ -21,25 +21,25 @@
skeleton::skeleton(std::size_t bone_count):
m_bone_parents(bone_count, 0),
m_bind_pose(*this)
m_rest_pose(*this)
{}
skeleton::skeleton():
skeleton(0)
{}
void skeleton::update_bind_pose()
void skeleton::update_rest_pose()
{
m_bind_pose.update();
m_rest_pose.update();
}
void skeleton::set_bone_count(std::size_t bone_count)
{
m_bone_parents.resize(bone_count, 0);
m_bind_pose.set_skeleton(this);
m_rest_pose.resize();
}
std::optional<typename skeleton::bone_index_type> skeleton::get_bone_index(hash::fnv1a32_t name) const
std::optional<bone_index_type> skeleton::get_bone_index(hash::fnv1a32_t name) const
{
if (auto i = m_bone_map.find(name); i != m_bone_map.end())
{

+ 10
- 16
src/engine/animation/skeleton.hpp View File

@ -20,12 +20,12 @@
#ifndef ANTKEEPER_ANIMATION_SKELETON_HPP
#define ANTKEEPER_ANIMATION_SKELETON_HPP
#include <engine/animation/skeleton-bind-pose.hpp>
#include <engine/animation/bone.hpp>
#include <engine/animation/rest-pose.hpp>
#include <engine/utility/hash/fnv1a.hpp>
#include <unordered_map>
#include <vector>
#include <optional>
#include <cstdint>
/**
* Skeletal animation skeleton.
@ -33,12 +33,6 @@
class skeleton
{
public:
/// Bone index type.
using bone_index_type = std::uint16_t;
/// Bone transform type.
using bone_transform_type = skeleton_pose::bone_transform_type;
/**
* Constructs a skeleton.
*
@ -50,9 +44,9 @@ public:
skeleton();
/**
* Updates the bind pose of the skeleton.
* Updates the rest pose of the skeleton.
*/
void update_bind_pose();
void update_rest_pose();
/**
* Sets the number of bones in the skeleton.
@ -82,7 +76,7 @@ public:
*/
inline void set_bone_transform(bone_index_type index, const bone_transform_type& transform)
{
m_bind_pose.set_relative_transform(index, transform);
m_rest_pose.set_relative_transform(index, transform);
}
/**
@ -125,18 +119,18 @@ public:
*/
[[nodiscard]] std::optional<bone_index_type> get_bone_index(hash::fnv1a32_t name) const;
/// Returns the skeleton's bind pose.
[[nodiscard]] inline const skeleton_bind_pose& get_bind_pose() const noexcept
/// Returns the skeleton's rest pose.
[[nodiscard]] inline const rest_pose& get_rest_pose() const noexcept
{
return m_bind_pose;
return m_rest_pose;
}
private:
/// Indices of bone parents.
std::vector<bone_index_type> m_bone_parents;
/// Bind pose of the skeleton.
skeleton_bind_pose m_bind_pose;
/// Rest pose of the skeleton.
rest_pose m_rest_pose;
/// Map of bone names to bone indices.
std::unordered_map<hash::fnv1a32_t, bone_index_type> m_bone_map;

+ 7
- 7
src/engine/render/model.cpp View File

@ -89,7 +89,7 @@ std::unique_ptr resource_loader::load(::resource_m
}
if (vertex_format_flags & vertex_attribute_bone)
{
vertex_size += sizeof(std::uint32_t) * bones_per_vertex;
vertex_size += sizeof(std::uint16_t) * bones_per_vertex;
vertex_size += sizeof(float) * bones_per_vertex;
}
if (vertex_format_flags & vertex_attribute_barycentric)
@ -144,7 +144,7 @@ std::unique_ptr resource_loader::load(::resource_m
ctx.read32<std::endian::little>(vertex_data_offset, bones_per_vertex);
ctx.read32<std::endian::little>(vertex_data_offset, bones_per_vertex);
vertex_data_offset += sizeof(std::uint32_t) * bones_per_vertex;
vertex_data_offset += sizeof(std::uint16_t) * bones_per_vertex;
vertex_data_offset += sizeof(float) * bones_per_vertex;
}
if (vertex_format_flags & vertex_attribute_barycentric)
@ -213,10 +213,10 @@ std::unique_ptr resource_loader::load(::resource_m
}
if (vertex_format_flags & vertex_attribute_bone)
{
attribute.type = gl::vertex_attribute_type::uint_32;
attribute.type = gl::vertex_attribute_type::uint_16;
attribute.components = bones_per_vertex;
vao.bind(render::vertex_attribute::bone_index, attribute);
attribute.offset += sizeof(std::uint32_t) * attribute.components;
attribute.offset += sizeof(std::uint16_t) * attribute.components;
attribute.type = gl::vertex_attribute_type::float_32;
attribute.components = bones_per_vertex;
@ -303,7 +303,7 @@ std::unique_ptr resource_loader::load(::resource_m
ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&bone_parent_index), 1);
// Construct bone transform
skeleton::bone_transform_type bone_transform;
bone_transform_type bone_transform;
// Read bone translation
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(bone_transform.translation.data()), 3);
@ -325,8 +325,8 @@ std::unique_ptr resource_loader::load(::resource_m
skeleton.set_bone_transform(i, bone_transform);
}
// Update skeleton
skeleton.update_bind_pose();
// Update skeleton's rest pose
skeleton.update_rest_pose();
}
return model;

src/engine/scene/rigged-mesh.cpp → src/engine/scene/skeletal-mesh.cpp View File

@ -17,23 +17,23 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include <engine/scene/rigged-mesh.hpp>
#include <engine/scene/skeletal-mesh.hpp>
#include <engine/scene/camera.hpp>
namespace scene {
rigged_mesh::rigged_mesh(std::shared_ptr<render::model> model)
skeletal_mesh::skeletal_mesh(std::shared_ptr<render::model> model)
{
set_model(model);
}
void rigged_mesh::set_model(std::shared_ptr<render::model> model)
void skeletal_mesh::set_model(std::shared_ptr<render::model> model)
{
m_model = model;
if (m_model)
{
m_pose.set_skeleton(&model->get_skeleton());
m_pose = animation_pose(model->get_skeleton());
m_operations.resize(m_model->get_groups().size());
for (std::size_t i = 0; i < m_operations.size(); ++i)
@ -58,7 +58,7 @@ void rigged_mesh::set_model(std::shared_ptr model)
transformed();
}
void rigged_mesh::set_material(std::size_t index, std::shared_ptr<render::material> material)
void skeletal_mesh::set_material(std::size_t index, std::shared_ptr<render::material> material)
{
if (material)
{
@ -70,7 +70,7 @@ void rigged_mesh::set_material(std::size_t index, std::shared_ptr
}
}
void rigged_mesh::reset_materials()
void skeletal_mesh::reset_materials()
{
for (std::size_t i = 0; i < m_operations.size(); ++i)
{
@ -78,7 +78,7 @@ void rigged_mesh::reset_materials()
}
}
void rigged_mesh::update_bounds()
void skeletal_mesh::update_bounds()
{
if (m_model)
{
@ -99,7 +99,7 @@ void rigged_mesh::update_bounds()
}
}
void rigged_mesh::transformed()
void skeletal_mesh::transformed()
{
update_bounds();
@ -110,7 +110,7 @@ void rigged_mesh::transformed()
}
}
void rigged_mesh::render(render::context& ctx) const
void skeletal_mesh::render(render::context& ctx) const
{
const float depth = ctx.camera->get_view_frustum().near().distance(get_translation());
for (auto& operation: m_operations)

src/engine/scene/rigged-mesh.hpp → src/engine/scene/skeletal-mesh.hpp View File

@ -17,13 +17,13 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_SCENE_RIGGED_MESH_HPP
#define ANTKEEPER_SCENE_RIGGED_MESH_HPP
#ifndef ANTKEEPER_SCENE_SKELETAL_MESH_HPP
#define ANTKEEPER_SCENE_SKELETAL_MESH_HPP
#include <engine/scene/object.hpp>
#include <engine/render/model.hpp>
#include <engine/render/operation.hpp>
#include <engine/animation/skeleton-pose.hpp>
#include <engine/animation/animation-pose.hpp>
#include <vector>
namespace scene {
@ -31,20 +31,20 @@ namespace scene {
/**
*
*/
class rigged_mesh: public object<rigged_mesh>
class skeletal_mesh: public object<skeletal_mesh>
{
public:
/**
* Constructs a rigged mesh from a model.
* Constructs a skeletal mesh from a model.
*
* @param model Model from which the rigged mesh will be constructed.
* @param model Model from which the skeletal mesh will be constructed.
*/
explicit rigged_mesh(std::shared_ptr<render::model> model);
explicit skeletal_mesh(std::shared_ptr<render::model> model);
/**
* Constructs a model instance.
*/
rigged_mesh() = default;
skeletal_mesh() = default;
/**
* Sets the model with which this model instance is associated.
@ -81,14 +81,14 @@ public:
void render(render::context& ctx) const override;
/// Returns the pose of the rigged mesh.
/// Returns the animation pose of the skeletal mesh.
/// @{
[[nodiscard]] inline const skeleton_pose& get_pose() const noexcept
[[nodiscard]] inline const animation_pose& get_pose() const noexcept
{
return m_pose;
}
[[nodiscard]] inline skeleton_pose& get_pose() noexcept
[[nodiscard]] inline animation_pose& get_pose() noexcept
{
return m_pose;
}
@ -101,9 +101,9 @@ private:
std::shared_ptr<render::model> m_model;
mutable std::vector<render::operation> m_operations;
aabb_type m_bounds{{0, 0, 0}, {0, 0, 0}};
skeleton_pose m_pose;
animation_pose m_pose;
};
} // namespace scene
#endif // ANTKEEPER_SCENE_RIGGED_MESH_HPP
#endif // ANTKEEPER_SCENE_SKELETAL_MESH_HPP

+ 27
- 29
src/game/ant/ant-morphogenesis.cpp View File

@ -23,11 +23,10 @@
#include <engine/math/quaternion.hpp>
#include <engine/debug/log.hpp>
#include <engine/geom/primitives/box.hpp>
#include <engine/animation/bone.hpp>
#include <unordered_set>
#include <optional>
using bone_index_type = skeleton::bone_index_type;
namespace {
/// Set of pointers to all possible ant skeleton bones.
@ -480,9 +479,8 @@ void build_ant_skeleton(const ant_phenome& phenome, ::skeleton& skeleton, ant_bo
* @param[in] phenome Ant phenome.
* @param[in] bones Set of ant skeleton bones.
* @param[in,out] skeleton Ant skeleton.
* @param[out] bind_pose_ss Skeleton-space bind pose.
*/
void build_ant_bind_pose(const ant_phenome& phenome, const ant_bone_set& bones, ::skeleton& skeleton)
void build_ant_rest_pose(const ant_phenome& phenome, const ant_bone_set& bones, ::skeleton& skeleton)
{
// Get body part skeletons
const ::skeleton& mesosoma_skeleton = phenome.mesosoma->model->get_skeleton();
@ -498,10 +496,10 @@ void build_ant_bind_pose(const ant_phenome& phenome, const ant_bone_set& bones,
auto get_bone_transform = [](const ::skeleton& skeleton, hash::fnv1a32_t bone_name)
{
return skeleton.get_bind_pose().get_relative_transform(*skeleton.get_bone_index(bone_name));
return skeleton.get_rest_pose().get_relative_transform(*skeleton.get_bone_index(bone_name));
};
// Build skeleton bind pose
// Build skeleton rest pose
skeleton.set_bone_transform(*bones.mesosoma, get_bone_transform(mesosoma_skeleton, "mesosoma"));
skeleton.set_bone_transform(*bones.procoxa_l, get_bone_transform(legs_skeleton, "procoxa_l"));
skeleton.set_bone_transform(*bones.profemur_l, get_bone_transform(legs_skeleton, "profemur_l"));
@ -567,7 +565,7 @@ void build_ant_bind_pose(const ant_phenome& phenome, const ant_bone_set& bones,
skeleton.set_bone_transform(*bones.hindwing_r, get_bone_transform(mesosoma_skeleton, "hindwing_r") * get_bone_transform(*hindwings_skeleton, "hindwing_r"));
}
skeleton.update_bind_pose();
skeleton.update_rest_pose();
}
} // namespace
@ -782,9 +780,9 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
ant_bone_set bones;
build_ant_skeleton(phenome, skeleton, bones);
// Build ant bind pose
build_ant_bind_pose(phenome, bones, skeleton);
const auto& bind_pose = skeleton.get_bind_pose();
// Build ant rest pose
build_ant_rest_pose(phenome, bones, skeleton);
const auto& rest_pose = skeleton.get_rest_pose();
// Get number of vertices for each body part
const std::uint32_t mesosoma_vertex_count = (mesosoma_model->get_groups()).front().index_count;
@ -827,30 +825,30 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
auto get_bone_transform = [](const ::skeleton& skeleton, hash::fnv1a32_t bone_name)
{
return skeleton.get_bind_pose().get_relative_transform(*skeleton.get_bone_index(bone_name));
return skeleton.get_rest_pose().get_relative_transform(*skeleton.get_bone_index(bone_name));
};
// Calculate transformations from part space to body space
const math::transform<float> legs_to_body = math::transform<float>::identity();
const math::transform<float> head_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "head");
const math::transform<float> mandible_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "mandible_l");
const math::transform<float> mandible_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "mandible_r");
const math::transform<float> antenna_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "antenna_l");
const math::transform<float> antenna_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "antenna_r");
const math::transform<float> waist_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "petiole");
const math::transform<float> head_to_body = rest_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "head");
const math::transform<float> mandible_l_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "mandible_l");
const math::transform<float> mandible_r_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "mandible_r");
const math::transform<float> antenna_l_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "antenna_l");
const math::transform<float> antenna_r_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "antenna_r");
const math::transform<float> waist_to_body = rest_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "petiole");
math::transform<float> gaster_to_body;
if (phenome.waist->postpetiole_present)
{
gaster_to_body = bind_pose.get_absolute_transform(*bones.postpetiole) * get_bone_transform(waist_skeleton, "gaster");
gaster_to_body = rest_pose.get_absolute_transform(*bones.postpetiole) * get_bone_transform(waist_skeleton, "gaster");
}
else if (phenome.waist->petiole_present)
{
gaster_to_body = bind_pose.get_absolute_transform(*bones.petiole) * get_bone_transform(waist_skeleton, "gaster");
gaster_to_body = rest_pose.get_absolute_transform(*bones.petiole) * get_bone_transform(waist_skeleton, "gaster");
}
else
{
gaster_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(waist_skeleton, "gaster");
gaster_to_body = rest_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(waist_skeleton, "gaster");
}
math::transform<float> sting_to_body;
@ -863,8 +861,8 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
math::transform<float> eye_r_to_body;
if (phenome.eyes->present)
{
eye_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "eye_l");
eye_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "eye_r");
eye_l_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "eye_l");
eye_r_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "eye_r");
}
math::transform<float> ocellus_l_to_body;
@ -872,12 +870,12 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
math::transform<float> ocellus_m_to_body;
if (phenome.ocelli->lateral_ocelli_present)
{
ocellus_l_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_l");
ocellus_r_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_r");
ocellus_l_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_l");
ocellus_r_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_r");
}
if (phenome.ocelli->median_ocellus_present)
{
ocellus_m_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_m");
ocellus_m_to_body = rest_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_m");
}
math::transform<float> forewing_l_to_body;
@ -886,10 +884,10 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
math::transform<float> hindwing_r_to_body;
if (phenome.wings->present)
{
forewing_l_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "forewing_l");
forewing_r_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "forewing_r");
hindwing_l_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "hindwing_l");
hindwing_r_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "hindwing_r");
forewing_l_to_body = rest_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "forewing_l");
forewing_r_to_body = rest_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "forewing_r");
hindwing_l_to_body = rest_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "hindwing_l");
hindwing_r_to_body = rest_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(mesosoma_skeleton, "hindwing_r");
}
// Build legs vertex reskin map

+ 7
- 7
src/game/states/nest-selection-state.cpp View File

@ -71,7 +71,7 @@
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/state-machine.hpp>
#include <engine/scene/static-mesh.hpp>
#include <engine/scene/rigged-mesh.hpp>
#include <engine/scene/skeletal-mesh.hpp>
nest_selection_state::nest_selection_state(::game& ctx):
game_state(ctx)
@ -128,11 +128,11 @@ nest_selection_state::nest_selection_state(::game& ctx):
// Create worker entity(s)
auto worker_rigged_mesh = std::make_unique<scene::rigged_mesh>(worker_model);
auto worker_skeletal_mesh = std::make_unique<scene::skeletal_mesh>(worker_model);
const auto& worker_skeleton = worker_model->get_skeleton();
const auto& worker_bind_pose = worker_skeleton.get_bind_pose();
auto& worker_pose = worker_rigged_mesh->get_pose();
const auto& worker_rest_pose = worker_skeleton.get_rest_pose();
auto& worker_pose = worker_skeletal_mesh->get_pose();
const float mandibles_open_angle = math::radians(32.0f);
auto open_left_mandible = math::transform<float>::identity();
@ -143,8 +143,8 @@ nest_selection_state::nest_selection_state(::game& ctx):
auto mandible_l_bone = *worker_skeleton.get_bone_index("mandible_l");
auto mandible_r_bone = *worker_skeleton.get_bone_index("mandible_r");
worker_pose.set_relative_transform(mandible_l_bone, worker_bind_pose.get_relative_transform(mandible_l_bone) * open_left_mandible);
worker_pose.set_relative_transform(mandible_r_bone, worker_bind_pose.get_relative_transform(mandible_r_bone) * open_right_mandible);
worker_pose.set_relative_transform(mandible_l_bone, worker_rest_pose.get_relative_transform(mandible_l_bone) * open_left_mandible);
worker_pose.set_relative_transform(mandible_r_bone, worker_rest_pose.get_relative_transform(mandible_r_bone) * open_right_mandible);
worker_pose.update();
worker_ant_eid = ctx.entity_registry->create();
@ -153,7 +153,7 @@ nest_selection_state::nest_selection_state(::game& ctx):
worker_transform_component.local.translation = {0, 0.5f, -4};
worker_transform_component.world = worker_transform_component.local;
ctx.entity_registry->emplace<transform_component>(worker_ant_eid, worker_transform_component);
ctx.entity_registry->emplace<scene_component>(worker_ant_eid, std::move(worker_rigged_mesh), std::uint8_t{1});
ctx.entity_registry->emplace<scene_component>(worker_ant_eid, std::move(worker_skeletal_mesh), std::uint8_t{1});

Loading…
Cancel
Save