Browse Source

Revise skeleton and skeleton poses. Add rigged mesh scene object

master
C. J. Howard 1 year ago
parent
commit
cb9f6838cd
25 changed files with 1191 additions and 683 deletions
  1. +0
    -124
      src/engine/animation/bone.hpp
  2. +0
    -55
      src/engine/animation/pose.cpp
  3. +0
    -59
      src/engine/animation/pose.hpp
  4. +57
    -0
      src/engine/animation/skeleton-bind-pose.cpp
  5. +42
    -0
      src/engine/animation/skeleton-bind-pose.hpp
  6. +80
    -0
      src/engine/animation/skeleton-pose.cpp
  7. +138
    -0
      src/engine/animation/skeleton-pose.hpp
  8. +29
    -0
      src/engine/animation/skeleton.cpp
  9. +109
    -11
      src/engine/animation/skeleton.hpp
  10. +43
    -0
      src/engine/geom/primitives/point.hpp
  11. +24
    -9
      src/engine/gl/vertex-array.cpp
  12. +1
    -1
      src/engine/math/interpolation.hpp
  13. +0
    -14
      src/engine/math/math.hpp
  14. +33
    -33
      src/engine/math/projection.hpp
  15. +20
    -20
      src/engine/render/model.cpp
  16. +1
    -2
      src/engine/render/operation.hpp
  17. +7
    -0
      src/engine/render/passes/material-pass.cpp
  18. +2
    -0
      src/engine/render/passes/material-pass.hpp
  19. +3
    -3
      src/engine/render/passes/shadow-map-pass.cpp
  20. +123
    -0
      src/engine/scene/rigged-mesh.cpp
  21. +109
    -0
      src/engine/scene/rigged-mesh.hpp
  22. +0
    -3
      src/engine/scene/static-mesh.cpp
  23. +3
    -17
      src/engine/scene/static-mesh.hpp
  24. +345
    -329
      src/game/ant/ant-morphogenesis.cpp
  25. +22
    -3
      src/game/states/nest-selection-state.cpp

+ 0
- 124
src/engine/animation/bone.hpp View File

@ -1,124 +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/>.
*/
#ifndef ANTKEEPER_ANIMATION_BONE_HPP
#define ANTKEEPER_ANIMATION_BONE_HPP
#include <cstdint>
/**
* Skeletal animation bone identifier, consisting of a bone index in the lower half, and a parent bone index in the upper half.
*/
using bone = std::uint32_t;
/// Mask to extract the index of a bone.
inline constexpr bone bone_index_mask = 0xffff;
/**
* Bone index comparison function object.
*/
struct bone_index_compare
{
/**
* Compares the indices of two bones.
*
* @param lhs First bone.
* @param rhs Second bone.
*
* @return Comparison result.
*/
[[nodiscard]] inline bool operator()(const bone& lhs, const bone& rhs) const noexcept
{
return (lhs & bone_index_mask) < (rhs & bone_index_mask);
}
};
/**
* Constructs a bone identifier.
*
* @param index Index of the bone.
* @param parent_index Index of the parent bone.
*
* @return Bone identifier.
*/
[[nodiscard]] inline bone make_bone(std::uint16_t index, std::uint16_t parent_index) noexcept
{
return (static_cast<std::uint32_t>(parent_index) << 16) | index;
}
/**
* Sets the parent of a bone.
*
* @param[out] child Bone to reparent.
* @param[in] parent New parent bone.
*/
inline void reparent_bone(bone& child, bone parent) noexcept
{
child = ((parent & bone_index_mask) << 16) | (child & bone_index_mask);
}
/**
* Constructs an orphan bone identifier.
*
* @param index Index of the orphan bone.
*
* @return Orphan bone identifier.
*/
[[nodiscard]] inline bone make_bone(std::uint16_t index) noexcept
{
return make_bone(index, index);
}
/**
* Returns the index of a bone.
*
* @param x Bone identifier.
*
* @return Index of the bone.
*/
[[nodiscard]] inline std::uint16_t bone_index(bone x) noexcept
{
return static_cast<std::uint16_t>(x & bone_index_mask);
}
/**
* Returns the parent index of a bone.
*
* @param x Bone identifier.
*
* @return Index of the parent bone.
*/
[[nodiscard]] inline std::uint16_t bone_parent_index(bone x) noexcept
{
return static_cast<std::uint16_t>(x >> 16);
}
/**
* Returns `true` if a bone has a parent, `false` otherwise.
*
* @param x Bone identifier.
*
* @return Bone parent status.
*/
[[nodiscard]] inline bool bone_has_parent(bone x) noexcept
{
return (x & bone_index_mask) != (x >> 16);
}
#endif // ANTKEEPER_ANIMATION_BONE_HPP

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

@ -1,55 +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/pose.hpp>
void concatenate(const pose& bone_space, pose& skeleton_space)
{
for (auto&& [bone, transform]: bone_space)
{
auto parent_index = bone_parent_index(bone);
if (parent_index != bone_index(bone))
{
auto parent = skeleton_space.find(parent_index);
skeleton_space[bone] = (parent != skeleton_space.end()) ? parent->second * transform : transform;
}
else
{
skeleton_space[bone] = transform;
}
}
}
void inverse(const pose& x, pose& y)
{
for (auto&& [bone, transform]: x)
{
y[bone] = math::inverse(transform);
}
}
void matrix_palette(const pose& inverse_bind_pose, const pose& pose, float4x4* palette)
{
for (auto&& [bone, transform]: pose)
{
auto index = ::bone_index(bone);
palette[index] = (inverse_bind_pose.at(bone) * transform).matrix();
}
}

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

@ -1,59 +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/>.
*/
#ifndef ANTKEEPER_ANIMATION_POSE_HPP
#define ANTKEEPER_ANIMATION_POSE_HPP
#include <engine/animation/bone.hpp>
#include <engine/math/transform.hpp>
#include <engine/utility/fundamental-types.hpp>
#include <map>
/**
* Skeletal animation pose.
*/
typedef std::map<bone, math::transform<float>, bone_index_compare> pose;
/**
* Transforms a pose from bone-space into skeleton-space.
*
* @param[in] bone_space Bone-space pose.
* @param[out] skeleton_space Skeleton-space pose.
*
* @warning If the index of any child bone is greater than its parent index, the concatenated pose may be incorrect.
*/
void concatenate(const pose& bone_space, pose& skeleton_space);
/**
* Inverses each transform in a pose.
*
* @param[in] x Input pose.
* @param[out] y Output pose.
*/
void inverse(const pose& x, pose& y);
/**
* Generates a skinning matrix palette from a pose.
*
* @param inverse_bind_pose Inverse of the skeleton-space bind pose.
* @param pose Bone-space Skeleton-space pose.
*/
void matrix_palette(const pose& inverse_bind_pose, const pose& pose, float4x4* palette);
#endif // ANTKEEPER_ANIMATION_POSE_HPP

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

@ -0,0 +1,57 @@
/*
* 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();
}
}

+ 42
- 0
src/engine/animation/skeleton-bind-pose.hpp View File

@ -0,0 +1,42 @@
/*
* 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_SKELETON_BIND_POSE_HPP
#define ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP
#include <engine/animation/skeleton-pose.hpp>
/**
* Skeleton bind pose.
*/
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;
};
#endif // ANTKEEPER_ANIMATION_SKELETON_BIND_POSE_HPP

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

@ -0,0 +1,80 @@
/*
* 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();
}

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

@ -0,0 +1,138 @@
/*
* 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_SKELETON_POSE_HPP
#define ANTKEEPER_ANIMATION_SKELETON_POSE_HPP
#include <engine/math/transform.hpp>
#include <engine/math/matrix.hpp>
#include <cstdint>
#include <vector>
class skeleton;
/**
* Skeleton pose.
*/
class skeleton_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.
*
* @param skeleton Skeleton with which to associate the pose.
*/
explicit skeleton_pose(const skeleton& skeleton);
/// Constructs an empty skeleton pose.
skeleton_pose() noexcept = default;
/**
* Updates the absolute transforms and matrix palette of the pose.
*/
virtual void update();
/**
* Resets all bone transforms to identity transforms.
*/
virtual void reset_bone_transforms();
/**
* Sets the number of bones in the pose.
*
* @param skeleton Skeleton with which to associate the pose.
*/
void set_skeleton(const skeleton* skeleton);
/**
* Sets the relative transform describing a bone pose.
*
* @param index Index of a bone.
* @param transform Relative transform describing the bone pose.
*/
inline void set_relative_transform(bone_index_type index, const bone_transform_type& transform)
{
m_relative_transforms[index] = transform;
}
/// Returns the skeleton with which the pose is associated.
[[nodiscard]] inline const skeleton* get_skeleton() const noexcept
{
return m_skeleton;
}
/**
* Returns the relative transform describing a bone pose.
*
* @param index Index of a bone.
*
* @return Relative transform describing the bone pose.
*/
[[nodiscard]] inline const bone_transform_type& get_relative_transform(bone_index_type index) const
{
return m_relative_transforms[index];
}
/**
* Returns the absolute transform describing a bone pose.
*
* @param index Index of a bone.
*
* @return Absolute transform describing the bone pose.
*/
[[nodiscard]] inline const bone_transform_type& get_absolute_transform(bone_index_type index) const
{
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};
/// Relative ransforms for each bone in a skeleton.
std::vector<bone_transform_type> m_relative_transforms;
/// 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

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

@ -19,3 +19,32 @@
#include <engine/animation/skeleton.hpp>
skeleton::skeleton(std::size_t bone_count):
m_bone_parents(bone_count, 0),
m_bind_pose(*this)
{}
skeleton::skeleton():
skeleton(0)
{}
void skeleton::update_bind_pose()
{
m_bind_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);
}
std::optional<typename skeleton::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())
{
return i->second;
}
return std::nullopt;
}

+ 109
- 11
src/engine/animation/skeleton.hpp View File

