@ -0,0 +1,53 @@ | |||
/* | |||
* 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/ik/constraints/euler-ik-constraint.hpp> | |||
#include <algorithm> | |||
#include <cmath> | |||
void euler_ik_constraint::solve(math::quaternion<float>& q) | |||
{ | |||
// Derive XYZ angles from quaternion | |||
const auto x = std::atan2(2.0f * (q.w() * q.x() + q.y() * q.z()), 1.0f - 2.0f * (q.x() * q.x() + q.y() * q.y())); | |||
const auto y = std::asin(2.0f * (q.w() * q.y() - q.z() * q.x())); | |||
const auto z = std::atan2(2.0f * (q.w() * q.z() + q.x() * q.y()), 1.0f - 2.0f * (q.y() * q.y() + q.z() * q.z())); | |||
// Constrain and halve angles | |||
const auto half_constrained_x = std::min<float>(std::max<float>(x, m_min.x()), m_max.x()) * 0.5f; | |||
const auto half_constrained_y = std::min<float>(std::max<float>(y, m_min.y()), m_max.y()) * 0.5f; | |||
const auto half_constrained_z = std::min<float>(std::max<float>(z, m_min.z()), m_max.z()) * 0.5f; | |||
// Reconstruct quaternion from constrained, halved angles | |||
const auto cx = std::cos(half_constrained_x); | |||
const auto sx = std::sin(half_constrained_x); | |||
const auto cy = std::cos(half_constrained_y); | |||
const auto sy = std::sin(half_constrained_y); | |||
const auto cz = std::cos(half_constrained_z); | |||
const auto sz = std::sin(half_constrained_z); | |||
q = math::normalize | |||
( | |||
math::quaternion<float> | |||
{ | |||
cx * cy * cz + sx * sy * sz, | |||
sx * cy * cz - cx * sy * sz, | |||
cx * sy * cz + sx * cy * sz, | |||
cx * cy * sz - sx * sy * cz | |||
} | |||
); | |||
} |
@ -0,0 +1,51 @@ | |||
/* | |||
* 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_EULER_IK_CONSTRAINT_HPP | |||
#define ANTKEEPER_ANIMATION_EULER_IK_CONSTRAINT_HPP | |||
#include <engine/animation/ik/ik-constraint.hpp> | |||
#include <engine/math/numbers.hpp> | |||
/** | |||
* Euler angle IK constraint. | |||
*/ | |||
class euler_ik_constraint: public ik_constraint | |||
{ | |||
public: | |||
void solve(math::quaternion<float>& q) override; | |||
/** | |||
* Sets the angular limits. | |||
* | |||
* @param min Minimum angles of the x-, y-, and z-axes, in radians. | |||
* @param max Maximum angles of the x-, y-, and z-axes, in radians. | |||
*/ | |||
inline void set_limits(const math::vector<float, 3>& min, const math::vector<float, 3>& max) noexcept | |||
{ | |||
m_min = min; | |||
m_max = max; | |||
} | |||
private: | |||
math::vector<float, 3> m_min{-math::pi<float>, -math::pi<float>, -math::pi<float>}; | |||
math::vector<float, 3> m_max{ math::pi<float>, math::pi<float>, math::pi<float>}; | |||
}; | |||
#endif // ANTKEEPER_ANIMATION_EULER_IK_CONSTRAINT_HPP |
@ -0,0 +1,54 @@ | |||
/* | |||
* 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/ik/constraints/swing-twist-ik-constraint.hpp> | |||
#include <cmath> | |||
void swing_twist_ik_constraint::set_twist_limit(float angle_min, float angle_max) | |||
{ | |||
m_cos_half_twist_min = std::cos(angle_min * 0.5f); | |||
m_sin_half_twist_min = std::sin(angle_min * 0.5f); | |||
m_cos_half_twist_max = std::cos(angle_max * 0.5f); | |||
m_sin_half_twist_max = std::sin(angle_max * 0.5f); | |||
} | |||
void swing_twist_ik_constraint::solve(math::quaternion<float>& q) | |||
{ | |||
constexpr math::vector<float, 3> twist_axis{0.0f, 0.0f, 1.0f}; | |||
// Decompose rotation into swing and twist components | |||
math::quaternion<float> swing; | |||
math::quaternion<float> twist; | |||
math::swing_twist(q, twist_axis, swing, twist); | |||
// Limit twist | |||
if (twist.z() < m_sin_half_twist_min) | |||
{ | |||
twist.z() = m_sin_half_twist_min; | |||
twist.w() = m_cos_half_twist_min; | |||
} | |||
else if (twist.z() > m_sin_half_twist_max) | |||
{ | |||
twist.z() = m_sin_half_twist_max; | |||
twist.w() = m_cos_half_twist_max; | |||
} | |||
// Re-compose rotation from swing and twist components | |||
q = math::normalize(swing * twist); | |||
} |
@ -0,0 +1,49 @@ | |||
/* | |||
* 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_SWING_TWIST_IK_CONSTRAINT_HPP | |||
#define ANTKEEPER_ANIMATION_SWING_TWIST_IK_CONSTRAINT_HPP | |||
#include <engine/animation/ik/ik-constraint.hpp> | |||
#include <engine/math/numbers.hpp> | |||
/** | |||
* IK constraint with cone-limited swing and angle-limited twist. | |||
*/ | |||
class swing_twist_ik_constraint: public ik_constraint | |||
{ | |||
public: | |||
void solve(math::quaternion<float>& q) override; | |||
/** | |||
* Sets the twist rotation limit. | |||
* | |||
* @param angle_min Minimum twist angle, in radians. | |||
* @param angle_max Maximum twist angle, in radians. | |||
*/ | |||
void set_twist_limit(float angle_min, float angle_max); | |||
private: | |||
float m_cos_half_twist_min{ 0}; | |||
float m_sin_half_twist_min{-1}; | |||
float m_cos_half_twist_max{ 0}; | |||
float m_sin_half_twist_max{ 1}; | |||
}; | |||
#endif // ANTKEEPER_ANIMATION_SWING_TWIST_IK_CONSTRAINT_HPP |
@ -0,0 +1,39 @@ | |||
/* | |||
* 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_IK_CONSTRAINT_HPP | |||
#define ANTKEEPER_ANIMATION_IK_CONSTRAINT_HPP | |||
#include <engine/math/quaternion.hpp> | |||
/** | |||
* Abstract base class for IK joint constraints. | |||
*/ | |||
class ik_constraint | |||
{ | |||
public: | |||
/** | |||
* Solves the constraint. | |||
* | |||
* @param[in,out] q Unit quaternion representing the rotation of a joint. | |||
*/ | |||
virtual void solve(math::quaternion<float>& q) = 0; | |||
}; | |||
#endif // ANTKEEPER_ANIMATION_IK_CONSTRAINT_HPP |
@ -0,0 +1,56 @@ | |||
/* | |||
* 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/ik/ik-rig.hpp> | |||
ik_rig::ik_rig(scene::skeletal_mesh& skeletal_mesh): | |||
m_skeletal_mesh(&skeletal_mesh), | |||
m_constraints(skeletal_mesh.get_pose().get_skeleton()->get_bone_count()) | |||
{} | |||
void ik_rig::set_constraint(bone_index_type index, std::shared_ptr<ik_constraint> constraint) | |||
{ | |||
m_constraints[index] = std::move(constraint); | |||
} | |||
void ik_rig::clear_constraints() | |||
{ | |||
for (auto& constraint: m_constraints) | |||
{ | |||
constraint.reset(); | |||
} | |||
} | |||
void ik_rig::solve() | |||
{ | |||
for (const auto& solver: m_solvers) | |||
{ | |||
solver->solve(); | |||
} | |||
} | |||
void ik_rig::add_solver(std::shared_ptr<ik_solver> solver) | |||
{ | |||
m_solvers.emplace_back(std::move(solver)); | |||
} | |||
void ik_rig::remove_solvers() | |||
{ | |||
m_solvers.clear(); | |||
} |
@ -0,0 +1,116 @@ | |||
/* | |||
* 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_IK_RIG_HPP | |||
#define ANTKEEPER_ANIMATION_IK_RIG_HPP | |||
#include <engine/scene/skeletal-mesh.hpp> | |||
#include <engine/animation/ik/ik-constraint.hpp> | |||
#include <engine/animation/ik/ik-solver.hpp> | |||
#include <memory> | |||
#include <vector> | |||
/** | |||
* | |||
*/ | |||
class ik_rig | |||
{ | |||
public: | |||
/** | |||
* Constructs an IK rig. | |||
* | |||
* @param skeletal_mesh Skeletal mesh with which to associate the IK rig. | |||
*/ | |||
explicit ik_rig(scene::skeletal_mesh& skeletal_mesh); | |||
/// Returns the skeleton with which the IK rig is associated. | |||
/// @{ | |||
[[nodiscard]] inline const scene::skeletal_mesh& get_skeletal_mesh() const noexcept | |||
{ | |||
return *m_skeletal_mesh; | |||
} | |||
[[nodiscard]] inline scene::skeletal_mesh& get_skeletal_mesh() noexcept | |||
{ | |||
return *m_skeletal_mesh; | |||
} | |||
/// @} | |||
/// @name Constraints | |||
/// @{ | |||
/** | |||
* Sets the IK constraint of a bone. | |||
* | |||
* @param index Index of a bone. | |||
* @param constraint IK constraint of the bone. | |||
*/ | |||
void set_constraint(bone_index_type index, std::shared_ptr<ik_constraint> constraint); | |||
/// Removes all constraints from the IK rig. | |||
void clear_constraints(); | |||
/** | |||
* Returns the IK constraint of a bone. | |||
* | |||
* @param index Index of a bone. | |||
* | |||
* @return Pointer to the IK constraint of the bone, or `nullptr` if the bone is unconstrained. | |||
*/ | |||
/// @{ | |||
[[nodiscard]] inline const ik_constraint* get_constraint(bone_index_type index) const | |||
{ | |||
return m_constraints[index].get(); | |||
} | |||
[[nodiscard]] inline ik_constraint* get_constraint(bone_index_type index) | |||
{ | |||
return m_constraints[index].get(); | |||
} | |||
/// @} | |||
/// @} | |||
/// @name Solvers | |||
/// @{ | |||
/** | |||
* Solves each solver in the IK rig. | |||
*/ | |||
void solve(); | |||
/** | |||
* Adds a solver to the IK rig. | |||
* | |||
* @param solver IK solver to add. | |||
*/ | |||
void add_solver(std::shared_ptr<ik_solver> solver); | |||
/** | |||
* Removes all solvers from the IK rig. | |||
*/ | |||
void remove_solvers(); | |||
/// @} | |||
private: | |||
scene::skeletal_mesh* m_skeletal_mesh{nullptr}; | |||
std::vector<std::shared_ptr<ik_constraint>> m_constraints; | |||
std::vector<std::shared_ptr<ik_solver>> m_solvers; | |||
}; | |||
#endif // ANTKEEPER_ANIMATION_IK_RIG_HPP |
@ -0,0 +1,35 @@ | |||
/* | |||
* 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_IK_SOLVER_HPP | |||
#define ANTKEEPER_ANIMATION_IK_SOLVER_HPP | |||
/** | |||
* Abstract base class for IK solvers. | |||
*/ | |||
class ik_solver | |||
{ | |||
public: | |||
/** | |||
* Transforms bones to find an inverse kinematic solution for an end effector. | |||
*/ | |||
virtual void solve() = 0; | |||
}; | |||
#endif // ANTKEEPER_ANIMATION_IK_SOLVER_HPP |
@ -0,0 +1,107 @@ | |||
/* | |||
* 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/ik/solvers/ccd-ik-solver.hpp> | |||
#include <engine/animation/ik/ik-rig.hpp> | |||
#include <engine/debug/log.hpp> | |||
#include <stdexcept> | |||
ccd_ik_solver::ccd_ik_solver(ik_rig& ik_rig, bone_index_type root_bone_index, bone_index_type effector_bone_index): | |||
m_ik_rig{&ik_rig} | |||
{ | |||
// Get reference to skeleton | |||
const auto& skeleton = *m_ik_rig->get_skeletal_mesh().get_pose().get_skeleton(); | |||
// Validate and count number of bones in bone chain | |||
std::size_t bone_count = 1; | |||
for (bone_index_type bone_index = effector_bone_index; bone_index != root_bone_index; ++bone_count) | |||
{ | |||
const auto parent_bone = skeleton.get_bone_parent(bone_index); | |||
if (parent_bone == bone_index) | |||
{ | |||
throw std::invalid_argument("Invalid bone chain"); | |||
} | |||
bone_index = parent_bone; | |||
} | |||
// Allocate and store bone indices | |||
m_bone_indices.resize(bone_count); | |||
m_bone_indices.front() = effector_bone_index; | |||
for (std::size_t i = 1; i < bone_count; ++i) | |||
{ | |||
m_bone_indices[i] = skeleton.get_bone_parent(m_bone_indices[i - 1]); | |||
} | |||
} | |||
void ccd_ik_solver::solve() | |||
{ | |||
// Get reference to skeletal mesh and its pose from the parent IK rig | |||
auto& skeletal_mesh = m_ik_rig->get_skeletal_mesh(); | |||
auto& pose = skeletal_mesh.get_pose(); | |||
// Get pose-space transform of end effector bone | |||
const auto& ps_effector_bone_transform = pose.get_absolute_transform(m_bone_indices.front()); | |||
// Transform goal position into pose-space | |||
const auto ps_goal_position = m_goal_position * skeletal_mesh.get_transform(); | |||
for (std::size_t i = 0; i < m_max_iterations; ++i) | |||
{ | |||
for (std::size_t j = 0; j < m_bone_indices.size(); ++j) | |||
{ | |||
// Transform end effector position into pose-space | |||
auto ps_effector_position = ps_effector_bone_transform * m_effector_position; | |||
// Check if end effector is within tolerable distance to goal position | |||
const auto sqr_distance = math::sqr_distance(ps_effector_position, ps_goal_position); | |||
if (sqr_distance <= m_sqr_distance_tolerance) | |||
{ | |||
return; | |||
} | |||
// Get index of current bone | |||
bone_index_type bone_index = m_bone_indices[j]; | |||
// Get pose-space and bone-space transforms of current bone | |||
const auto& ps_bone_transform = pose.get_absolute_transform(bone_index); | |||
const auto& bs_bone_transform = pose.get_relative_transform(bone_index); | |||
// Find pose-space direction vector from current bone to end effector | |||
const auto ps_effector_direction = math::normalize(ps_effector_position - ps_bone_transform.translation); | |||
// Find pose-space direction vector from current bone to IK goal | |||
const auto ps_goal_direction = math::normalize(ps_goal_position - ps_bone_transform.translation); | |||
// Calculate rotation of current bone that brings effector closer to goal | |||
auto bone_rotation = math::normalize(math::rotation(ps_effector_direction, ps_goal_direction, 1e-5f) * bs_bone_transform.rotation); | |||
// Apply current bone constraints to rotation | |||
if (auto* constraint = m_ik_rig->get_constraint(bone_index)) | |||
{ | |||
constraint->solve(bone_rotation); | |||
} | |||
// Rotate current bone | |||
pose.set_relative_rotation(bone_index, bone_rotation); | |||
//pose.update(bone_index, j + 1); | |||
pose.update(); | |||
} | |||
} | |||
} |
@ -0,0 +1,129 @@ | |||
/* | |||
* 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_CCD_IK_SOLVER_HPP | |||
#define ANTKEEPER_ANIMATION_CCD_IK_SOLVER_HPP | |||
#include <engine/animation/ik/ik-solver.hpp> | |||
#include <engine/animation/bone.hpp> | |||
#include <vector> | |||
class ik_rig; | |||
/** | |||
* Cyclic Coordinate Descent (CCD) IK solver. | |||
*/ | |||
class ccd_ik_solver: public ik_solver | |||
{ | |||
public: | |||
/** | |||
* Constructs a CCD IK solver. | |||
* | |||
* @param ik_rig IK rig with which to associate this IK solver. | |||
* @param root_bone_index Index of the first bone in the bone chain. | |||
* @param effector_bone_index Index of the last bone in the bone chain. | |||
* @param chain_length Number of bones in the IK chain. | |||
*/ | |||
ccd_ik_solver(ik_rig& ik_rig, bone_index_type root_bone_index, bone_index_type effector_bone_index); | |||
/// @name Solving | |||
/// @{ | |||
void solve() override; | |||
/** | |||
* Sets the maximum number of solving iterations. | |||
* | |||
* @param iterations Maximum number of solving iterations. | |||
*/ | |||
inline void set_max_iterations(std::size_t iterations) noexcept | |||
{ | |||
m_max_iterations = iterations; | |||
} | |||
/** | |||
* Sets the maximum tolerable distance between the goal and end effector. | |||
* | |||
* @param tolerance Tolerable distance between the goal and end effector. | |||
*/ | |||
inline void set_distance_tolerance(float distance) noexcept | |||
{ | |||
m_sqr_distance_tolerance = distance * distance; | |||
} | |||
/// Returns the maximum number of solving iterations. | |||
[[nodiscard]] inline std::size_t get_max_iterations() const noexcept | |||
{ | |||
return m_max_iterations; | |||
} | |||
/// @} | |||
/// @name Effector | |||
/// @{ | |||
/** | |||
* Sets the position of the end effector. | |||
* | |||
* @param position Position of the end effector, relative to the tip bone. | |||
*/ | |||
inline void set_effector_position(const math::vector<float, 3>& position) noexcept | |||
{ | |||
m_effector_position = position; | |||
} | |||
/// Returns the position of the end effector, relative to the tip bone. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_effector_position() const | |||
{ | |||
return m_effector_position; | |||
} | |||
/// @} | |||
/// @name Goal | |||
/// @{ | |||
/** | |||
* Thes the position of the IK goal. | |||
* | |||
* @param position IK goal position, in world-space. | |||
*/ | |||
inline void set_goal_position(const math::vector<float, 3>& position) noexcept | |||
{ | |||
m_goal_position = position; | |||
} | |||
/// Returns the position of goal, in world-space. | |||
[[nodiscard]] inline const math::vector<float, 3>& get_goal_position() const | |||
{ | |||
return m_goal_position; | |||
} | |||
/// @} | |||
private: | |||
ik_rig* m_ik_rig{nullptr}; | |||
std::size_t m_max_iterations{10}; | |||
std::vector<bone_index_type> m_bone_indices; | |||
math::vector<float, 3> m_effector_position{0.0f, 0.0f, 0.0f}; | |||
math::vector<float, 3> m_goal_position{0.0f, 0.0f, 0.0f}; | |||
float m_sqr_distance_tolerance{1e-5f}; | |||
}; | |||
#endif // ANTKEEPER_ANIMATION_CCD_IK_SOLVER_HPP |
@ -0,0 +1,32 @@ | |||
/* | |||
* 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_INPUT_UPDATE_EVENT_HPP | |||
#define ANTKEEPER_INPUT_UPDATE_EVENT_HPP | |||
namespace input { | |||
/** | |||
* Event generated after input events are polled. | |||
*/ | |||
struct update_event {}; | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_UPDATE_EVENT_HPP |
@ -0,0 +1,31 @@ | |||
/* | |||
* 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_GAME_IK_COMPONENT_HPP | |||
#define ANTKEEPER_GAME_IK_COMPONENT_HPP | |||
#include <engine/animation/ik/ik-rig.hpp> | |||
#include <memory> | |||
struct ik_component | |||
{ | |||
std::shared_ptr<ik_rig> rig; | |||
}; | |||
#endif // ANTKEEPER_GAME_IK_COMPONENT_HPP |
@ -0,0 +1,45 @@ | |||
/* | |||
* 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 "game/systems/ik-system.hpp" | |||
#include "game/components/ik-component.hpp" | |||
#include <engine/entity/id.hpp> | |||
#include <algorithm> | |||
#include <execution> | |||
ik_system::ik_system(entity::registry& registry): | |||
updatable_system(registry) | |||
{} | |||
void ik_system::update(float t, float dt) | |||
{ | |||
auto view = registry.view<ik_component>(); | |||
std::for_each | |||
( | |||
std::execution::par_unseq, | |||
view.begin(), | |||
view.end(), | |||
[&](auto entity_id) | |||
{ | |||
const auto& component = view.get<ik_component>(entity_id); | |||
component.rig->solve(); | |||
} | |||
); | |||
} |
@ -0,0 +1,36 @@ | |||
/* | |||
* 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_GAME_IK_SYSTEM_HPP | |||
#define ANTKEEPER_GAME_IK_SYSTEM_HPP | |||
#include "game/systems/updatable-system.hpp" | |||
/** | |||
* | |||
*/ | |||
class ik_system: | |||
public updatable_system | |||
{ | |||
public: | |||
explicit ik_system(entity::registry& registry); | |||
void update(float t, float dt) override; | |||
}; | |||
#endif // ANTKEEPER_GAME_IK_SYSTEM_HPP |