From 95f18215e677bce33693737942925c0c2a0b8741 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 14 Jul 2022 18:25:39 +0800 Subject: [PATCH] Revise skeletal animation-related types --- CMakeLists.txt | 1 + src/animation/bone.hpp | 119 +++++ src/animation/pose.cpp | 39 ++ .../skeleton.hpp => animation/pose.hpp} | 45 +- src/{render => animation}/skeleton.cpp | 19 +- .../bone.hpp => animation/skeleton.hpp} | 30 +- src/game/ant/morphogenesis.cpp | 472 +++++++++--------- src/game/state/nuptial-flight.cpp | 4 +- src/game/world.cpp | 2 +- src/render/model.hpp | 4 +- src/render/operation.hpp | 3 +- src/resources/model-loader.cpp | 58 ++- src/scene/model-instance.hpp | 3 +- 13 files changed, 454 insertions(+), 345 deletions(-) create mode 100644 src/animation/bone.hpp create mode 100644 src/animation/pose.cpp rename src/{render/skeleton.hpp => animation/pose.hpp} (54%) rename src/{render => animation}/skeleton.cpp (69%) rename src/{render/bone.hpp => animation/skeleton.hpp} (65%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b94016..7faddc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.7) + option(VERSION_STRING "Project version string" "0.0.0") project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX) diff --git a/src/animation/bone.hpp b/src/animation/bone.hpp new file mode 100644 index 0000000..4b66f54 --- /dev/null +++ b/src/animation/bone.hpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 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 . + */ + +#ifndef ANTKEEPER_ANIMATION_BONE_HPP +#define ANTKEEPER_ANIMATION_BONE_HPP + +#include + +/// Mask to extract the index of a bone. +constexpr std::uint16_t bone_index_mask = 0xFF; + +/** + * Skeletal animation bone identifier, consisting of a bone index in the lower half, and a parent bone index in the upper half. + */ +typedef std::uint16_t bone; + +/** + * 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. + */ + bool operator()(const bone& lhs, const bone& rhs) const; +}; + +/** + * Constructs a bone identifier. + * + * @param index Index of the bone. + * @param parent_index Index of the parent bone. + * @return Bone identifier. + */ +bone make_bone(std::uint8_t index, std::uint8_t parent_index); + +/** + * Constructs an orphan bone identifier. + * + * @param index Index of the orphan bone. + * @return Orphan bone identifier. + */ +bone make_bone(std::uint8_t index); + +/** + * Returns the index of a bone. + * + * @param x Bone identifier. + * @return Index of the bone. + */ +std::uint8_t bone_index(bone x); + +/** + * Returns the parent index of a bone. + * + * @param x Bone identifier. + * @return Index of the parent bone. + */ +std::uint8_t bone_parent_index(bone x); + +/** + * Returns `true` if a bone has a parent, `false` otherwise. + * + * @param x Bone identifier. + * @return Bone parent status. + */ +bool bone_has_parent(bone x); + +inline bool bone_index_compare::operator()(const bone& lhs, const bone& rhs) const +{ + return (lhs & bone_index_mask) < (rhs & bone_index_mask); +} + +inline bone make_bone(std::uint8_t index, std::uint8_t parent_index) +{ + return (static_cast(parent_index) << 8) | index; +} + +inline bone make_bone(std::uint8_t index) +{ + return make_bone(index, index); +} + +inline std::uint8_t bone_index(bone x) +{ + return static_cast(x & bone_index_mask); +} + +inline std::uint8_t bone_parent_index(bone x) +{ + return static_cast(x >> 8); +} + +inline bool bone_has_parent(bone x) +{ + return (x & bone_index_mask) != (x >> 8); +} + +#endif // ANTKEEPER_ANIMATION_BONE_HPP diff --git a/src/animation/pose.cpp b/src/animation/pose.cpp new file mode 100644 index 0000000..bcce652 --- /dev/null +++ b/src/animation/pose.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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 . + */ + +#include "animation/pose.hpp" +#include "math/transform-operators.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; + } + } +} diff --git a/src/render/skeleton.hpp b/src/animation/pose.hpp similarity index 54% rename from src/render/skeleton.hpp rename to src/animation/pose.hpp index f6cd1f3..3ffd714 100644 --- a/src/render/skeleton.hpp +++ b/src/animation/pose.hpp @@ -17,37 +17,26 @@ * along with Antkeeper source code. If not, see . */ -#ifndef ANTKEEPER_RENDER_SKELETON_HPP -#define ANTKEEPER_RENDER_SKELETON_HPP +#ifndef ANTKEEPER_ANIMATION_POSE_HPP +#define ANTKEEPER_ANIMATION_POSE_HPP -#include "render/bone.hpp" -#include -#include -#include -#include - -namespace render { +#include "animation/bone.hpp" +#include "math/transform-type.hpp" +#include /** - * Skeletal animation skeleton. + * Skeletal animation pose. */ -struct skeleton -{ - /// Collection of bones. - std::vector bones; - - /// Maps bone names to bone indices. - std::unordered_map bone_map; - - /** - * Calculates the global transform of a bone. - * - * @param index Index of the bone. - * @return Global transform of the bone. - */ - math::transform concatenate(std::uint16_t index) const; -}; +typedef std::map, bone_index_compare> pose; -} // namespace render +/** + * 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); -#endif // ANTKEEPER_RENDER_SKELETON_HPP +#endif // ANTKEEPER_ANIMATION_POSE_HPP diff --git a/src/render/skeleton.cpp b/src/animation/skeleton.cpp similarity index 69% rename from src/render/skeleton.cpp rename to src/animation/skeleton.cpp index aaaa4d7..1d563b6 100644 --- a/src/render/skeleton.cpp +++ b/src/animation/skeleton.cpp @@ -17,23 +17,6 @@ * along with Antkeeper source code. If not, see . */ -#include "render/skeleton.hpp" +#include "animation/skeleton.hpp" #include "math/transform-operators.hpp" -namespace render { - -math::transform skeleton::concatenate(std::uint16_t index) const -{ - const bone* bone = &bones[index]; - math::transform transform = bone->transform; - - while (bone->parent) - { - transform = bone->parent->transform * transform; - bone = bone->parent; - } - - return transform; -} - -} // namespace render diff --git a/src/render/bone.hpp b/src/animation/skeleton.hpp similarity index 65% rename from src/render/bone.hpp rename to src/animation/skeleton.hpp index a23bce3..7339eb7 100644 --- a/src/render/bone.hpp +++ b/src/animation/skeleton.hpp @@ -17,28 +17,24 @@ * along with Antkeeper source code. If not, see . */ -#ifndef ANTKEEPER_RENDER_BONE_HPP -#define ANTKEEPER_RENDER_BONE_HPP +#ifndef ANTKEEPER_ANIMATION_SKELETON_HPP +#define ANTKEEPER_ANIMATION_SKELETON_HPP -#include "math/transform-type.hpp" - -namespace render { +#include "animation/bone.hpp" +#include "animation/pose.hpp" +#include +#include /** - * Skeletal animation bone. + * Skeletal animation skeleton. */ -struct bone +struct skeleton { - /// Pointer to the parent bone. - bone* parent; - - /// Local transform, relative to the parent bone. - math::transform transform; + /// Bone-space bind pose of the skeleton. + pose bind_pose; - /// Length of the bone. - float length; + /// Maps bone names to bone identifiers. + std::unordered_map bone_map; }; -} // namespace render - -#endif // ANTKEEPER_RENDER_BONE_HPP +#endif // ANTKEEPER_ANIMATION_SKELETON_HPP diff --git a/src/game/ant/morphogenesis.cpp b/src/game/ant/morphogenesis.cpp index 1ef5663..36eb03c 100644 --- a/src/game/ant/morphogenesis.cpp +++ b/src/game/ant/morphogenesis.cpp @@ -43,8 +43,8 @@ static 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_set& old_bone_indices, - std::uint16_t new_bone_index, + const std::unordered_set& old_bone_indices, + std::uint8_t new_bone_index, const math::transform& transform ); static geom::aabb calculate_bounds(std::uint8_t* vertex_data, std::size_t index_count, const gl::vertex_attribute& position_attribute); @@ -295,21 +295,21 @@ render::model* build_model bone_index_attribute = &it->second; // Get body part skeletons - const render::skeleton& mesosoma_skeleton = mesosoma->get_skeleton(); - const render::skeleton& legs_skeleton = legs->get_skeleton(); - const render::skeleton& head_skeleton = head->get_skeleton(); - const render::skeleton& mandibles_skeleton = mandibles->get_skeleton(); - const render::skeleton& antennae_skeleton = antennae->get_skeleton(); - const render::skeleton& waist_skeleton = waist->get_skeleton(); - const render::skeleton& gaster_skeleton = gaster->get_skeleton(); - const render::skeleton* sting_skeleton = (sting) ? &sting->get_skeleton() : nullptr; - const render::skeleton* eyes_skeleton = (eyes) ? &eyes->get_skeleton() : nullptr; - const render::skeleton* lateral_ocelli_skeleton = (lateral_ocelli) ? &lateral_ocelli->get_skeleton() : nullptr; - const render::skeleton* median_ocellus_skeleton = (median_ocellus) ? &median_ocellus->get_skeleton() : nullptr; + const ::skeleton& mesosoma_skeleton = mesosoma->get_skeleton(); + const ::skeleton& legs_skeleton = legs->get_skeleton(); + const ::skeleton& head_skeleton = head->get_skeleton(); + const ::skeleton& mandibles_skeleton = mandibles->get_skeleton(); + const ::skeleton& antennae_skeleton = antennae->get_skeleton(); + const ::skeleton& waist_skeleton = waist->get_skeleton(); + const ::skeleton& gaster_skeleton = gaster->get_skeleton(); + const ::skeleton* sting_skeleton = (sting) ? &sting->get_skeleton() : nullptr; + const ::skeleton* eyes_skeleton = (eyes) ? &eyes->get_skeleton() : nullptr; + const ::skeleton* lateral_ocelli_skeleton = (lateral_ocelli) ? &lateral_ocelli->get_skeleton() : nullptr; + const ::skeleton* median_ocellus_skeleton = (median_ocellus) ? &median_ocellus->get_skeleton() : nullptr; bool postpetiole = (waist_skeleton.bone_map.find("postpetiole") != waist_skeleton.bone_map.end()); // Allocate skeleton bones - render::skeleton& skeleton = model->get_skeleton(); + ::skeleton& skeleton = model->get_skeleton(); std::size_t bone_count = 34; if (postpetiole) bone_count += 1; @@ -319,219 +319,225 @@ render::model* build_model bone_count += 2; if (hindwings) bone_count += 2; - skeleton.bones.resize(bone_count); // Assign bone indices - std::uint16_t bone_index = 0; - std::uint16_t mesosoma_bone_index = bone_index++; - std::uint16_t foreleg_coxa_l_bone_index = bone_index++; - std::uint16_t foreleg_coxa_r_bone_index = bone_index++; - std::uint16_t foreleg_femur_l_bone_index = bone_index++; - std::uint16_t foreleg_femur_r_bone_index = bone_index++; - std::uint16_t foreleg_tibia_l_bone_index = bone_index++; - std::uint16_t foreleg_tibia_r_bone_index = bone_index++; - std::uint16_t foreleg_tarsus_l_bone_index = bone_index++; - std::uint16_t foreleg_tarsus_r_bone_index = bone_index++; - std::uint16_t midleg_coxa_l_bone_index = bone_index++; - std::uint16_t midleg_coxa_r_bone_index = bone_index++; - std::uint16_t midleg_femur_l_bone_index = bone_index++; - std::uint16_t midleg_femur_r_bone_index = bone_index++; - std::uint16_t midleg_tibia_l_bone_index = bone_index++; - std::uint16_t midleg_tibia_r_bone_index = bone_index++; - std::uint16_t midleg_tarsus_l_bone_index = bone_index++; - std::uint16_t midleg_tarsus_r_bone_index = bone_index++; - std::uint16_t hindleg_coxa_l_bone_index = bone_index++; - std::uint16_t hindleg_coxa_r_bone_index = bone_index++; - std::uint16_t hindleg_femur_l_bone_index = bone_index++; - std::uint16_t hindleg_femur_r_bone_index = bone_index++; - std::uint16_t hindleg_tibia_l_bone_index = bone_index++; - std::uint16_t hindleg_tibia_r_bone_index = bone_index++; - std::uint16_t hindleg_tarsus_l_bone_index = bone_index++; - std::uint16_t hindleg_tarsus_r_bone_index = bone_index++; - std::uint16_t head_bone_index = bone_index++; - std::uint16_t mandible_l_bone_index = bone_index++; - std::uint16_t mandible_r_bone_index = bone_index++; - std::uint16_t scape_l_bone_index = bone_index++; - std::uint16_t scape_r_bone_index = bone_index++; - std::uint16_t pedicel_l_bone_index = bone_index++; - std::uint16_t pedicel_r_bone_index = bone_index++; - std::uint16_t petiole_bone_index = bone_index++; - std::uint16_t postpetiole_bone_index = (postpetiole) ? bone_index++ : static_cast(bone_count); - std::uint16_t gaster_bone_index = bone_index++; - std::uint16_t sting_bone_index = (sting) ? bone_index++ : static_cast(bone_count); - - // Get references and pointers to bones - render::bone& mesosoma_bone = skeleton.bones[mesosoma_bone_index]; - render::bone& foreleg_coxa_l_bone = skeleton.bones[foreleg_coxa_l_bone_index]; - render::bone& foreleg_coxa_r_bone = skeleton.bones[foreleg_coxa_r_bone_index]; - render::bone& foreleg_femur_l_bone = skeleton.bones[foreleg_femur_l_bone_index]; - render::bone& foreleg_femur_r_bone = skeleton.bones[foreleg_femur_r_bone_index]; - render::bone& foreleg_tibia_l_bone = skeleton.bones[foreleg_tibia_l_bone_index]; - render::bone& foreleg_tibia_r_bone = skeleton.bones[foreleg_tibia_r_bone_index]; - render::bone& foreleg_tarsus_l_bone = skeleton.bones[foreleg_tarsus_l_bone_index]; - render::bone& foreleg_tarsus_r_bone = skeleton.bones[foreleg_tarsus_r_bone_index]; - render::bone& midleg_coxa_l_bone = skeleton.bones[midleg_coxa_l_bone_index]; - render::bone& midleg_coxa_r_bone = skeleton.bones[midleg_coxa_r_bone_index]; - render::bone& midleg_femur_l_bone = skeleton.bones[midleg_femur_l_bone_index]; - render::bone& midleg_femur_r_bone = skeleton.bones[midleg_femur_r_bone_index]; - render::bone& midleg_tibia_l_bone = skeleton.bones[midleg_tibia_l_bone_index]; - render::bone& midleg_tibia_r_bone = skeleton.bones[midleg_tibia_r_bone_index]; - render::bone& midleg_tarsus_l_bone = skeleton.bones[midleg_tarsus_l_bone_index]; - render::bone& midleg_tarsus_r_bone = skeleton.bones[midleg_tarsus_r_bone_index]; - render::bone& hindleg_coxa_l_bone = skeleton.bones[hindleg_coxa_l_bone_index]; - render::bone& hindleg_coxa_r_bone = skeleton.bones[hindleg_coxa_r_bone_index]; - render::bone& hindleg_femur_l_bone = skeleton.bones[hindleg_femur_l_bone_index]; - render::bone& hindleg_femur_r_bone = skeleton.bones[hindleg_femur_r_bone_index]; - render::bone& hindleg_tibia_l_bone = skeleton.bones[hindleg_tibia_l_bone_index]; - render::bone& hindleg_tibia_r_bone = skeleton.bones[hindleg_tibia_r_bone_index]; - render::bone& hindleg_tarsus_l_bone = skeleton.bones[hindleg_tarsus_l_bone_index]; - render::bone& hindleg_tarsus_r_bone = skeleton.bones[hindleg_tarsus_r_bone_index]; - render::bone& head_bone = skeleton.bones[head_bone_index]; - render::bone& mandible_l_bone = skeleton.bones[mandible_l_bone_index]; - render::bone& mandible_r_bone = skeleton.bones[mandible_r_bone_index]; - render::bone& scape_l_bone = skeleton.bones[scape_l_bone_index]; - render::bone& scape_r_bone = skeleton.bones[scape_r_bone_index]; - render::bone& pedicel_l_bone = skeleton.bones[pedicel_l_bone_index]; - render::bone& pedicel_r_bone = skeleton.bones[pedicel_r_bone_index]; - render::bone& petiole_bone = skeleton.bones[petiole_bone_index]; - render::bone* postpetiole_bone = (postpetiole) ? &skeleton.bones[postpetiole_bone_index] : nullptr; - render::bone& gaster_bone = skeleton.bones[gaster_bone_index]; - render::bone* sting_bone = (sting) ? &skeleton.bones[sting_bone_index] : nullptr; - - // Skeleton mesosoma + std::uint8_t bone_index = 0; + std::uint8_t mesosoma_bone_index = bone_index++; + std::uint8_t foreleg_coxa_l_bone_index = bone_index++; + std::uint8_t foreleg_coxa_r_bone_index = bone_index++; + std::uint8_t foreleg_femur_l_bone_index = bone_index++; + std::uint8_t foreleg_femur_r_bone_index = bone_index++; + std::uint8_t foreleg_tibia_l_bone_index = bone_index++; + std::uint8_t foreleg_tibia_r_bone_index = bone_index++; + std::uint8_t foreleg_tarsus_l_bone_index = bone_index++; + std::uint8_t foreleg_tarsus_r_bone_index = bone_index++; + std::uint8_t midleg_coxa_l_bone_index = bone_index++; + std::uint8_t midleg_coxa_r_bone_index = bone_index++; + std::uint8_t midleg_femur_l_bone_index = bone_index++; + std::uint8_t midleg_femur_r_bone_index = bone_index++; + std::uint8_t midleg_tibia_l_bone_index = bone_index++; + std::uint8_t midleg_tibia_r_bone_index = bone_index++; + std::uint8_t midleg_tarsus_l_bone_index = bone_index++; + std::uint8_t midleg_tarsus_r_bone_index = bone_index++; + std::uint8_t hindleg_coxa_l_bone_index = bone_index++; + std::uint8_t hindleg_coxa_r_bone_index = bone_index++; + std::uint8_t hindleg_femur_l_bone_index = bone_index++; + std::uint8_t hindleg_femur_r_bone_index = bone_index++; + std::uint8_t hindleg_tibia_l_bone_index = bone_index++; + std::uint8_t hindleg_tibia_r_bone_index = bone_index++; + std::uint8_t hindleg_tarsus_l_bone_index = bone_index++; + std::uint8_t hindleg_tarsus_r_bone_index = bone_index++; + std::uint8_t head_bone_index = bone_index++; + std::uint8_t mandible_l_bone_index = bone_index++; + std::uint8_t mandible_r_bone_index = bone_index++; + std::uint8_t scape_l_bone_index = bone_index++; + std::uint8_t scape_r_bone_index = bone_index++; + std::uint8_t pedicel_l_bone_index = bone_index++; + std::uint8_t pedicel_r_bone_index = bone_index++; + std::uint8_t petiole_bone_index = bone_index++; + std::uint8_t postpetiole_bone_index = (postpetiole) ? bone_index++ : static_cast(bone_count); + std::uint8_t gaster_bone_index = bone_index++; + std::uint8_t sting_bone_index = (sting) ? bone_index++ : static_cast(bone_count); + + // Construct bone identifiers + ::bone mesosoma_bone = make_bone(mesosoma_bone_index); + ::bone foreleg_coxa_l_bone = make_bone(foreleg_coxa_l_bone_index); + ::bone foreleg_coxa_r_bone = make_bone(foreleg_coxa_r_bone_index); + ::bone foreleg_femur_l_bone = make_bone(foreleg_femur_l_bone_index, foreleg_coxa_l_bone_index); + ::bone foreleg_femur_r_bone = make_bone(foreleg_femur_r_bone_index, foreleg_coxa_r_bone_index); + ::bone foreleg_tibia_l_bone = make_bone(foreleg_tibia_l_bone_index, foreleg_femur_l_bone_index); + ::bone foreleg_tibia_r_bone = make_bone(foreleg_tibia_r_bone_index, foreleg_femur_r_bone_index); + ::bone foreleg_tarsus_l_bone = make_bone(foreleg_tarsus_l_bone_index, foreleg_tibia_l_bone_index); + ::bone foreleg_tarsus_r_bone = make_bone(foreleg_tarsus_r_bone_index, foreleg_tibia_r_bone_index); + ::bone midleg_coxa_l_bone = make_bone(midleg_coxa_l_bone_index); + ::bone midleg_coxa_r_bone = make_bone(midleg_coxa_r_bone_index); + ::bone midleg_femur_l_bone = make_bone(midleg_femur_l_bone_index, midleg_coxa_l_bone_index); + ::bone midleg_femur_r_bone = make_bone(midleg_femur_r_bone_index, midleg_coxa_r_bone_index); + ::bone midleg_tibia_l_bone = make_bone(midleg_tibia_l_bone_index, midleg_femur_l_bone_index); + ::bone midleg_tibia_r_bone = make_bone(midleg_tibia_r_bone_index, midleg_femur_r_bone_index); + ::bone midleg_tarsus_l_bone = make_bone(midleg_tarsus_l_bone_index, midleg_tibia_l_bone_index); + ::bone midleg_tarsus_r_bone = make_bone(midleg_tarsus_r_bone_index, midleg_tibia_r_bone_index); + ::bone hindleg_coxa_l_bone = make_bone(hindleg_coxa_l_bone_index); + ::bone hindleg_coxa_r_bone = make_bone(hindleg_coxa_r_bone_index); + ::bone hindleg_femur_l_bone = make_bone(hindleg_femur_l_bone_index, hindleg_coxa_l_bone_index); + ::bone hindleg_femur_r_bone = make_bone(hindleg_femur_r_bone_index, hindleg_coxa_r_bone_index); + ::bone hindleg_tibia_l_bone = make_bone(hindleg_tibia_l_bone_index, hindleg_femur_l_bone_index); + ::bone hindleg_tibia_r_bone = make_bone(hindleg_tibia_r_bone_index, hindleg_femur_r_bone_index); + ::bone hindleg_tarsus_l_bone = make_bone(hindleg_tarsus_l_bone_index, hindleg_tibia_l_bone_index); + ::bone hindleg_tarsus_r_bone = make_bone(hindleg_tarsus_r_bone_index, hindleg_tibia_r_bone_index); + ::bone head_bone = make_bone(head_bone_index, mesosoma_bone_index); + ::bone mandible_l_bone = make_bone(mandible_l_bone_index, head_bone_index); + ::bone mandible_r_bone = make_bone(mandible_r_bone_index, head_bone_index); + ::bone scape_l_bone = make_bone(scape_l_bone_index, head_bone_index); + ::bone scape_r_bone = make_bone(scape_r_bone_index, head_bone_index); + ::bone pedicel_l_bone = make_bone(pedicel_l_bone_index, scape_l_bone_index); + ::bone pedicel_r_bone = make_bone(pedicel_r_bone_index, scape_r_bone_index); + ::bone petiole_bone = make_bone(petiole_bone_index, mesosoma_bone_index); + ::bone postpetiole_bone = make_bone(postpetiole_bone_index, petiole_bone_index); + ::bone gaster_bone = make_bone(gaster_bone_index, (postpetiole) ? postpetiole_bone_index : petiole_bone_index); + ::bone sting_bone = make_bone(sting_bone_index, gaster_bone_index); + + // Map bone names to bones + skeleton.bone_map["mesosoma"] = mesosoma_bone; + skeleton.bone_map["foreleg_coxa_l"] = foreleg_coxa_l_bone; + skeleton.bone_map["foreleg_coxa_r"] = foreleg_coxa_r_bone; + skeleton.bone_map["foreleg_femur_l"] = foreleg_femur_l_bone; + skeleton.bone_map["foreleg_femur_r"] = foreleg_femur_r_bone; + skeleton.bone_map["foreleg_tibia_l"] = foreleg_tibia_l_bone; + skeleton.bone_map["foreleg_tibia_r"] = foreleg_tibia_r_bone; + skeleton.bone_map["foreleg_tarsus_l"] = foreleg_tarsus_l_bone; + skeleton.bone_map["foreleg_tarsus_r"] = foreleg_tarsus_r_bone; + skeleton.bone_map["midleg_coxa_l"] = midleg_coxa_l_bone; + skeleton.bone_map["midleg_coxa_r"] = midleg_coxa_r_bone; + skeleton.bone_map["midleg_femur_l"] = midleg_femur_l_bone; + skeleton.bone_map["midleg_femur_r"] = midleg_femur_r_bone; + skeleton.bone_map["midleg_tibia_l"] = midleg_tibia_l_bone; + skeleton.bone_map["midleg_tibia_r"] = midleg_tibia_r_bone; + skeleton.bone_map["midleg_tarsus_l"] = midleg_tarsus_l_bone; + skeleton.bone_map["midleg_tarsus_r"] = midleg_tarsus_r_bone; + skeleton.bone_map["hindleg_coxa_l"] = hindleg_coxa_l_bone; + skeleton.bone_map["hindleg_coxa_r"] = hindleg_coxa_r_bone; + skeleton.bone_map["hindleg_femur_l"] = hindleg_femur_l_bone; + skeleton.bone_map["hindleg_femur_r"] = hindleg_femur_r_bone; + skeleton.bone_map["hindleg_tibia_l"] = hindleg_tibia_l_bone; + skeleton.bone_map["hindleg_tibia_r"] = hindleg_tibia_r_bone; + skeleton.bone_map["hindleg_tarsus_l"] = hindleg_tarsus_l_bone; + skeleton.bone_map["hindleg_tarsus_r"] = hindleg_tarsus_r_bone; + skeleton.bone_map["head"] = head_bone; + skeleton.bone_map["mandible_l"] = mandible_l_bone; + skeleton.bone_map["mandible_r"] = mandible_r_bone; + skeleton.bone_map["scape_l"] = scape_l_bone; + skeleton.bone_map["scape_r"] = scape_r_bone; + skeleton.bone_map["pedicel_l"] = pedicel_l_bone; + skeleton.bone_map["pedicel_r"] = pedicel_r_bone; + skeleton.bone_map["petiole"] = petiole_bone; + if (postpetiole) + skeleton.bone_map["postpetiole"] = postpetiole_bone; + skeleton.bone_map["gaster"] = gaster_bone; + if (sting) + skeleton.bone_map["sting"] = sting_bone; + + // Get reference to skeleton bind pose + pose& bind_pose = skeleton.bind_pose; + + // Skeleton mesosoma pose if (auto it = mesosoma_skeleton.bone_map.find("mesosoma"); it != mesosoma_skeleton.bone_map.end()) - mesosoma_bone = mesosoma_skeleton.bones[it->second]; - mesosoma_bone.parent = nullptr; + bind_pose[mesosoma_bone] = mesosoma_skeleton.bind_pose.at(it->second); - // Skeleton forelegs + // Skeleton forelegs pose if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_l"); it != legs_skeleton.bone_map.end()) - foreleg_coxa_l_bone = legs_skeleton.bones[it->second]; - foreleg_coxa_l_bone.parent = &mesosoma_bone; + bind_pose[foreleg_coxa_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_r"); it != legs_skeleton.bone_map.end()) - foreleg_coxa_r_bone = legs_skeleton.bones[it->second]; - foreleg_coxa_r_bone.parent = &mesosoma_bone; + bind_pose[foreleg_coxa_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("foreleg_femur_l"); it != legs_skeleton.bone_map.end()) - foreleg_femur_l_bone = legs_skeleton.bones[it->second]; - foreleg_femur_l_bone.parent = &foreleg_coxa_l_bone; + bind_pose[foreleg_femur_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("foreleg_femur_r"); it != legs_skeleton.bone_map.end()) - foreleg_femur_r_bone = legs_skeleton.bones[it->second]; - foreleg_femur_r_bone.parent = &foreleg_coxa_r_bone; + bind_pose[foreleg_femur_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_l"); it != legs_skeleton.bone_map.end()) - foreleg_tibia_l_bone = legs_skeleton.bones[it->second]; - foreleg_tibia_l_bone.parent = &foreleg_femur_l_bone; + bind_pose[foreleg_tibia_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_r"); it != legs_skeleton.bone_map.end()) - foreleg_tibia_r_bone = legs_skeleton.bones[it->second]; - foreleg_tibia_r_bone.parent = &foreleg_femur_r_bone; + bind_pose[foreleg_tibia_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus_l"); it != legs_skeleton.bone_map.end()) - foreleg_tarsus_l_bone = legs_skeleton.bones[it->second]; - foreleg_tarsus_l_bone.parent = &foreleg_tibia_l_bone; + bind_pose[foreleg_tarsus_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus_r"); it != legs_skeleton.bone_map.end()) - foreleg_tarsus_r_bone = legs_skeleton.bones[it->second]; - foreleg_tarsus_r_bone.parent = &foreleg_tibia_r_bone; + bind_pose[foreleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second); - // Skeleton midlegs + // Skeleton midlegs pose if (auto it = legs_skeleton.bone_map.find("midleg_coxa_l"); it != legs_skeleton.bone_map.end()) - midleg_coxa_l_bone = legs_skeleton.bones[it->second]; - midleg_coxa_l_bone.parent = &mesosoma_bone; + bind_pose[midleg_coxa_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("midleg_coxa_r"); it != legs_skeleton.bone_map.end()) - midleg_coxa_r_bone = legs_skeleton.bones[it->second]; - midleg_coxa_r_bone.parent = &mesosoma_bone; + bind_pose[midleg_coxa_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("midleg_femur_l"); it != legs_skeleton.bone_map.end()) - midleg_femur_l_bone = legs_skeleton.bones[it->second]; - midleg_femur_l_bone.parent = &midleg_coxa_l_bone; + bind_pose[midleg_femur_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("midleg_femur_r"); it != legs_skeleton.bone_map.end()) - midleg_femur_r_bone = legs_skeleton.bones[it->second]; - midleg_femur_r_bone.parent = &midleg_coxa_r_bone; + bind_pose[midleg_femur_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("midleg_tibia_l"); it != legs_skeleton.bone_map.end()) - midleg_tibia_l_bone = legs_skeleton.bones[it->second]; - midleg_tibia_l_bone.parent = &midleg_femur_l_bone; + bind_pose[midleg_tibia_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("midleg_tibia_r"); it != legs_skeleton.bone_map.end()) - midleg_tibia_r_bone = legs_skeleton.bones[it->second]; - midleg_tibia_r_bone.parent = &midleg_femur_r_bone; + bind_pose[midleg_tibia_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("midleg_tarsus_l"); it != legs_skeleton.bone_map.end()) - midleg_tarsus_l_bone = legs_skeleton.bones[it->second]; - midleg_tarsus_l_bone.parent = &midleg_tibia_l_bone; + bind_pose[midleg_tarsus_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("midleg_tarsus_r"); it != legs_skeleton.bone_map.end()) - midleg_tarsus_r_bone = legs_skeleton.bones[it->second]; - midleg_tarsus_r_bone.parent = &midleg_tibia_r_bone; + bind_pose[midleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second); - // Skeleton hindlegs + // Skeleton hindlegs pose if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_l"); it != legs_skeleton.bone_map.end()) - hindleg_coxa_l_bone = legs_skeleton.bones[it->second]; - hindleg_coxa_l_bone.parent = &mesosoma_bone; + bind_pose[hindleg_coxa_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_r"); it != legs_skeleton.bone_map.end()) - hindleg_coxa_r_bone = legs_skeleton.bones[it->second]; - hindleg_coxa_r_bone.parent = &mesosoma_bone; + bind_pose[hindleg_coxa_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("hindleg_femur_l"); it != legs_skeleton.bone_map.end()) - hindleg_femur_l_bone = legs_skeleton.bones[it->second]; - hindleg_femur_l_bone.parent = &hindleg_coxa_l_bone; + bind_pose[hindleg_femur_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("hindleg_femur_r"); it != legs_skeleton.bone_map.end()) - hindleg_femur_r_bone = legs_skeleton.bones[it->second]; - hindleg_femur_r_bone.parent = &hindleg_coxa_r_bone; + bind_pose[hindleg_femur_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_l"); it != legs_skeleton.bone_map.end()) - hindleg_tibia_l_bone = legs_skeleton.bones[it->second]; - hindleg_tibia_l_bone.parent = &hindleg_femur_l_bone; + bind_pose[hindleg_tibia_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_r"); it != legs_skeleton.bone_map.end()) - hindleg_tibia_r_bone = legs_skeleton.bones[it->second]; - hindleg_tibia_r_bone.parent = &hindleg_femur_r_bone; + bind_pose[hindleg_tibia_r_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus_l"); it != legs_skeleton.bone_map.end()) - hindleg_tarsus_l_bone = legs_skeleton.bones[it->second]; - hindleg_tarsus_l_bone.parent = &hindleg_tibia_l_bone; + bind_pose[hindleg_tarsus_l_bone] = legs_skeleton.bind_pose.at(it->second); if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus_r"); it != legs_skeleton.bone_map.end()) - hindleg_tarsus_r_bone = legs_skeleton.bones[it->second]; - hindleg_tarsus_r_bone.parent = &hindleg_tibia_r_bone; + bind_pose[hindleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second); - // Skeleton head - if (auto it = head_skeleton.bone_map.find("head"); it != head_skeleton.bone_map.end()) - head_bone = head_skeleton.bones[it->second]; - head_bone.parent = &mesosoma_bone; + // Skeleton head pose + bind_pose[head_bone] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head")) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("head")); - // Skeleton mandibles - if (auto it = mandibles_skeleton.bone_map.find("mandible_l"); it != mandibles_skeleton.bone_map.end()) - mandible_l_bone = mandibles_skeleton.bones[it->second]; - mandible_l_bone.parent = &head_bone; - if (auto it = mandibles_skeleton.bone_map.find("mandible_r"); it != mandibles_skeleton.bone_map.end()) - mandible_r_bone = mandibles_skeleton.bones[it->second]; - mandible_r_bone.parent = &head_bone; + // Skeleton mandibles pose + bind_pose[mandible_l_bone] = 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[mandible_r_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r")) * mandibles_skeleton.bind_pose.at(mandibles_skeleton.bone_map.at("mandible_r")); - // Skeleton antennae - if (auto it = antennae_skeleton.bone_map.find("scape_l"); it != antennae_skeleton.bone_map.end()) - scape_l_bone = antennae_skeleton.bones[it->second]; - scape_l_bone.parent = &head_bone; - if (auto it = antennae_skeleton.bone_map.find("scape_r"); it != antennae_skeleton.bone_map.end()) - scape_r_bone = antennae_skeleton.bones[it->second]; - scape_r_bone.parent = &head_bone; - if (auto it = antennae_skeleton.bone_map.find("pedicel_l"); it != antennae_skeleton.bone_map.end()) - pedicel_l_bone = antennae_skeleton.bones[it->second]; - pedicel_l_bone.parent = &scape_l_bone; - if (auto it = antennae_skeleton.bone_map.find("pedicel_r"); it != antennae_skeleton.bone_map.end()) - pedicel_r_bone = antennae_skeleton.bones[it->second]; - pedicel_r_bone.parent = &scape_r_bone; - - // Skeleton waist - if (auto it = waist_skeleton.bone_map.find("petiole"); it != waist_skeleton.bone_map.end()) - petiole_bone = waist_skeleton.bones[it->second]; - petiole_bone.parent = &mesosoma_bone; + // Skeleton antennae pose + bind_pose[scape_l_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_l")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("scape_l")); + bind_pose[scape_r_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_r")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("scape_r")); + bind_pose[pedicel_l_bone] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("pedicel_l")); + bind_pose[pedicel_r_bone] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("pedicel_r")); + + // Skeleton waist pose + bind_pose[petiole_bone] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole")); if (postpetiole) { - if (auto it = waist_skeleton.bone_map.find("postpetiole"); it != waist_skeleton.bone_map.end()) - *postpetiole_bone = waist_skeleton.bones[it->second]; - postpetiole_bone->parent = &petiole_bone; + bind_pose[postpetiole_bone] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole")); } - // Skeleton gaster - if (auto it = gaster_skeleton.bone_map.find("gaster"); it != gaster_skeleton.bone_map.end()) - gaster_bone = gaster_skeleton.bones[it->second]; - gaster_bone.parent = (postpetiole) ? postpetiole_bone : &petiole_bone; + // Skeleton gaster pose + if (postpetiole) + { + bind_pose[gaster_bone] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster")); + } + else + { + bind_pose[gaster_bone] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster")); + } - // Skeleton sting + // Skeleton sting pose if (sting) { - if (auto it = sting_skeleton->bone_map.find("sting"); it != sting_skeleton->bone_map.end()) - *sting_bone = sting_skeleton->bones[it->second]; - sting_bone->parent = &gaster_bone; + bind_pose[sting_bone] = gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting")) * sting_skeleton->bind_pose.at(sting_skeleton->bone_map.at("sting")); } + // Calculate the skeleton-space bind pose + pose bind_pose_ss; + concatenate(bind_pose, bind_pose_ss); + // Get number of vertex indices for each body part std::size_t mesosoma_index_count = (*mesosoma->get_groups())[0]->get_index_count(); std::size_t legs_index_count = (*legs->get_groups())[0]->get_index_count(); @@ -557,48 +563,38 @@ render::model* build_model + sting_index_count; // Calculate transform from head space to body space - math::transform head_to_body; - if (auto it = mesosoma_skeleton.bone_map.find("head"); it != mesosoma_skeleton.bone_map.end()) - head_to_body = mesosoma_skeleton.concatenate(it->second); + math::transform head_to_body = bind_pose_ss.at(mesosoma_bone) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head")); // Reskin head bone - std::unordered_set old_head_bone_indices; + std::unordered_set old_head_bone_indices; if (auto it = head_skeleton.bone_map.find("head"); it != head_skeleton.bone_map.end()) old_head_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + head_vbo_offset, head_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_head_bone_indices, head_bone_index, head_to_body); - // Calculate transforms from mandible space to body space - math::transform mandible_l_to_body; - if (auto it = head_skeleton.bone_map.find("mandible_l"); it != head_skeleton.bone_map.end()) - mandible_l_to_body = head_to_body * head_skeleton.concatenate(it->second); - math::transform mandible_r_to_body; - if (auto it = head_skeleton.bone_map.find("mandible_r"); it != head_skeleton.bone_map.end()) - mandible_r_to_body = head_to_body * head_skeleton.concatenate(it->second); + // Calculate transforms from mandibles space to body space + math::transform mandible_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_l")); + math::transform mandible_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r")); // Reskin mandible bones - std::unordered_set old_head_mandible_l_bone_indices; + std::unordered_set old_head_mandible_l_bone_indices; if (auto it = mandibles_skeleton.bone_map.find("mandible_l"); it != mandibles_skeleton.bone_map.end()) old_head_mandible_l_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + mandibles_vbo_offset, mandibles_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_head_mandible_l_bone_indices, mandible_l_bone_index, mandible_l_to_body); - std::unordered_set old_head_mandible_r_bone_indices; + std::unordered_set old_head_mandible_r_bone_indices; if (auto it = mandibles_skeleton.bone_map.find("mandible_r"); it != mandibles_skeleton.bone_map.end()) old_head_mandible_r_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + mandibles_vbo_offset, mandibles_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_head_mandible_r_bone_indices, mandible_r_bone_index, mandible_r_to_body); // Calculate transforms from antennae space to body space - math::transform antenna_l_to_body; - if (auto it = head_skeleton.bone_map.find("scape_l"); it != head_skeleton.bone_map.end()) - antenna_l_to_body = head_to_body * head_skeleton.concatenate(it->second); - math::transform antenna_r_to_body; - if (auto it = head_skeleton.bone_map.find("scape_r"); it != head_skeleton.bone_map.end()) - antenna_r_to_body = head_to_body * head_skeleton.concatenate(it->second); + math::transform antenna_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_l")); + math::transform antenna_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_r")); // Reskin scape bones - std::unordered_set old_scape_l_indices; + std::unordered_set old_scape_l_indices; if (auto it = antennae_skeleton.bone_map.find("scape_l"); it != antennae_skeleton.bone_map.end()) old_scape_l_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_scape_l_indices, scape_l_bone_index, antenna_l_to_body); - std::unordered_set old_scape_r_indices; + std::unordered_set old_scape_r_indices; if (auto it = antennae_skeleton.bone_map.find("scape_r"); it != antennae_skeleton.bone_map.end()) old_scape_r_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_scape_r_indices, scape_r_bone_index, antenna_r_to_body); @@ -620,42 +616,38 @@ render::model* build_model "flagellomere_11", "flagellomere_12" }; - std::unordered_set old_pedicel_l_indices; + std::unordered_set old_pedicel_l_indices; for (const std::string& bone_name: pedicel_bone_names) if (auto it = antennae_skeleton.bone_map.find(bone_name + "_l"); it != antennae_skeleton.bone_map.end()) old_pedicel_l_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_pedicel_l_indices, pedicel_l_bone_index, antenna_l_to_body); - std::unordered_set old_pedicel_r_indices; + std::unordered_set old_pedicel_r_indices; for (const std::string& bone_name: pedicel_bone_names) if (auto it = antennae_skeleton.bone_map.find(bone_name + "_r"); it != antennae_skeleton.bone_map.end()) old_pedicel_r_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_pedicel_r_indices, pedicel_r_bone_index, antenna_r_to_body); - + // Calculate transform from waist space to body space - math::transform waist_to_body; - if (auto it = mesosoma_skeleton.bone_map.find("petiole"); it != mesosoma_skeleton.bone_map.end()) - waist_to_body = mesosoma_skeleton.concatenate(it->second); + math::transform waist_to_body = bind_pose_ss.at(mesosoma_bone) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")); // Reskin waist bones - std::unordered_set old_petiole_bone_indices; + std::unordered_set old_petiole_bone_indices; if (auto it = waist_skeleton.bone_map.find("petiole"); it != waist_skeleton.bone_map.end()) old_petiole_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + waist_vbo_offset, waist_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_petiole_bone_indices, petiole_bone_index, waist_to_body); if (postpetiole) { - std::unordered_set old_postpetiole_bone_indices; + std::unordered_set old_postpetiole_bone_indices; if (auto it = waist_skeleton.bone_map.find("postpetiole"); it != waist_skeleton.bone_map.end()) old_postpetiole_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + waist_vbo_offset, waist_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_postpetiole_bone_indices, postpetiole_bone_index, waist_to_body); } // Calculate transform from gaster space to body space - math::transform gaster_to_body; - if (auto it = waist_skeleton.bone_map.find("gaster"); it != waist_skeleton.bone_map.end()) - gaster_to_body = waist_to_body * waist_skeleton.concatenate(it->second); + math::transform gaster_to_body = bind_pose_ss.at(bone_parent_index(gaster_bone)) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster")); // Reskin gaster bones - std::unordered_set old_gaster_bone_indices; + std::unordered_set old_gaster_bone_indices; if (auto it = gaster_skeleton.bone_map.find("gaster"); it != gaster_skeleton.bone_map.end()) old_gaster_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + gaster_vbo_offset, gaster_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_gaster_bone_indices, gaster_bone_index, gaster_to_body); @@ -663,12 +655,10 @@ render::model* build_model if (sting) { // Calculate transform from sting space to body space - math::transform sting_to_body; - if (auto it = gaster_skeleton.bone_map.find("sting"); it != gaster_skeleton.bone_map.end()) - sting_to_body = gaster_to_body * gaster_skeleton.concatenate(it->second); - + math::transform sting_to_body = bind_pose_ss.at(gaster_bone) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting")); + // Reskin sting bones - std::unordered_set old_sting_bone_indices; + std::unordered_set old_sting_bone_indices; if (auto it = sting_skeleton->bone_map.find("sting"); it != sting_skeleton->bone_map.end()) old_sting_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + sting_vbo_offset, sting_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_sting_bone_indices, sting_bone_index, sting_to_body); @@ -677,19 +667,15 @@ render::model* build_model if (eyes) { // Calculate transforms from eyes space to body space - math::transform eye_l_to_body; - if (auto it = head_skeleton.bone_map.find("eye_l"); it != head_skeleton.bone_map.end()) - eye_l_to_body = head_to_body * head_skeleton.concatenate(it->second); - math::transform eye_r_to_body; - if (auto it = head_skeleton.bone_map.find("eye_r"); it != head_skeleton.bone_map.end()) - eye_r_to_body = head_to_body * head_skeleton.concatenate(it->second); + math::transform eye_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_l")); + math::transform eye_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_r")); // Reskin eye bones - std::unordered_set old_eye_l_bone_indices; + std::unordered_set old_eye_l_bone_indices; if (auto it = eyes_skeleton->bone_map.find("eye_l"); it != eyes_skeleton->bone_map.end()) old_eye_l_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + eyes_vbo_offset, eyes_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_eye_l_bone_indices, head_bone_index, eye_l_to_body); - std::unordered_set old_eye_r_bone_indices; + std::unordered_set old_eye_r_bone_indices; if (auto it = eyes_skeleton->bone_map.find("eye_r"); it != eyes_skeleton->bone_map.end()) old_eye_r_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + eyes_vbo_offset, eyes_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_eye_r_bone_indices, head_bone_index, eye_r_to_body); @@ -698,19 +684,15 @@ render::model* build_model if (lateral_ocelli) { // Calculate transforms from lateral ocelli space to body space - math::transform ocellus_l_to_body; - if (auto it = head_skeleton.bone_map.find("ocellus_l"); it != head_skeleton.bone_map.end()) - ocellus_l_to_body = head_to_body * head_skeleton.concatenate(it->second); - math::transform ocellus_r_to_body; - if (auto it = head_skeleton.bone_map.find("ocellus_r"); it != head_skeleton.bone_map.end()) - ocellus_r_to_body = head_to_body * head_skeleton.concatenate(it->second); + math::transform ocellus_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_l")); + math::transform ocellus_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_r")); // Reskin lateral ocelli bones - std::unordered_set old_ocellus_l_bone_indices; + std::unordered_set old_ocellus_l_bone_indices; if (auto it = lateral_ocelli_skeleton->bone_map.find("ocellus_l"); it != lateral_ocelli_skeleton->bone_map.end()) old_ocellus_l_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + lateral_ocelli_vbo_offset, lateral_ocelli_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_ocellus_l_bone_indices, head_bone_index, ocellus_l_to_body); - std::unordered_set old_ocellus_r_bone_indices; + std::unordered_set old_ocellus_r_bone_indices; if (auto it = lateral_ocelli_skeleton->bone_map.find("ocellus_r"); it != lateral_ocelli_skeleton->bone_map.end()) old_ocellus_r_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + lateral_ocelli_vbo_offset, lateral_ocelli_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_ocellus_r_bone_indices, head_bone_index, ocellus_r_to_body); @@ -719,12 +701,10 @@ render::model* build_model if (median_ocellus) { // Calculate transforms from lateral ocelli space to body space - math::transform ocellus_m_to_body; - if (auto it = head_skeleton.bone_map.find("ocellus_m"); it != head_skeleton.bone_map.end()) - ocellus_m_to_body = head_to_body * head_skeleton.concatenate(it->second); + math::transform ocellus_m_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_m")); // Reskin lateral ocelli bones - std::unordered_set old_ocellus_m_bone_indices; + std::unordered_set old_ocellus_m_bone_indices; if (auto it = median_ocellus_skeleton->bone_map.find("ocellus_m"); it != median_ocellus_skeleton->bone_map.end()) old_ocellus_m_bone_indices.emplace(it->second); reskin_vertices(vertex_buffer_data + median_ocellus_vbo_offset, median_ocellus_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_ocellus_m_bone_indices, head_bone_index, ocellus_m_to_body); @@ -817,8 +797,8 @@ 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_set& old_bone_indices, - std::uint16_t new_bone_index, + const std::unordered_set& old_bone_indices, + std::uint8_t new_bone_index, const math::transform& transform ) { @@ -833,7 +813,7 @@ void reskin_vertices float* bone_index = reinterpret_cast(bone_index_data + bone_index_attribute.stride * i); // Skip irrelevant bones - if (!old_bone_indices.count(static_cast(*bone_index + 0.5f))) + if (!old_bone_indices.count(static_cast(*bone_index + 0.5f))) continue; // Get vertex position diff --git a/src/game/state/nuptial-flight.cpp b/src/game/state/nuptial-flight.cpp index 5c35852..2003680 100644 --- a/src/game/state/nuptial-flight.cpp +++ b/src/game/state/nuptial-flight.cpp @@ -97,7 +97,7 @@ nuptial_flight::nuptial_flight(game::context& ctx): game::world::create_moon(ctx); // Set time to solar noon - game::world::set_time(ctx, 0.3); + game::world::set_time(ctx, 0.0); // Freeze time game::world::set_time_scale(ctx, 0.0); @@ -264,7 +264,7 @@ void nuptial_flight::setup_camera() ctx.entity_registry->assign(camera_eid, constraint_stack); } - float ev100 = 13.5f; + float ev100 = 14.0f; ctx.surface_camera->set_exposure(ev100); } diff --git a/src/game/world.cpp b/src/game/world.cpp index a3ed583..6023d33 100644 --- a/src/game/world.cpp +++ b/src/game/world.cpp @@ -194,7 +194,7 @@ void create_sun(game::context& ctx) // Create ambient sun light scene object scene::ambient_light* sun_ambient = new scene::ambient_light(); sun_ambient->set_color({1, 1, 1}); - sun_ambient->set_intensity(30000.0f); + sun_ambient->set_intensity(30000.0f * 0.0f); sun_ambient->update_tweens(); // Add sun light scene objects to surface scene diff --git a/src/render/model.hpp b/src/render/model.hpp index 5e234ca..2701525 100644 --- a/src/render/model.hpp +++ b/src/render/model.hpp @@ -20,7 +20,7 @@ #ifndef ANTKEEPER_RENDER_MODEL_HPP #define ANTKEEPER_RENDER_MODEL_HPP -#include "render/skeleton.hpp" +#include "animation/skeleton.hpp" #include "gl/vertex-array.hpp" #include "gl/vertex-buffer.hpp" #include "gl/drawing-mode.hpp" @@ -157,7 +157,7 @@ private: std::unordered_map group_map; gl::vertex_array vao; gl::vertex_buffer vbo; - render::skeleton skeleton; + ::skeleton skeleton; }; inline void model::set_bounds(const aabb_type& bounds) diff --git a/src/render/operation.hpp b/src/render/operation.hpp index 4f9ae7c..b233757 100644 --- a/src/render/operation.hpp +++ b/src/render/operation.hpp @@ -21,12 +21,11 @@ #define ANTKEEPER_RENDER_OPERATION_HPP #include "utility/fundamental-types.hpp" +#include "animation/pose.hpp" #include "gl/vertex-array.hpp" #include "gl/drawing-mode.hpp" #include -class pose; - namespace render { class material; diff --git a/src/resources/model-loader.cpp b/src/resources/model-loader.cpp index 36602ec..1fce30d 100644 --- a/src/resources/model-loader.cpp +++ b/src/resources/model-loader.cpp @@ -223,62 +223,66 @@ render::model* resource_loader::load(resource_manager* resource_m { if (auto bones_node = skeleton_node->find("bones"); bones_node != skeleton_node->end()) { - render::skeleton& skeleton = model->get_skeleton(); - skeleton.bones.resize(bones_node->size()); + ::skeleton& skeleton = model->get_skeleton(); + pose& bind_pose = skeleton.bind_pose; - std::size_t bone_index = 0; + std::uint8_t bone_index = 0; for (const auto& bone_node: bones_node.value()) { - render::bone& bone = skeleton.bones[bone_index]; - - // Find bone name - if (auto name_node = bone_node.find("name"); name_node != bone_node.end()) - { - // Add bone to bone map - skeleton.bone_map[name_node->get()] = bone_index; - } - // Find parent bone - bone.parent = nullptr; + std::uint8_t bone_parent_index = bone_index; if (auto parent_node = bone_node.find("parent"); parent_node != bone_node.end()) { - // Link bone to parent bone (if any) if (!parent_node->is_null()) - bone.parent = &skeleton.bones[parent_node->get()]; + bone_parent_index = parent_node->get(); } + // Construct bone identifier + ::bone bone = make_bone(bone_index, bone_parent_index); - // Clear bone transform - bone.transform = math::identity_transform; + // Get reference to the bone's bind pose transform + auto& bone_transform = bind_pose[bone]; - // Find translation + // Get bone translation if (auto translation_node = bone_node.find("translation"); translation_node != bone_node.end()) { if (translation_node->size() == 3) { - bone.transform.translation.x = (*translation_node)[0].get(); - bone.transform.translation.y = (*translation_node)[1].get(); - bone.transform.translation.z = (*translation_node)[2].get(); + bone_transform.translation.x = (*translation_node)[0].get(); + bone_transform.translation.y = (*translation_node)[1].get(); + bone_transform.translation.z = (*translation_node)[2].get(); } } - // Find rotation + // Get bone rotation if (auto rotation_node = bone_node.find("rotation"); rotation_node != bone_node.end()) { if (rotation_node->size() == 4) { - bone.transform.rotation.w = (*rotation_node)[0].get(); - bone.transform.rotation.x = (*rotation_node)[1].get(); - bone.transform.rotation.y = (*rotation_node)[2].get(); - bone.transform.rotation.z = (*rotation_node)[3].get(); + bone_transform.rotation.w = (*rotation_node)[0].get(); + bone_transform.rotation.x = (*rotation_node)[1].get(); + bone_transform.rotation.y = (*rotation_node)[2].get(); + bone_transform.rotation.z = (*rotation_node)[3].get(); } } - // Find length + // Set bone scale + bone_transform.scale = {1, 1, 1}; + + // Get bone length + /* if (auto length_node = bone_node.find("length"); length_node != bone_node.end()) bone.length = length_node->get(); else bone.length = 0.0f; + */ + + // Get bone name + if (auto name_node = bone_node.find("name"); name_node != bone_node.end()) + { + // Add bone to bone map + skeleton.bone_map[name_node->get()] = bone; + } ++bone_index; } diff --git a/src/scene/model-instance.hpp b/src/scene/model-instance.hpp index b73b7bc..9fa1253 100644 --- a/src/scene/model-instance.hpp +++ b/src/scene/model-instance.hpp @@ -21,12 +21,11 @@ #define ANTKEEPER_SCENE_MODEL_INSTANCE_HPP #include "scene/object.hpp" +#include "animation/pose.hpp" #include "geom/aabb.hpp" #include "render/model.hpp" #include -class pose; - namespace scene { class model_instance: public object