@ -20,28 +20,126 @@
#ifndef ANTKEEPER_ANIMATION_SKELETON_HPP
#define ANTKEEPER_ANIMATION_SKELETON_HPP
#include <engine/animation/bone.hpp>
#include <engine/animation/pose.hpp>
#include <engine/animation/skeleton-bind-pose.hpp>
#include <engine/utility/hash/fnv1a.hpp>
#include <string>
#include <unordered_map>
#include <vector>
#include <optional>
#include <cstdint>
/**
* Skeletal animation skeleton.
*/
struct skeleton
class skeleton
{
/// Bone-space bind pose of the skeleton.
pose bind_pose;
public:
/// Bone index type.
using bone_index_type = std::uint16_t;
/// Inverse skeleton-space bind pose of the skeleton.
pose inverse_bind_pose;
/// Bone transform type.
using bone_transform_type = skeleton_pose::bone_transform_type;
std::vector<bone> bones;
/**
* Constructs a skeleton.
*
* @param bone_count Number of bones in the skeleton.
*/
explicit skeleton(std::size_t bone_count);
/// Maps bone names to bone identifiers.
std::unordered_map<hash::fnv1a32_t, bone> bone_map;
/// Constructs an empty skeleton.
skeleton();
/**
* Updates the bind pose of the skeleton.
*/
void update_bind_pose();
/**
* Sets the number of bones in the skeleton.
*
* @param size Number of bones in the skeleton.
*/
void set_bone_count(std::size_t size);
/**
* Sets the parent of a bone.
*
* @param child_index Index of the child bone.
* @param parent_index Index of the parent bone.
*
* @warning The index of a child bone must be greater than the index of its parent. Failure to properly index bones will result in incorrect pose concatenation.
*/
inline void set_bone_parent(bone_index_type child_index, bone_index_type parent_index)
{
m_bone_parents[child_index] = parent_index;
}
/**
* Sets the transform of a bone, relative to its parent bone.
*
* @param index Index of a bone.
* @param transform Bone transform, relative to the parent bone.
*/
inline void set_bone_transform(bone_index_type index, const bone_transform_type& transform)
{
m_bind_pose.set_relative_transform(index, transform);
}
/**
* Sets the name of a bone.
*
* @param index Index of a bone.
* @param name Name of the bone.
*/
inline void set_bone_name(bone_index_type index, hash::fnv1a32_t name)
{
m_bone_map[name] = index;
}
/**
* Returns the number of bones in the skeleton.
*/
[[nodiscard]] inline std::size_t get_bone_count() const noexcept
{
return m_bone_parents.size();
}
/**
* Returns the index of the parent of a bone.
*
* @param child_index Index of the child bone.
*
* @return Index of the child bone's parent, or @p index if the child bone has no parent.
*/
[[nodiscard]] inline bone_index_type get_bone_parent(bone_index_type child_index) const
{
return m_bone_parents[child_index];
}
/**
* Finds the index of a bone from the bone's name.
*
* @param name Name of a bone.
*
* @return Index of the bone, or `std::nullopt` if no bone with the given name was found.
*/
[[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
{
return m_bind_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;
/// Map of bone names to bone indices.
std::unordered_map<hash::fnv1a32_t, bone_index_type> m_bone_map;
};
#endif // ANTKEEPER_ANIMATION_SKELETON_HPP

+ 43
- 0
src/engine/geom/primitives/point.hpp View File

@ -0,0 +1,43 @@
/*
* 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_GEOM_PRIMITIVES_POINT_HPP
#define ANTKEEPER_GEOM_PRIMITIVES_POINT_HPP
#include <engine/math/vector.hpp>
namespace geom {
namespace primitives {
/**
* *n*-dimensional point.
*
* @tparam T Real type.
* @tparam N Number of dimensions.
*/
template <class T, std::size_t N>
using point = vector<T, N>;
} // namespace primitives
using namespace primitives;
} // namespace geom
#endif // ANTKEEPER_GEOM_PRIMITIVES_POINT_HPP

+ 24
- 9
src/engine/gl/vertex-array.cpp View File

@ -65,15 +65,30 @@ void vertex_array::bind(attribute_location_type location, const vertex_attribute
GLenum gl_type = vertex_attribute_type_lut[static_cast<std::size_t>(attribute.type)];
glBindVertexArray(gl_array_id);
glBindBuffer(GL_ARRAY_BUFFER, attribute.buffer->gl_buffer_id);
glVertexAttribPointer
(
static_cast<GLuint>(location),
static_cast<GLint>(attribute.components),
gl_type,
GL_FALSE,
static_cast<GLsizei>(attribute.stride),
reinterpret_cast<const GLvoid*>(attribute.offset)
);
if (gl_type == GL_FLOAT || gl_type == GL_HALF_FLOAT || gl_type == GL_DOUBLE)
{
glVertexAttribPointer
(
static_cast<GLuint>(location),
static_cast<GLint>(attribute.components),
gl_type,
GL_FALSE,
static_cast<GLsizei>(attribute.stride),
reinterpret_cast<const GLvoid*>(attribute.offset)
);
}
else
{
glVertexAttribIPointer
(
static_cast<GLuint>(location),
static_cast<GLint>(attribute.components),
gl_type,
static_cast<GLsizei>(attribute.stride),
reinterpret_cast<const GLvoid*>(attribute.offset)
);
}
glEnableVertexAttribArray(static_cast<GLuint>(location));
}

+ 1
- 1
src/engine/math/interpolation.hpp View File

@ -38,7 +38,7 @@ namespace math {
* @tparam S Scalar type.
*/
template <typename T, typename S = float>
[[nodiscard]] constexpr T lerp(const T& x, const T& y, S a)
[[nodiscard]] constexpr T lerp(const T& x, const T& y, S a) noexcept
{
return x + (y - x) * a;
}

+ 0
- 14
src/engine/math/math.hpp View File

@ -23,18 +23,4 @@
/// Mathematical functions and data types.
namespace math {}
#include <engine/math/vector.hpp>
#include <engine/math/matrix.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/math/se3.hpp>
#include <engine/math/transform.hpp>
#include <engine/math/angles.hpp>
#include <engine/math/numbers.hpp>
#include <engine/math/quadrature.hpp>
#include <engine/math/interpolation.hpp>
#include <engine/math/map.hpp>
#include <engine/math/projection.hpp>
#endif // ANTKEEPER_MATH_HPP

+ 33
- 33
src/engine/math/projection.hpp View File

@ -58,7 +58,7 @@ template
}
/**
* Creates an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
* Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
*
* @param left Signed distance to the left clipping plane.
* @param right Signed distance to the right clipping plane.
@ -73,16 +73,16 @@ template
[[nodiscard]] constexpr matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far) noexcept
{
return
{{
{T(2) / (right - left), T(0), T(0), T(0)},
{T(0), T(2) / (top - bottom), T(0), T(0)},
{T(0), T(0), T(-2) / (z_far - z_near), T(0)},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((z_far + z_near) / (z_far - z_near)), T(1)}
}};
{{
{T{2} / (right - left), T{0}, T{0}, T{0}},
{T{0}, T{2} / (top - bottom), T{0}, T{0}},
{T{0}, T{0}, T{-2} / (z_far - z_near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((z_far + z_near) / (z_far - z_near)), T{1}}
}};
}
/**
* Creates an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
* Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
*
* @param left Signed distance to the left clipping plane.
* @param right Signed distance to the right clipping plane.
@ -97,16 +97,16 @@ template
[[nodiscard]] constexpr matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far) noexcept
{
return
{{
{T(2) / (right - left), T(0), T(0), T(0)},
{T(0), T(2) / (top - bottom), T(0), T(0)},
{T(0), T(0), T(-1) / (z_far - z_near), T(0)},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -z_near / (z_far - z_near), T(1)}
}};
{{
{T{2} / (right - left), T{0}, T{0}, T{0}},
{T{0}, T{2} / (top - bottom), T{0}, T{0}},
{T{0}, T{0}, T{-1} / (z_far - z_near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -z_near / (z_far - z_near), T{1}}
}};
}
/**
* Creates a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
* Constructs a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
*
* @param vertical_fov Vertical field of view angle, in radians.
* @param aspect_ratio Aspect ratio which determines the horizontal field of view.
@ -118,20 +118,20 @@ template
template <class T>
[[nodiscard]] matrix<T, 4, 4> perspective(T vertical_fov, T aspect_ratio, T z_near, T z_far)
{
T half_fov = vertical_fov * T(0.5);
T f = std::cos(half_fov) / std::sin(half_fov);
const T half_fov = vertical_fov * T{0.5};
const T f = std::cos(half_fov) / std::sin(half_fov);
return
{{
{f / aspect_ratio, T(0), T(0), T(0)},
{T(0), f, T(0), T(0)},
{T(0), T(0), (z_far + z_near) / (z_near - z_far), T(-1)},
{T(0), T(0), (T(2) * z_far * z_near) / (z_near - z_far), T(0)}
}};
{{
{f / aspect_ratio, T{0}, T{0}, T{0}},
{T{0}, f, T{0}, T{0}},
{T{0}, T{0}, (z_far + z_near) / (z_near - z_far), T{-1}},
{T{0}, T{0}, (T{2} * z_far * z_near) / (z_near - z_far), T{0}}
}};
}
/**
* Creates a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
* Constructs a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
*
* @param vertical_fov Vertical field of view angle, in radians.
* @param aspect_ratio Aspect ratio which determines the horizontal field of view.
@ -143,16 +143,16 @@ template
template <class T>
[[nodiscard]] matrix<T, 4, 4> perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z_far)
{
T half_fov = vertical_fov * T(0.5);
T f = std::cos(half_fov) / std::sin(half_fov);
const T half_fov = vertical_fov * T{0.5};
const T f = std::cos(half_fov) / std::sin(half_fov);
return
{{
{f / aspect_ratio, T(0), T(0), T(0)},
{T(0), f, T(0), T(0)},
{T(0), T(0), z_far / (z_near - z_far), T(-1)},
{T(0), T(0), -(z_far * z_near) / (z_far - z_near), T(0)}
}};
{{
{f / aspect_ratio, T{0}, T{0}, T{0}},
{T{0}, f, T{0}, T{0}},
{T{0}, T{0}, z_far / (z_near - z_far), T{-1}},
{T{0}, T{0}, -(z_far * z_near) / (z_far - z_near), T{0}}
}};
}
} // namespace math

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

@ -213,7 +213,7 @@ std::unique_ptr resource_loader::load(::resource_m
}
if (vertex_format_flags & vertex_attribute_bone)
{
attribute.type = gl::vertex_attribute_type::uint_16;
attribute.type = gl::vertex_attribute_type::uint_32;
attribute.components = bones_per_vertex;
vao.bind(render::vertex_attribute::bone_index, attribute);
attribute.offset += sizeof(std::uint32_t) * attribute.components;
@ -235,7 +235,7 @@ std::unique_ptr resource_loader::load(::resource_m
attribute.type = gl::vertex_attribute_type::float_32;
attribute.components = 3;
vao.bind(render::vertex_attribute::target, attribute);
attribute.offset += sizeof(float) * attribute.components;
//attribute.offset += sizeof(float) * attribute.components;
}
// Read model bounds
@ -283,31 +283,27 @@ std::unique_ptr resource_loader::load(::resource_m
if (vertex_format_flags & vertex_attribute_bone)
{
::skeleton& skeleton = model->get_skeleton();
pose& bind_pose = skeleton.bind_pose;
// Read bone count
std::uint16_t bone_count = 0;
ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&bone_count), 1);
// Resize skeleton
skeleton.set_bone_count(bone_count);
// Read bones
for (std::uint16_t i = 0; i < bone_count; ++i)
{
// Read bone key
hash::fnv1a32_t bone_key = {};
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&bone_key), 1);
// Read parent bone index
std::uint16_t parent_bone_index = i;
ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&parent_bone_index), 1);
// Read bone name
hash::fnv1a32_t bone_name = {};
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&bone_name), 1);
// Construct bone identifier
::bone bone = make_bone(i, parent_bone_index);
// Read bone parent index
std::uint16_t bone_parent_index = i;
ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&bone_parent_index), 1);
// Add bone to bone map
skeleton.bone_map[bone_key] = bone;
// Get reference to the bone's bind pose transform
auto& bone_transform = bind_pose[bone];
// Construct bone transform
skeleton::bone_transform_type bone_transform;
// Read bone translation
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(bone_transform.translation.data()), 3);
@ -322,11 +318,15 @@ std::unique_ptr resource_loader::load(::resource_m
// Read bone length
float bone_length = 0.0f;
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&bone_length), 1);
// Set bone properties
skeleton.set_bone_name(i, bone_name);
skeleton.set_bone_parent(i, bone_parent_index);
skeleton.set_bone_transform(i, bone_transform);
}
// Calculate inverse skeleton-space bind pose
::concatenate(skeleton.bind_pose, skeleton.inverse_bind_pose);
::inverse(skeleton.inverse_bind_pose, skeleton.inverse_bind_pose);
// Update skeleton
skeleton.update_bind_pose();
}
return model;

+ 1
- 2
src/engine/render/operation.hpp View File

@ -21,7 +21,6 @@
#define ANTKEEPER_RENDER_OPERATION_HPP
#include <engine/utility/fundamental-types.hpp>
#include <engine/animation/pose.hpp>
#include <engine/gl/vertex-array.hpp>
#include <engine/gl/drawing-mode.hpp>
#include <engine/render/material.hpp>
@ -46,7 +45,7 @@ struct operation
float depth{0.0f};
std::size_t instance_count{0};
std::span<const float4x4> skinning_palette{};
std::span<const float4x4> matrix_palette{};
};
} // namespace render

+ 7
- 0
src/engine/render/passes/material-pass.cpp View File

@ -267,6 +267,7 @@ void material_pass::render(render::context& ctx)
// Update geometry-dependent shader variables
model = &operation->transform;
matrix_palette = operation->matrix_palette;
for (const auto& command: active_cache_entry->geometry_command_buffer)
{
command();
@ -722,6 +723,12 @@ void material_pass::build_geometry_command_buffer(std::vector
{
command_buffer.emplace_back([&, model_view_projection_var](){model_view_projection_var->update((*view_projection) * (*model));});
}
// Update matrix palette variable
if (auto matrix_palette_var = shader_program.variable("matrix_palette"))
{
command_buffer.emplace_back([&, matrix_palette_var](){matrix_palette_var->update(matrix_palette);});
}
}
void material_pass::build_material_command_buffer(std::vector<std::function<void()>>& command_buffer, const gl::shader_program& shader_program, const material& material) const

+ 2
- 0
src/engine/render/passes/material-pass.hpp View File

@ -28,6 +28,7 @@
#include <engine/gl/texture-2d.hpp>
#include <functional>
#include <unordered_map>
#include <span>
class resource_manager;
@ -131,6 +132,7 @@ private:
// Geometry
const float4x4* model;
std::span<const float4x4> matrix_palette;
/// Hash of the lighting state.
std::size_t lighting_state_hash;

+ 3
- 3
src/engine/render/passes/shadow-map-pass.cpp View File

@ -288,7 +288,7 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render::
}
// Switch shader programs if necessary
gl::shader_program* shader_program = (operation->skinning_palette.empty()) ? unskinned_shader_program.get() : skinned_shader_program.get();
gl::shader_program* shader_program = (operation->matrix_palette.empty()) ? unskinned_shader_program.get() : skinned_shader_program.get();
if (active_shader_program != shader_program)
{
active_shader_program = shader_program;
@ -316,8 +316,8 @@ void shadow_map_pass::render_csm(const scene::directional_light& light, render::
bool operation_compare(const render::operation* a, const render::operation* b)
{
const bool skinned_a = !a->skinning_palette.empty();
const bool skinned_b = !b->skinning_palette.empty();
const bool skinned_a = !a->matrix_palette.empty();
const bool skinned_b = !b->matrix_palette.empty();
const bool two_sided_a = (a->material) ? a->material->is_two_sided() : false;
const bool two_sided_b = (b->material) ? b->material->is_two_sided() : false;

+ 123
- 0
src/engine/scene/rigged-mesh.cpp View File

@ -0,0 +1,123 @@
/*
* 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/scene/rigged-mesh.hpp>
#include <engine/scene/camera.hpp>
namespace scene {
rigged_mesh::rigged_mesh(std::shared_ptr<render::model> model)
{
set_model(model);
}
void rigged_mesh::set_model(std::shared_ptr<render::model> model)
{
m_model = model;
if (m_model)
{
m_pose.set_skeleton(&model->get_skeleton());
m_operations.resize(m_model->get_groups().size());
for (std::size_t i = 0; i < m_operations.size(); ++i)
{
const auto& group = m_model->get_groups()[i];
auto& operation = m_operations[i];
operation.vertex_array = m_model->get_vertex_array().get();
operation.drawing_mode = group.drawing_mode;
operation.start_index = group.start_index;
operation.index_count = group.index_count;
operation.material = group.material;
operation.matrix_palette = m_pose.get_matrix_palette();
}
}
else
{
m_operations.clear();
}
transformed();
}
void rigged_mesh::set_material(std::size_t index, std::shared_ptr<render::material> material)
{
if (material)
{
m_operations[index].material = material;
}
else
{
m_operations[index].material = m_model->get_groups()[index].material;
}
}
void rigged_mesh::reset_materials()
{
for (std::size_t i = 0; i < m_operations.size(); ++i)
{
m_operations[i].material = m_model->get_groups()[i].material;
}
}
void rigged_mesh::update_bounds()
{
if (m_model)
{
// Get model bounds
const auto& model_bounds = m_model->get_bounds();
// Naive algorithm: transform each corner of the model AABB
m_bounds.min = {std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()};
m_bounds.max = {-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity()};
for (std::size_t i = 0; i < 8; ++i)
{
m_bounds.extend(get_transform() * model_bounds.corner(i));
}
}
else
{
m_bounds = {get_translation(), get_translation()};
}
}
void rigged_mesh::transformed()
{
update_bounds();
const float4x4 transform_matrix = get_transform().matrix();
for (auto& operation: m_operations)
{
operation.transform = transform_matrix;
}
}
void rigged_mesh::render(render::context& ctx) const
{
const float depth = ctx.camera->get_view_frustum().near().distance(get_translation());
for (auto& operation: m_operations)
{
operation.depth = depth;
ctx.operations.push_back(&operation);
}
}
} // namespace scene

+ 109
- 0
src/engine/scene/rigged-mesh.hpp View File

@ -0,0 +1,109 @@
/*
* 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_SCENE_RIGGED_MESH_HPP
#define ANTKEEPER_SCENE_RIGGED_MESH_HPP
#include <engine/scene/object.hpp>
#include <engine/render/model.hpp>
#include <engine/render/operation.hpp>
#include <engine/animation/skeleton-pose.hpp>
#include <vector>
namespace scene {
/**
*
*/
class rigged_mesh: public object<rigged_mesh>
{
public:
/**
* Constructs a rigged mesh from a model.
*
* @param model Model from which the rigged mesh will be constructed.
*/
explicit rigged_mesh(std::shared_ptr<render::model> model);
/**
* Constructs a model instance.
*/
rigged_mesh() = default;
/**
* Sets the model with which this model instance is associated.
*
* @warning This will reset all overwritten materials.
*/
void set_model(std::shared_ptr<render::model> model);
/**
* Overwrites the material of a model group for this model instance.
*
* @param index Index of a model group.
* @param material Pointer to the material which should overwrite the model group's material. A value of `nullptr` indicates the material will not be overwritten.
*/
void set_material(std::size_t index, std::shared_ptr<render::material> material);
/**
* Resets all overwritten materials.
*/
void reset_materials();
[[nodiscard]] inline const aabb_type& get_bounds() const noexcept override
{
return m_bounds;
}
/**
* Returns the model of the model instance.
*/
[[nodiscard]] inline const std::shared_ptr<render::model>& get_model() const noexcept
{
return m_model;
}
void render(render::context& ctx) const override;
/// Returns the pose of the rigged mesh.
/// @{
[[nodiscard]] inline const skeleton_pose& get_pose() const noexcept
{
return m_pose;
}
[[nodiscard]] inline skeleton_pose& get_pose() noexcept
{
return m_pose;
}
/// @}
private:
void update_bounds();
void transformed() override;
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;
};
} // namespace scene
#endif // ANTKEEPER_SCENE_RIGGED_MESH_HPP

+ 0
- 3
src/engine/scene/static-mesh.cpp View File

@ -47,13 +47,10 @@ void static_mesh::set_model(std::shared_ptr model)
operation.index_count = group.index_count;
operation.material = group.material;
}
::concatenate(m_model->get_skeleton().bind_pose, m_pose);
}
else
{
m_operations.clear();
m_pose.clear();
}
transformed();

+ 3
- 17
src/engine/scene/static-mesh.hpp View File

@ -21,7 +21,6 @@
#define ANTKEEPER_SCENE_STATIC_MESH_HPP
#include <engine/scene/object.hpp>
#include <engine/animation/pose.hpp>
#include <engine/render/model.hpp>
#include <engine/render/operation.hpp>
#include <vector>
@ -47,7 +46,9 @@ public:
static_mesh() = default;
/**
* Sets the model with which this model instance is associated. This will reset the pose and all overwritten materials.
* Sets the model with which this model instance is associated.
*
* @warning This will reset all overwritten materials.
*/
void set_model(std::shared_ptr<render::model> model);
@ -77,20 +78,6 @@ public:
return m_model;
}
/**
* Returns the skeletal animation pose of this model instance.
*/
/// @{
[[nodiscard]] inline const pose& get_pose() const noexcept
{
return m_pose;
}
[[nodiscard]] inline pose& get_pose() noexcept
{
return m_pose;
}
/// @}
void render(render::context& ctx) const override;
private:
@ -99,7 +86,6 @@ private:
std::shared_ptr<render::model> m_model;
mutable std::vector<render::operation> m_operations;
::pose m_pose;
aabb_type m_bounds{{0, 0, 0}, {0, 0, 0}};
};

+ 345
- 329
src/game/ant/ant-morphogenesis.cpp View File

@ -24,52 +24,55 @@
#include <engine/debug/log.hpp>
#include <engine/geom/primitives/box.hpp>
#include <unordered_set>
#include <optional>
using bone_index_type = skeleton::bone_index_type;
namespace {
/// Set of pointers to all possible ant skeleton bones.
struct ant_bone_set
{
::bone* mesosoma{nullptr};
::bone* procoxa_l{nullptr};
::bone* profemur_l{nullptr};
::bone* protibia_l{nullptr};
::bone* protarsus_l{nullptr};
::bone* procoxa_r{nullptr};
::bone* profemur_r{nullptr};
::bone* protibia_r{nullptr};
::bone* protarsus_r{nullptr};
::bone* mesocoxa_l{nullptr};
::bone* mesofemur_l{nullptr};
::bone* mesotibia_l{nullptr};
::bone* mesotarsus_l{nullptr};
::bone* mesocoxa_r{nullptr};
::bone* mesofemur_r{nullptr};
::bone* mesotibia_r{nullptr};
::bone* mesotarsus_r{nullptr};
::bone* metacoxa_l{nullptr};
::bone* metafemur_l{nullptr};
::bone* metatibia_l{nullptr};
::bone* metatarsus_l{nullptr};
::bone* metacoxa_r{nullptr};
::bone* metafemur_r{nullptr};
::bone* metatibia_r{nullptr};
::bone* metatarsus_r{nullptr};
::bone* head{nullptr};
::bone* mandible_l{nullptr};
::bone* mandible_r{nullptr};
::bone* antennomere1_l{nullptr};
::bone* antennomere2_l{nullptr};
::bone* antennomere1_r{nullptr};
::bone* antennomere2_r{nullptr};
::bone* petiole{nullptr};
::bone* postpetiole{nullptr};
::bone* gaster{nullptr};
::bone* sting{nullptr};
::bone* forewing_l{nullptr};
::bone* forewing_r{nullptr};
::bone* hindwing_l{nullptr};
::bone* hindwing_r{nullptr};
std::optional<bone_index_type> mesosoma;
std::optional<bone_index_type> procoxa_l;
std::optional<bone_index_type> profemur_l;
std::optional<bone_index_type> protibia_l;
std::optional<bone_index_type> protarsus_l;
std::optional<bone_index_type> procoxa_r;
std::optional<bone_index_type> profemur_r;
std::optional<bone_index_type> protibia_r;
std::optional<bone_index_type> protarsus_r;
std::optional<bone_index_type> mesocoxa_l;
std::optional<bone_index_type> mesofemur_l;
std::optional<bone_index_type> mesotibia_l;
std::optional<bone_index_type> mesotarsus_l;
std::optional<bone_index_type> mesocoxa_r;
std::optional<bone_index_type> mesofemur_r;
std::optional<bone_index_type> mesotibia_r;
std::optional<bone_index_type> mesotarsus_r;
std::optional<bone_index_type> metacoxa_l;
std::optional<bone_index_type> metafemur_l;
std::optional<bone_index_type> metatibia_l;
std::optional<bone_index_type> metatarsus_l;
std::optional<bone_index_type> metacoxa_r;
std::optional<bone_index_type> metafemur_r;
std::optional<bone_index_type> metatibia_r;
std::optional<bone_index_type> metatarsus_r;
std::optional<bone_index_type> head;
std::optional<bone_index_type> mandible_l;
std::optional<bone_index_type> mandible_r;
std::optional<bone_index_type> antennomere1_l;
std::optional<bone_index_type> antennomere2_l;
std::optional<bone_index_type> antennomere1_r;
std::optional<bone_index_type> antennomere2_r;
std::optional<bone_index_type> petiole;
std::optional<bone_index_type> postpetiole;
std::optional<bone_index_type> gaster;
std::optional<bone_index_type> sting;
std::optional<bone_index_type> forewing_l;
std::optional<bone_index_type> forewing_r;
std::optional<bone_index_type> hindwing_l;
std::optional<bone_index_type> hindwing_r;
};
/**
@ -91,7 +94,7 @@ void reskin_vertices
const gl::vertex_attribute& normal_attribute,
const gl::vertex_attribute& tangent_attribute,
const gl::vertex_attribute& bone_index_attribute,
const std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>>& reskin_map
const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>>& reskin_map
)
{
std::byte* position_data = vertex_data + position_attribute.offset;
@ -105,7 +108,7 @@ void reskin_vertices
std::uint32_t& bone_index = reinterpret_cast<std::uint32_t&>(*(bone_index_data + bone_index_attribute.stride * i));
// Ignore vertices with unmapped bone indices
auto entry = reskin_map.find(static_cast<std::uint16_t>(bone_index));
auto entry = reskin_map.find(static_cast<bone_index_type>(bone_index));
if (entry == reskin_map.end())
{
continue;
@ -239,11 +242,11 @@ void reskin_vertices
* * sting
*
*/
[[nodiscard]] std::uint16_t count_ant_skeleton_bones(const ant_phenome& phenome) noexcept
[[nodiscard]] std::size_t count_ant_skeleton_bones(const ant_phenome& phenome) noexcept
{
constexpr std::uint16_t minimum_bone_count = 33;
constexpr std::size_t minimum_bone_count = 33;
std::uint16_t bone_count = minimum_bone_count;
std::size_t bone_count = minimum_bone_count;
if (phenome.waist->petiole_present)
{
@ -275,189 +278,199 @@ void reskin_vertices
void build_ant_skeleton(const ant_phenome& phenome, ::skeleton& skeleton, ant_bone_set& bones)
{
// Allocate bones
const std::uint16_t bone_count = count_ant_skeleton_bones(phenome);
skeleton.bones.resize(bone_count);
skeleton.set_bone_count(count_ant_skeleton_bones(phenome));
// Construct ant bone set
bone_index_type bone_index = 0;
bones.mesosoma = bone_index;
bones.procoxa_l = ++bone_index;
bones.profemur_l = ++bone_index;
bones.protibia_l = ++bone_index;
bones.protarsus_l = ++bone_index;
bones.procoxa_r = ++bone_index;
bones.profemur_r = ++bone_index;
bones.protibia_r = ++bone_index;
bones.protarsus_r = ++bone_index;
bones.mesocoxa_l = ++bone_index;
bones.mesofemur_l = ++bone_index;
bones.mesotibia_l = ++bone_index;
bones.mesotarsus_l = ++bone_index;
bones.mesocoxa_r = ++bone_index;
bones.mesofemur_r = ++bone_index;
bones.mesotibia_r = ++bone_index;
bones.mesotarsus_r = ++bone_index;
bones.metacoxa_l = ++bone_index;
bones.metafemur_l = ++bone_index;
bones.metatibia_l = ++bone_index;
bones.metatarsus_l = ++bone_index;
bones.metacoxa_r = ++bone_index;
bones.metafemur_r = ++bone_index;
bones.metatibia_r = ++bone_index;
bones.metatarsus_r = ++bone_index;
bones.head = ++bone_index;
bones.mandible_l = ++bone_index;
bones.mandible_r = ++bone_index;
bones.antennomere1_l = ++bone_index;
bones.antennomere2_l = ++bone_index;
bones.antennomere1_r = ++bone_index;
bones.antennomere2_r = ++bone_index;
// Assign bone indices
for (std::uint16_t i = 0; i < bone_count; ++i)
if (phenome.waist->petiole_present)
{
skeleton.bones[i] = i;
bones.petiole = ++bone_index;
}
// Construct ant bone set
::bone* current_bone = skeleton.bones.data();
bones.mesosoma = current_bone;
bones.procoxa_l = ++current_bone;
bones.profemur_l = ++current_bone;
bones.protibia_l = ++current_bone;
bones.protarsus_l = ++current_bone;
bones.procoxa_r = ++current_bone;
bones.profemur_r = ++current_bone;
bones.protibia_r = ++current_bone;
bones.protarsus_r = ++current_bone;
bones.mesocoxa_l = ++current_bone;
bones.mesofemur_l = ++current_bone;
bones.mesotibia_l = ++current_bone;
bones.mesotarsus_l = ++current_bone;
bones.mesocoxa_r = ++current_bone;
bones.mesofemur_r = ++current_bone;
bones.mesotibia_r = ++current_bone;
bones.mesotarsus_r = ++current_bone;
bones.metacoxa_l = ++current_bone;
bones.metafemur_l = ++current_bone;
bones.metatibia_l = ++current_bone;
bones.metatarsus_l = ++current_bone;
bones.metacoxa_r = ++current_bone;
bones.metafemur_r = ++current_bone;
bones.metatibia_r = ++current_bone;
bones.metatarsus_r = ++current_bone;
bones.head = ++current_bone;
bones.mandible_l = ++current_bone;
bones.mandible_r = ++current_bone;
bones.antennomere1_l = ++current_bone;
bones.antennomere2_l = ++current_bone;
bones.antennomere1_r = ++current_bone;
bones.antennomere2_r = ++current_bone;
bones.petiole = phenome.waist->petiole_present ? ++current_bone : nullptr;
bones.postpetiole = phenome.waist->postpetiole_present ? ++current_bone : nullptr;
bones.gaster = ++current_bone;
bones.sting = phenome.sting->present ? ++current_bone : nullptr;
bones.forewing_l = phenome.wings->present ? ++current_bone : nullptr;
bones.forewing_r = phenome.wings->present ? ++current_bone : nullptr;
bones.hindwing_l = phenome.wings->present ? ++current_bone : nullptr;
bones.hindwing_r = phenome.wings->present ? ++current_bone : nullptr;
if (phenome.waist->postpetiole_present)
{
bones.postpetiole = ++bone_index;
}
bones.gaster = ++bone_index;
if (phenome.sting->present)
{
bones.sting = ++bone_index;
}
if (phenome.wings->present)
{
bones.forewing_l = ++bone_index;
bones.forewing_r = ++bone_index;
bones.hindwing_l = ++bone_index;
bones.hindwing_r = ++bone_index;
}
// Assign bone parents
reparent_bone(*bones.mesosoma, *bones.mesosoma);
reparent_bone(*bones.procoxa_l, *bones.mesosoma);
reparent_bone(*bones.profemur_l, *bones.procoxa_l);
reparent_bone(*bones.protibia_l, *bones.profemur_l);
reparent_bone(*bones.protarsus_l, *bones.protibia_l);
reparent_bone(*bones.procoxa_r, *bones.mesosoma);
reparent_bone(*bones.profemur_r, *bones.procoxa_r);
reparent_bone(*bones.protibia_r, *bones.profemur_r);
reparent_bone(*bones.protarsus_r, *bones.protibia_r);
reparent_bone(*bones.mesocoxa_l, *bones.mesosoma);
reparent_bone(*bones.mesofemur_l, *bones.mesocoxa_l);
reparent_bone(*bones.mesotibia_l, *bones.mesofemur_l);
reparent_bone(*bones.mesotarsus_l, *bones.mesotibia_l);
reparent_bone(*bones.mesocoxa_r, *bones.mesosoma);
reparent_bone(*bones.mesofemur_r, *bones.mesocoxa_r);
reparent_bone(*bones.mesotibia_r, *bones.mesofemur_r);
reparent_bone(*bones.mesotarsus_r, *bones.mesotibia_r);
reparent_bone(*bones.metacoxa_l, *bones.mesosoma);
reparent_bone(*bones.metafemur_l, *bones.metacoxa_l);
reparent_bone(*bones.metatibia_l, *bones.metafemur_l);
reparent_bone(*bones.metatarsus_l, *bones.metatibia_l);
reparent_bone(*bones.metacoxa_r, *bones.mesosoma);
reparent_bone(*bones.metafemur_r, *bones.metacoxa_r);
reparent_bone(*bones.metatibia_r, *bones.metafemur_r);
reparent_bone(*bones.metatarsus_r, *bones.metatibia_r);
reparent_bone(*bones.head, *bones.mesosoma);
reparent_bone(*bones.mandible_l, *bones.head);
reparent_bone(*bones.mandible_r, *bones.head);
reparent_bone(*bones.antennomere1_l, *bones.head);
reparent_bone(*bones.antennomere2_l, *bones.antennomere1_l);
reparent_bone(*bones.antennomere1_r, *bones.head);
reparent_bone(*bones.antennomere2_r, *bones.antennomere1_r);
skeleton.set_bone_parent(*bones.mesosoma, *bones.mesosoma);
skeleton.set_bone_parent(*bones.procoxa_l, *bones.mesosoma);
skeleton.set_bone_parent(*bones.profemur_l, *bones.procoxa_l);
skeleton.set_bone_parent(*bones.protibia_l, *bones.profemur_l);
skeleton.set_bone_parent(*bones.protarsus_l, *bones.protibia_l);
skeleton.set_bone_parent(*bones.procoxa_r, *bones.mesosoma);
skeleton.set_bone_parent(*bones.profemur_r, *bones.procoxa_r);
skeleton.set_bone_parent(*bones.protibia_r, *bones.profemur_r);
skeleton.set_bone_parent(*bones.protarsus_r, *bones.protibia_r);
skeleton.set_bone_parent(*bones.mesocoxa_l, *bones.mesosoma);
skeleton.set_bone_parent(*bones.mesofemur_l, *bones.mesocoxa_l);
skeleton.set_bone_parent(*bones.mesotibia_l, *bones.mesofemur_l);
skeleton.set_bone_parent(*bones.mesotarsus_l, *bones.mesotibia_l);
skeleton.set_bone_parent(*bones.mesocoxa_r, *bones.mesosoma);
skeleton.set_bone_parent(*bones.mesofemur_r, *bones.mesocoxa_r);
skeleton.set_bone_parent(*bones.mesotibia_r, *bones.mesofemur_r);
skeleton.set_bone_parent(*bones.mesotarsus_r, *bones.mesotibia_r);
skeleton.set_bone_parent(*bones.metacoxa_l, *bones.mesosoma);
skeleton.set_bone_parent(*bones.metafemur_l, *bones.metacoxa_l);
skeleton.set_bone_parent(*bones.metatibia_l, *bones.metafemur_l);
skeleton.set_bone_parent(*bones.metatarsus_l, *bones.metatibia_l);
skeleton.set_bone_parent(*bones.metacoxa_r, *bones.mesosoma);
skeleton.set_bone_parent(*bones.metafemur_r, *bones.metacoxa_r);
skeleton.set_bone_parent(*bones.metatibia_r, *bones.metafemur_r);
skeleton.set_bone_parent(*bones.metatarsus_r, *bones.metatibia_r);
skeleton.set_bone_parent(*bones.head, *bones.mesosoma);
skeleton.set_bone_parent(*bones.mandible_l, *bones.head);
skeleton.set_bone_parent(*bones.mandible_r, *bones.head);
skeleton.set_bone_parent(*bones.antennomere1_l, *bones.head);
skeleton.set_bone_parent(*bones.antennomere2_l, *bones.antennomere1_l);
skeleton.set_bone_parent(*bones.antennomere1_r, *bones.head);
skeleton.set_bone_parent(*bones.antennomere2_r, *bones.antennomere1_r);
if (bones.petiole)
{
reparent_bone(*bones.petiole, *bones.mesosoma);
skeleton.set_bone_parent(*bones.petiole, *bones.mesosoma);
}
if (bones.postpetiole)
{
if (bones.petiole)
{
reparent_bone(*bones.postpetiole, *bones.petiole);
skeleton.set_bone_parent(*bones.postpetiole, *bones.petiole);
}
else
{
reparent_bone(*bones.postpetiole, *bones.mesosoma);
skeleton.set_bone_parent(*bones.postpetiole, *bones.mesosoma);
}
}
if (bones.postpetiole)
{
reparent_bone(*bones.gaster, *bones.postpetiole);
skeleton.set_bone_parent(*bones.gaster, *bones.postpetiole);
}
else
{
if (bones.petiole)
{
reparent_bone(*bones.gaster, *bones.petiole);
skeleton.set_bone_parent(*bones.gaster, *bones.petiole);
}
else
{
reparent_bone(*bones.gaster, *bones.mesosoma);
skeleton.set_bone_parent(*bones.gaster, *bones.mesosoma);
}
}
if (bones.sting)
{
reparent_bone(*bones.sting, *bones.gaster);
skeleton.set_bone_parent(*bones.sting, *bones.gaster);
}
if (bones.forewing_l)
{
reparent_bone(*bones.forewing_l, *bones.mesosoma);
reparent_bone(*bones.forewing_r, *bones.mesosoma);
reparent_bone(*bones.hindwing_l, *bones.mesosoma);
reparent_bone(*bones.hindwing_r, *bones.mesosoma);
skeleton.set_bone_parent(*bones.forewing_l, *bones.mesosoma);
skeleton.set_bone_parent(*bones.forewing_r, *bones.mesosoma);
skeleton.set_bone_parent(*bones.hindwing_l, *bones.mesosoma);
skeleton.set_bone_parent(*bones.hindwing_r, *bones.mesosoma);
}
// Map bone names to bones
skeleton.bone_map["mesosoma"] = *bones.mesosoma;
skeleton.bone_map["procoxa_l"] = *bones.procoxa_l;
skeleton.bone_map["profemur_l"] = *bones.profemur_l;
skeleton.bone_map["protibia_l"] = *bones.protibia_l;
skeleton.bone_map["protarsus_l"] = *bones.protarsus_l;
skeleton.bone_map["procoxa_r"] = *bones.procoxa_r;
skeleton.bone_map["profemur_r"] = *bones.profemur_r;
skeleton.bone_map["protibia_r"] = *bones.protibia_r;
skeleton.bone_map["protarsus_r"] = *bones.protarsus_r;
skeleton.bone_map["mesocoxa_l"] = *bones.mesocoxa_l;
skeleton.bone_map["mesofemur_l"] = *bones.mesofemur_l;
skeleton.bone_map["mesotibia_l"] = *bones.mesotibia_l;
skeleton.bone_map["mesotarsus_l"] = *bones.mesotarsus_l;
skeleton.bone_map["mesocoxa_r"] = *bones.mesocoxa_r;
skeleton.bone_map["mesofemur_r"] = *bones.mesofemur_r;
skeleton.bone_map["mesotibia_r"] = *bones.mesotibia_r;
skeleton.bone_map["mesotarsus_r"] = *bones.mesotarsus_r;
skeleton.bone_map["metacoxa_l"] = *bones.metacoxa_l;
skeleton.bone_map["metafemur_l"] = *bones.metafemur_l;
skeleton.bone_map["metatibia_l"] = *bones.metatibia_l;
skeleton.bone_map["metatarsus_l"] = *bones.metatarsus_l;
skeleton.bone_map["metacoxa_r"] = *bones.metacoxa_r;
skeleton.bone_map["metafemur_r"] = *bones.metafemur_r;
skeleton.bone_map["metatibia_r"] = *bones.metatibia_r;
skeleton.bone_map["metatarsus_r"] = *bones.metatarsus_r;
skeleton.bone_map["head"] = *bones.head;
skeleton.bone_map["mandible_l"] = *bones.mandible_l;
skeleton.bone_map["mandible_r"] = *bones.mandible_r;
skeleton.bone_map["antennomere1_l"] = *bones.antennomere1_l;
skeleton.bone_map["antennomere2_l"] = *bones.antennomere2_l;
skeleton.bone_map["antennomere1_r"] = *bones.antennomere1_r;
skeleton.bone_map["antennomere2_r"] = *bones.antennomere2_r;
skeleton.set_bone_name(*bones.mesosoma, "mesosoma");
skeleton.set_bone_name(*bones.procoxa_l, "procoxa_l");
skeleton.set_bone_name(*bones.profemur_l, "profemur_l");
skeleton.set_bone_name(*bones.protibia_l, "protibia_l");
skeleton.set_bone_name(*bones.protarsus_l, "protarsus_l");
skeleton.set_bone_name(*bones.procoxa_r, "procoxa_r");
skeleton.set_bone_name(*bones.profemur_r, "profemur_r");
skeleton.set_bone_name(*bones.protibia_r, "protibia_r");
skeleton.set_bone_name(*bones.protarsus_r, "protarsus_r");
skeleton.set_bone_name(*bones.mesocoxa_l, "mesocoxa_l");
skeleton.set_bone_name(*bones.mesofemur_l, "mesofemur_l");
skeleton.set_bone_name(*bones.mesotibia_l, "mesotibia_l");
skeleton.set_bone_name(*bones.mesotarsus_l, "mesotarsus_l");
skeleton.set_bone_name(*bones.mesocoxa_r, "mesocoxa_r");
skeleton.set_bone_name(*bones.mesofemur_r, "mesofemur_r");
skeleton.set_bone_name(*bones.mesotibia_r, "mesotibia_r");
skeleton.set_bone_name(*bones.mesotarsus_r, "mesotarsus_r");
skeleton.set_bone_name(*bones.metacoxa_l, "metacoxa_l");
skeleton.set_bone_name(*bones.metafemur_l, "metafemur_l");
skeleton.set_bone_name(*bones.metatibia_l, "metatibia_l");
skeleton.set_bone_name(*bones.metatarsus_l, "metatarsus_l");
skeleton.set_bone_name(*bones.metacoxa_r, "metacoxa_r");
skeleton.set_bone_name(*bones.metafemur_r, "metafemur_r");
skeleton.set_bone_name(*bones.metatibia_r, "metatibia_r");
skeleton.set_bone_name(*bones.metatarsus_r, "metatarsus_r");
skeleton.set_bone_name(*bones.head, "head");
skeleton.set_bone_name(*bones.mandible_l, "mandible_l");
skeleton.set_bone_name(*bones.mandible_r, "mandible_r");
skeleton.set_bone_name(*bones.antennomere1_l, "antennomere1_l");
skeleton.set_bone_name(*bones.antennomere2_l, "antennomere2_l");
skeleton.set_bone_name(*bones.antennomere1_r, "antennomere1_r");
skeleton.set_bone_name(*bones.antennomere2_r, "antennomere2_r");
if (bones.petiole)
{
skeleton.bone_map["petiole"] = *bones.petiole;
skeleton.set_bone_name(*bones.petiole, "petiole");
}
if (bones.postpetiole)
{
skeleton.bone_map["postpetiole"] = *bones.postpetiole;
skeleton.set_bone_name(*bones.postpetiole, "postpetiole");
}
skeleton.bone_map["gaster"] = *bones.gaster;
skeleton.set_bone_name(*bones.gaster, "gaster");
if (bones.sting)
{
skeleton.bone_map["sting"] = *bones.sting;
skeleton.set_bone_name(*bones.sting, "sting");
}
if (bones.forewing_l)
{
skeleton.bone_map["forewing_l"] = *bones.forewing_l;
skeleton.bone_map["forewing_r"] = *bones.forewing_r;
skeleton.bone_map["hindwing_l"] = *bones.hindwing_l;
skeleton.bone_map["hindwing_r"] = *bones.hindwing_r;
skeleton.set_bone_name(*bones.forewing_l, "forewing_l");
skeleton.set_bone_name(*bones.forewing_r, "forewing_r");
skeleton.set_bone_name(*bones.hindwing_l, "hindwing_l");
skeleton.set_bone_name(*bones.hindwing_r, "hindwing_r");
}
}
@ -469,7 +482,7 @@ void build_ant_skeleton(const ant_phenome& phenome, ::skeleton& skeleton, ant_bo
* @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, ::pose& bind_pose_ss)
void build_ant_bind_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();
@ -483,80 +496,78 @@ void build_ant_bind_pose(const ant_phenome& phenome, const ant_bone_set& bones,
const ::skeleton* forewings_skeleton = (phenome.wings->present) ? &phenome.wings->forewings_model->get_skeleton() : nullptr;
const ::skeleton* hindwings_skeleton = (phenome.wings->present) ? &phenome.wings->hindwings_model->get_skeleton() : nullptr;
// Get reference to skeleton bind pose
pose& bind_pose = skeleton.bind_pose;
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));
};
// Build skeleton bind pose
bind_pose[*bones.mesosoma] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("mesosoma"));
bind_pose[*bones.procoxa_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("procoxa_l"));
bind_pose[*bones.profemur_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("profemur_l"));
bind_pose[*bones.protibia_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protibia_l"));
bind_pose[*bones.protarsus_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protarsus1_l"));
bind_pose[*bones.procoxa_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("procoxa_r"));
bind_pose[*bones.profemur_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("profemur_r"));
bind_pose[*bones.protibia_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protibia_r"));
bind_pose[*bones.protarsus_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("protarsus1_r"));
bind_pose[*bones.mesocoxa_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesocoxa_l"));
bind_pose[*bones.mesofemur_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesofemur_l"));
bind_pose[*bones.mesotibia_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotibia_l"));
bind_pose[*bones.mesotarsus_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotarsus1_l"));
bind_pose[*bones.mesocoxa_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesocoxa_r"));
bind_pose[*bones.mesofemur_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesofemur_r"));
bind_pose[*bones.mesotibia_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotibia_r"));
bind_pose[*bones.mesotarsus_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("mesotarsus1_r"));
bind_pose[*bones.metacoxa_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metacoxa_l"));
bind_pose[*bones.metafemur_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metafemur_l"));
bind_pose[*bones.metatibia_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatibia_l"));
bind_pose[*bones.metatarsus_l] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatarsus1_l"));
bind_pose[*bones.metacoxa_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metacoxa_r"));
bind_pose[*bones.metafemur_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metafemur_r"));
bind_pose[*bones.metatibia_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatibia_r"));
bind_pose[*bones.metatarsus_r] = legs_skeleton.bind_pose.at(legs_skeleton.bone_map.at("metatarsus1_r"));
bind_pose[*bones.head] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head")) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("head"));
bind_pose[*bones.mandible_l] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_l")) * mandibles_skeleton.bind_pose.at(mandibles_skeleton.bone_map.at("mandible_l"));
bind_pose[*bones.mandible_r] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r")) * mandibles_skeleton.bind_pose.at(mandibles_skeleton.bone_map.at("mandible_r"));
bind_pose[*bones.antennomere1_l] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_l")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere1_l"));
bind_pose[*bones.antennomere2_l] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere2_l"));
bind_pose[*bones.antennomere1_r] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_r")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere1_r"));
bind_pose[*bones.antennomere2_r] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere2_r"));
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"));
skeleton.set_bone_transform(*bones.protibia_l, get_bone_transform(legs_skeleton, "protibia_l"));
skeleton.set_bone_transform(*bones.protarsus_l, get_bone_transform(legs_skeleton, "protarsus1_l"));
skeleton.set_bone_transform(*bones.procoxa_r, get_bone_transform(legs_skeleton, "procoxa_r"));
skeleton.set_bone_transform(*bones.profemur_r, get_bone_transform(legs_skeleton, "profemur_r"));
skeleton.set_bone_transform(*bones.protibia_r, get_bone_transform(legs_skeleton, "protibia_r"));
skeleton.set_bone_transform(*bones.protarsus_r, get_bone_transform(legs_skeleton, "protarsus1_r"));
skeleton.set_bone_transform(*bones.mesocoxa_l, get_bone_transform(legs_skeleton, "mesocoxa_l"));
skeleton.set_bone_transform(*bones.mesofemur_l, get_bone_transform(legs_skeleton, "mesofemur_l"));
skeleton.set_bone_transform(*bones.mesotibia_l, get_bone_transform(legs_skeleton, "mesotibia_l"));
skeleton.set_bone_transform(*bones.mesotarsus_l, get_bone_transform(legs_skeleton, "mesotarsus1_l"));
skeleton.set_bone_transform(*bones.mesocoxa_r, get_bone_transform(legs_skeleton, "mesocoxa_r"));
skeleton.set_bone_transform(*bones.mesofemur_r, get_bone_transform(legs_skeleton, "mesofemur_r"));
skeleton.set_bone_transform(*bones.mesotibia_r, get_bone_transform(legs_skeleton, "mesotibia_r"));
skeleton.set_bone_transform(*bones.mesotarsus_r, get_bone_transform(legs_skeleton, "mesotarsus1_r"));
skeleton.set_bone_transform(*bones.metacoxa_l, get_bone_transform(legs_skeleton, "metacoxa_l"));
skeleton.set_bone_transform(*bones.metafemur_l, get_bone_transform(legs_skeleton, "metafemur_l"));
skeleton.set_bone_transform(*bones.metatibia_l, get_bone_transform(legs_skeleton, "metatibia_l"));
skeleton.set_bone_transform(*bones.metatarsus_l, get_bone_transform(legs_skeleton, "metatarsus1_l"));
skeleton.set_bone_transform(*bones.metacoxa_r, get_bone_transform(legs_skeleton, "metacoxa_r"));
skeleton.set_bone_transform(*bones.metafemur_r, get_bone_transform(legs_skeleton, "metafemur_r"));
skeleton.set_bone_transform(*bones.metatibia_r, get_bone_transform(legs_skeleton, "metatibia_r"));
skeleton.set_bone_transform(*bones.metatarsus_r, get_bone_transform(legs_skeleton, "metatarsus1_r"));
skeleton.set_bone_transform(*bones.head, get_bone_transform(mesosoma_skeleton, "head") * get_bone_transform(head_skeleton, "head"));
skeleton.set_bone_transform(*bones.mandible_l, get_bone_transform(head_skeleton, "mandible_l") * get_bone_transform(mandibles_skeleton, "mandible_l"));
skeleton.set_bone_transform(*bones.mandible_r, get_bone_transform(head_skeleton, "mandible_r") * get_bone_transform(mandibles_skeleton, "mandible_r"));
skeleton.set_bone_transform(*bones.antennomere1_l, get_bone_transform(head_skeleton, "antenna_l") * get_bone_transform(antennae_skeleton, "antennomere1_l"));
skeleton.set_bone_transform(*bones.antennomere2_l, get_bone_transform(antennae_skeleton, "antennomere2_l"));
skeleton.set_bone_transform(*bones.antennomere1_r, get_bone_transform(head_skeleton, "antenna_r") * get_bone_transform(antennae_skeleton, "antennomere1_r"));
skeleton.set_bone_transform(*bones.antennomere2_r, get_bone_transform(antennae_skeleton, "antennomere2_r"));
if (bones.petiole)
{
bind_pose[*bones.petiole] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole"));
skeleton.set_bone_transform(*bones.petiole, get_bone_transform(mesosoma_skeleton, "petiole") * get_bone_transform(waist_skeleton, "petiole"));
}
if (bones.postpetiole)
{
bind_pose[*bones.postpetiole] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole"));
bind_pose[*bones.gaster] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster"));
skeleton.set_bone_transform(*bones.postpetiole, get_bone_transform(waist_skeleton, "postpetiole"));
skeleton.set_bone_transform(*bones.gaster, get_bone_transform(waist_skeleton, "postpetiole") * get_bone_transform(gaster_skeleton, "gaster"));
}
else if (bones.petiole)
{
bind_pose[*bones.gaster] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster"));
skeleton.set_bone_transform(*bones.gaster, get_bone_transform(waist_skeleton, "petiole") * get_bone_transform(gaster_skeleton, "gaster"));
}
else
{
bind_pose[*bones.gaster] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster"));
skeleton.set_bone_transform(*bones.gaster, get_bone_transform(mesosoma_skeleton, "petiole") * get_bone_transform(gaster_skeleton, "gaster"));
}
if (bones.sting)
{
bind_pose[*bones.sting] = gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting")) * sting_skeleton->bind_pose.at(sting_skeleton->bone_map.at("sting"));
skeleton.set_bone_transform(*bones.sting, get_bone_transform(gaster_skeleton, "sting") * get_bone_transform(*sting_skeleton, "sting"));
}
if (bones.forewing_l)
{
bind_pose[*bones.forewing_l] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_l")) * forewings_skeleton->bind_pose.at(forewings_skeleton->bone_map.at("forewing_l"));
bind_pose[*bones.forewing_r] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_r")) * forewings_skeleton->bind_pose.at(forewings_skeleton->bone_map.at("forewing_r"));
bind_pose[*bones.hindwing_l] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_l")) * hindwings_skeleton->bind_pose.at(hindwings_skeleton->bone_map.at("hindwing_l"));
bind_pose[*bones.hindwing_r] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_r")) * hindwings_skeleton->bind_pose.at(hindwings_skeleton->bone_map.at("hindwing_r"));
skeleton.set_bone_transform(*bones.forewing_l, get_bone_transform(mesosoma_skeleton, "forewing_l") * get_bone_transform(*forewings_skeleton, "forewing_l"));
skeleton.set_bone_transform(*bones.forewing_r, get_bone_transform(mesosoma_skeleton, "forewing_r") * get_bone_transform(*forewings_skeleton, "forewing_r"));
skeleton.set_bone_transform(*bones.hindwing_l, get_bone_transform(mesosoma_skeleton, "hindwing_l") * get_bone_transform(*hindwings_skeleton, "hindwing_l"));
skeleton.set_bone_transform(*bones.hindwing_r, get_bone_transform(mesosoma_skeleton, "hindwing_r") * get_bone_transform(*hindwings_skeleton, "hindwing_r"));
}
// Calculate the skeleton-space bind pose
::concatenate(bind_pose, bind_pose_ss);
// Calculate inverse skeleton-space bind pose
::inverse(bind_pose_ss, skeleton.inverse_bind_pose);
skeleton.update_bind_pose();
}
} // namespace
@ -772,8 +783,8 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
build_ant_skeleton(phenome, skeleton, bones);
// Build ant bind pose
pose bind_pose_ss;
build_ant_bind_pose(phenome, bones, skeleton, bind_pose_ss);
build_ant_bind_pose(phenome, bones, skeleton);
const auto& bind_pose = skeleton.get_bind_pose();
// Get number of vertices for each body part
const std::uint32_t mesosoma_vertex_count = (mesosoma_model->get_groups()).front().index_count;
@ -814,41 +825,46 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
const ::skeleton* forewings_skeleton = (phenome.wings->present) ? &phenome.wings->forewings_model->get_skeleton() : nullptr;
const ::skeleton* hindwings_skeleton = (phenome.wings->present) ? &phenome.wings->hindwings_model->get_skeleton() : nullptr;
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));
};
// 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_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head"));
const math::transform<float> mandible_l_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_l"));
const math::transform<float> mandible_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r"));
const math::transform<float> antenna_l_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_l"));
const math::transform<float> antenna_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_r"));
const math::transform<float> waist_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole"));
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");
math::transform<float> gaster_to_body;
if (phenome.waist->postpetiole_present)
{
gaster_to_body = bind_pose_ss.at(*bones.postpetiole) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster"));
gaster_to_body = bind_pose.get_absolute_transform(*bones.postpetiole) * get_bone_transform(waist_skeleton, "gaster");
}
else if (phenome.waist->petiole_present)
{
gaster_to_body = bind_pose_ss.at(*bones.petiole) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster"));
gaster_to_body = bind_pose.get_absolute_transform(*bones.petiole) * get_bone_transform(waist_skeleton, "gaster");
}
else
{
gaster_to_body = bind_pose_ss.at(*bones.mesosoma) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster"));
gaster_to_body = bind_pose.get_absolute_transform(*bones.mesosoma) * get_bone_transform(waist_skeleton, "gaster");
}
math::transform<float> sting_to_body;
if (phenome.sting->present)
{
sting_to_body = gaster_to_body * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting"));
sting_to_body = gaster_to_body * get_bone_transform(gaster_skeleton, "sting");
}
math::transform<float> eye_l_to_body;
math::transform<float> eye_r_to_body;
if (phenome.eyes->present)
{
eye_l_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_l"));
eye_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_r"));
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");
}
math::transform<float> ocellus_l_to_body;
@ -856,12 +872,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_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_l"));
ocellus_r_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_r"));
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");
}
if (phenome.ocelli->median_ocellus_present)
{
ocellus_m_to_body = bind_pose_ss.at(*bones.head) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_m"));
ocellus_m_to_body = bind_pose.get_absolute_transform(*bones.head) * get_bone_transform(head_skeleton, "ocellus_m");
}
math::transform<float> forewing_l_to_body;
@ -870,85 +886,85 @@ 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_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_l"));
forewing_r_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("forewing_r"));
hindwing_l_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_l"));
hindwing_r_to_body = bind_pose_ss.at(*bones.mesosoma) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("hindwing_r"));
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");
}
// Build legs vertex reskin map
const std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> legs_reskin_map
{
{bone_index(legs_skeleton.bone_map.at("procoxa_l")), {bone_index(*bones.procoxa_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("profemur_l")), {bone_index(*bones.profemur_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protibia_l")), {bone_index(*bones.protibia_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus1_l")), {bone_index(*bones.protarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus2_l")), {bone_index(*bones.protarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus3_l")), {bone_index(*bones.protarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus4_l")), {bone_index(*bones.protarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus5_l")), {bone_index(*bones.protarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("procoxa_r")), {bone_index(*bones.procoxa_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("profemur_r")), {bone_index(*bones.profemur_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protibia_r")), {bone_index(*bones.protibia_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus1_r")), {bone_index(*bones.protarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus2_r")), {bone_index(*bones.protarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus3_r")), {bone_index(*bones.protarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus4_r")), {bone_index(*bones.protarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("protarsus5_r")), {bone_index(*bones.protarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesocoxa_l")), {bone_index(*bones.mesocoxa_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesofemur_l")), {bone_index(*bones.mesofemur_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotibia_l")), {bone_index(*bones.mesotibia_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus1_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus2_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus3_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus4_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus5_l")), {bone_index(*bones.mesotarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesocoxa_r")), {bone_index(*bones.mesocoxa_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesofemur_r")), {bone_index(*bones.mesofemur_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotibia_r")), {bone_index(*bones.mesotibia_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus1_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus2_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus3_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus4_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("mesotarsus5_r")), {bone_index(*bones.mesotarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metacoxa_l")), {bone_index(*bones.metacoxa_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metafemur_l")), {bone_index(*bones.metafemur_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatibia_l")), {bone_index(*bones.metatibia_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus1_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus2_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus3_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus4_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus5_l")), {bone_index(*bones.metatarsus_l), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metacoxa_r")), {bone_index(*bones.metacoxa_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metafemur_r")), {bone_index(*bones.metafemur_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatibia_r")), {bone_index(*bones.metatibia_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus1_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus2_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus3_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus4_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}},
{bone_index(legs_skeleton.bone_map.at("metatarsus5_r")), {bone_index(*bones.metatarsus_r), &legs_to_body}}
const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> legs_reskin_map
{
{*legs_skeleton.get_bone_index("procoxa_l"), {*bones.procoxa_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("profemur_l"), {*bones.profemur_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("protibia_l"), {*bones.protibia_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus1_l"), {*bones.protarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus2_l"), {*bones.protarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus3_l"), {*bones.protarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus4_l"), {*bones.protarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus5_l"), {*bones.protarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("procoxa_r"), {*bones.procoxa_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("profemur_r"), {*bones.profemur_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("protibia_r"), {*bones.protibia_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus1_r"), {*bones.protarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus2_r"), {*bones.protarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus3_r"), {*bones.protarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus4_r"), {*bones.protarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("protarsus5_r"), {*bones.protarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesocoxa_l"), {*bones.mesocoxa_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesofemur_l"), {*bones.mesofemur_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotibia_l"), {*bones.mesotibia_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus1_l"), {*bones.mesotarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus2_l"), {*bones.mesotarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus3_l"), {*bones.mesotarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus4_l"), {*bones.mesotarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus5_l"), {*bones.mesotarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesocoxa_r"), {*bones.mesocoxa_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesofemur_r"), {*bones.mesofemur_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotibia_r"), {*bones.mesotibia_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus1_r"), {*bones.mesotarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus2_r"), {*bones.mesotarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus3_r"), {*bones.mesotarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus4_r"), {*bones.mesotarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("mesotarsus5_r"), {*bones.mesotarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metacoxa_l"), {*bones.metacoxa_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metafemur_l"), {*bones.metafemur_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatibia_l"), {*bones.metatibia_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus1_l"), {*bones.metatarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus2_l"), {*bones.metatarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus3_l"), {*bones.metatarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus4_l"), {*bones.metatarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus5_l"), {*bones.metatarsus_l, &legs_to_body}},
{*legs_skeleton.get_bone_index("metacoxa_r"), {*bones.metacoxa_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metafemur_r"), {*bones.metafemur_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatibia_r"), {*bones.metatibia_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus1_r"), {*bones.metatarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus2_r"), {*bones.metatarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus3_r"), {*bones.metatarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus4_r"), {*bones.metatarsus_r, &legs_to_body}},
{*legs_skeleton.get_bone_index("metatarsus5_r"), {*bones.metatarsus_r, &legs_to_body}}
};
// Build head vertex reskin map
const std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> head_reskin_map
const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> head_reskin_map
{
{bone_index(head_skeleton.bone_map.at("head")), {bone_index(*bones.head), &head_to_body}}
{*head_skeleton.get_bone_index("head"), {*bones.head, &head_to_body}}
};
// Build mandibles vertex reskin map
const std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> mandibles_reskin_map
const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> mandibles_reskin_map
{
{bone_index(mandibles_skeleton.bone_map.at("mandible_l")), {bone_index(*bones.mandible_l), &mandible_l_to_body}},
{bone_index(mandibles_skeleton.bone_map.at("mandible_r")), {bone_index(*bones.mandible_r), &mandible_r_to_body}}
{*mandibles_skeleton.get_bone_index("mandible_l"), {*bones.mandible_l, &mandible_l_to_body}},
{*mandibles_skeleton.get_bone_index("mandible_r"), {*bones.mandible_r, &mandible_r_to_body}}
};
// Build antennae vertex reskin map
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> antennae_reskin_map
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> antennae_reskin_map
{
{bone_index(antennae_skeleton.bone_map.at("antennomere1_l")), {bone_index(*bones.antennomere1_l), &antenna_l_to_body}},
{bone_index(antennae_skeleton.bone_map.at("antennomere2_l")), {bone_index(*bones.antennomere2_l), &antenna_l_to_body}},
{bone_index(antennae_skeleton.bone_map.at("antennomere1_r")), {bone_index(*bones.antennomere1_r), &antenna_r_to_body}},
{bone_index(antennae_skeleton.bone_map.at("antennomere2_r")), {bone_index(*bones.antennomere2_r), &antenna_r_to_body}}
{*antennae_skeleton.get_bone_index("antennomere1_l"), {*bones.antennomere1_l, &antenna_l_to_body}},
{*antennae_skeleton.get_bone_index("antennomere2_l"), {*bones.antennomere2_l, &antenna_l_to_body}},
{*antennae_skeleton.get_bone_index("antennomere1_r"), {*bones.antennomere1_r, &antenna_r_to_body}},
{*antennae_skeleton.get_bone_index("antennomere2_r"), {*bones.antennomere2_r, &antenna_r_to_body}}
};
for (std::uint8_t i = 3; i <= phenome.antennae->total_antennomere_count; ++i)
{
@ -958,66 +974,66 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
const hash::fnv1a32_t antennomere_l_key = hash::fnv1a32<char>(antennomere_l_name);
const hash::fnv1a32_t antennomere_r_key = hash::fnv1a32<char>(antennomere_r_name);
antennae_reskin_map.emplace(bone_index(antennae_skeleton.bone_map.at(antennomere_l_key)), std::tuple(bone_index(*bones.antennomere2_l), &antenna_l_to_body));
antennae_reskin_map.emplace(bone_index(antennae_skeleton.bone_map.at(antennomere_r_key)), std::tuple(bone_index(*bones.antennomere2_r), &antenna_r_to_body));
antennae_reskin_map.emplace(*antennae_skeleton.get_bone_index(antennomere_l_key), std::tuple(*bones.antennomere2_l, &antenna_l_to_body));
antennae_reskin_map.emplace(*antennae_skeleton.get_bone_index(antennomere_r_key), std::tuple(*bones.antennomere2_r, &antenna_r_to_body));
}
// Build waist vertex reskin map
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> waist_reskin_map;
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> waist_reskin_map;
if (phenome.waist->petiole_present)
{
waist_reskin_map.emplace(bone_index(waist_skeleton.bone_map.at("petiole")), std::tuple(bone_index(*bones.petiole), &waist_to_body));
waist_reskin_map.emplace(*waist_skeleton.get_bone_index("petiole"), std::tuple(*bones.petiole, &waist_to_body));
}
if (phenome.waist->postpetiole_present)
{
waist_reskin_map.emplace(bone_index(waist_skeleton.bone_map.at("postpetiole")), std::tuple(bone_index(*bones.postpetiole), &waist_to_body));
waist_reskin_map.emplace(*waist_skeleton.get_bone_index("postpetiole"), std::tuple(*bones.postpetiole, &waist_to_body));
}
// Build gaster vertex reskin map
const std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> gaster_reskin_map
const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> gaster_reskin_map
{
{bone_index(gaster_skeleton.bone_map.at("gaster")), {bone_index(*bones.gaster), &gaster_to_body}}
{*gaster_skeleton.get_bone_index("gaster"), {*bones.gaster, &gaster_to_body}}
};
// Build sting vertex reskin map
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> sting_reskin_map;
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> sting_reskin_map;
if (phenome.sting->present)
{
sting_reskin_map.emplace(bone_index(sting_skeleton->bone_map.at("sting")), std::tuple(bone_index(*bones.sting), &sting_to_body));
sting_reskin_map.emplace(*sting_skeleton->get_bone_index("sting"), std::tuple(*bones.sting, &sting_to_body));
}
// Build eyes vertex reskin map
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> eyes_reskin_map;
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> eyes_reskin_map;
if (phenome.eyes->present)
{
eyes_reskin_map.emplace(bone_index(eyes_skeleton->bone_map.at("eye_l")), std::tuple(bone_index(*bones.head), &eye_l_to_body));
eyes_reskin_map.emplace(bone_index(eyes_skeleton->bone_map.at("eye_r")), std::tuple(bone_index(*bones.head), &eye_r_to_body));
eyes_reskin_map.emplace(*eyes_skeleton->get_bone_index("eye_l"), std::tuple(*bones.head, &eye_l_to_body));
eyes_reskin_map.emplace(*eyes_skeleton->get_bone_index("eye_r"), std::tuple(*bones.head, &eye_r_to_body));
}
// Build lateral ocelli vertex reskin map
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> lateral_ocelli_reskin_map;
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> lateral_ocelli_reskin_map;
if (phenome.ocelli->lateral_ocelli_present)
{
lateral_ocelli_reskin_map.emplace(bone_index(lateral_ocelli_skeleton->bone_map.at("ocellus_l")), std::tuple(bone_index(*bones.head), &ocellus_l_to_body));
lateral_ocelli_reskin_map.emplace(bone_index(lateral_ocelli_skeleton->bone_map.at("ocellus_r")), std::tuple(bone_index(*bones.head), &ocellus_r_to_body));
lateral_ocelli_reskin_map.emplace(*lateral_ocelli_skeleton->get_bone_index("ocellus_l"), std::tuple(*bones.head, &ocellus_l_to_body));
lateral_ocelli_reskin_map.emplace(*lateral_ocelli_skeleton->get_bone_index("ocellus_r"), std::tuple(*bones.head, &ocellus_r_to_body));
}
// Build median ocellus vertex reskin map
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> median_ocellus_reskin_map;
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> median_ocellus_reskin_map;
if (phenome.ocelli->median_ocellus_present)
{
median_ocellus_reskin_map.emplace(bone_index(median_ocellus_skeleton->bone_map.at("ocellus_m")), std::tuple(bone_index(*bones.head), &ocellus_m_to_body));
median_ocellus_reskin_map.emplace(*median_ocellus_skeleton->get_bone_index("ocellus_m"), std::tuple(*bones.head, &ocellus_m_to_body));
}
// Build wings vertex reskin maps
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> forewings_reskin_map;
std::unordered_map<std::uint16_t, std::tuple<std::uint16_t, const math::transform<float>*>> hindwings_reskin_map;
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> forewings_reskin_map;
std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> hindwings_reskin_map;
if (phenome.wings->present)
{
forewings_reskin_map.emplace(bone_index(forewings_skeleton->bone_map.at("forewing_l")), std::tuple(bone_index(*bones.forewing_l), &forewing_l_to_body));
forewings_reskin_map.emplace(bone_index(forewings_skeleton->bone_map.at("forewing_r")), std::tuple(bone_index(*bones.forewing_r), &forewing_r_to_body));
hindwings_reskin_map.emplace(bone_index(hindwings_skeleton->bone_map.at("hindwing_l")), std::tuple(bone_index(*bones.hindwing_l), &hindwing_l_to_body));
hindwings_reskin_map.emplace(bone_index(hindwings_skeleton->bone_map.at("hindwing_r")), std::tuple(bone_index(*bones.hindwing_r), &hindwing_r_to_body));
forewings_reskin_map.emplace(*forewings_skeleton->get_bone_index("forewing_l"), std::tuple(*bones.forewing_l, &forewing_l_to_body));
forewings_reskin_map.emplace(*forewings_skeleton->get_bone_index("forewing_r"), std::tuple(*bones.forewing_r, &forewing_r_to_body));
hindwings_reskin_map.emplace(*hindwings_skeleton->get_bone_index("hindwing_l"), std::tuple(*bones.hindwing_l, &hindwing_l_to_body));
hindwings_reskin_map.emplace(*hindwings_skeleton->get_bone_index("hindwing_r"), std::tuple(*bones.hindwing_r, &hindwing_r_to_body));
}
// Reskin legs vertices

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

@ -71,6 +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>
nest_selection_state::nest_selection_state(::game& ctx):
game_state(ctx)
@ -102,8 +103,6 @@ nest_selection_state::nest_selection_state(::game& ctx):
worker_model = ant_morphogenesis(worker_phenome);
debug::log::trace("Generated worker model");
// Create floor plane
auto floor_archetype = ctx.resource_manager->load<entity::archetype>("desert-scrub-plane.ent");
@ -128,13 +127,33 @@ nest_selection_state::nest_selection_state(::game& ctx):
ctx.entity_registry->emplace<rigid_body_component>(floor_eid, std::move(floor_body));
// Create worker entity(s)
auto worker_rigged_mesh = std::make_unique<scene::rigged_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 float mandibles_open_angle = math::radians(32.0f);
auto open_left_mandible = math::transform<float>::identity();
open_left_mandible.rotation = math::angle_axis(-mandibles_open_angle, float3{0, 0, 1});
auto open_right_mandible = math::transform<float>::identity();
open_right_mandible.rotation = math::angle_axis(mandibles_open_angle, float3{0, 0, 1});
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.update();
worker_ant_eid = ctx.entity_registry->create();
transform_component worker_transform_component;
worker_transform_component.local = math::transform<float>::identity();
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::make_unique<scene::static_mesh>(worker_model), std::uint8_t{1});
ctx.entity_registry->emplace<scene_component>(worker_ant_eid, std::move(worker_rigged_mesh), std::uint8_t{1});

Loading…
Cancel
Save