diff --git a/src/animation/bone.hpp b/src/animation/bone.hpp index 4b66f54..28fa6dd 100644 --- a/src/animation/bone.hpp +++ b/src/animation/bone.hpp @@ -22,14 +22,16 @@ #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; +/// Mask to extract the index of a bone. +constexpr bone bone_index_mask = 0xFF; + /** * Bone index comparison function object. */ diff --git a/src/animation/pose.cpp b/src/animation/pose.cpp index bcce652..ae92ed2 100644 --- a/src/animation/pose.cpp +++ b/src/animation/pose.cpp @@ -19,6 +19,7 @@ #include "animation/pose.hpp" #include "math/transform-operators.hpp" +#include "math/transform-functions.hpp" void concatenate(const pose& bone_space, pose& skeleton_space) { @@ -37,3 +38,20 @@ void concatenate(const pose& bone_space, pose& skeleton_space) } } } + +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) + { + std::uint8_t index = ::bone_index(bone); + palette[index] = math::matrix_cast(inverse_bind_pose.at(bone) * transform); + } +} diff --git a/src/animation/pose.hpp b/src/animation/pose.hpp index 3ffd714..2c996cd 100644 --- a/src/animation/pose.hpp +++ b/src/animation/pose.hpp @@ -22,6 +22,7 @@ #include "animation/bone.hpp" #include "math/transform-type.hpp" +#include "utility/fundamental-types.hpp" #include /** @@ -39,4 +40,20 @@ typedef std::map, bone_index_compare> pose; */ 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 diff --git a/src/animation/skeleton.cpp b/src/animation/skeleton.cpp index 1d563b6..cfa934a 100644 --- a/src/animation/skeleton.cpp +++ b/src/animation/skeleton.cpp @@ -18,5 +18,4 @@ */ #include "animation/skeleton.hpp" -#include "math/transform-operators.hpp" diff --git a/src/animation/skeleton.hpp b/src/animation/skeleton.hpp index 7339eb7..ac65020 100644 --- a/src/animation/skeleton.hpp +++ b/src/animation/skeleton.hpp @@ -33,6 +33,9 @@ struct skeleton /// Bone-space bind pose of the skeleton. pose bind_pose; + /// Inverse skeleton-space bind pose of the skeleton. + pose inverse_bind_pose; + /// Maps bone names to bone identifiers. std::unordered_map bone_map; }; diff --git a/src/config.hpp.in b/src/config.hpp.in index 2123901..f97f258 100644 --- a/src/config.hpp.in +++ b/src/config.hpp.in @@ -68,6 +68,7 @@ constexpr float nuptial_flight_fade_in_duration = 5.0f; #define MATERIAL_PASS_MAX_POINT_LIGHT_COUNT 1 #define MATERIAL_PASS_MAX_DIRECTIONAL_LIGHT_COUNT 2 #define MATERIAL_PASS_MAX_SPOTLIGHT_COUNT 1 +#define MATERIAL_PASS_MAX_BONE_COUNT 64 #define TERRAIN_PATCH_SIZE 200.0f #define TERRAIN_PATCH_RESOLUTION 4 #define VEGETATION_PATCH_RESOLUTION 1 diff --git a/src/game/ant/morphogenesis.cpp b/src/game/ant/morphogenesis.cpp index 36eb03c..576d3d7 100644 --- a/src/game/ant/morphogenesis.cpp +++ b/src/game/ant/morphogenesis.cpp @@ -90,9 +90,6 @@ render::model* generate_queen(const ant::breed& breed) render::model* generate_worker(const ant::breed& breed) { - // Get material parameters - - // Build exoskeleton material render::material* exoskeleton_material = build_exoskeleton_material(*breed.pigmentation, *breed.sculpturing); @@ -361,24 +358,24 @@ render::model* build_model // 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_coxa_l_bone = make_bone(foreleg_coxa_l_bone_index, mesosoma_bone_index); + ::bone foreleg_coxa_r_bone = make_bone(foreleg_coxa_r_bone_index, mesosoma_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_coxa_l_bone = make_bone(midleg_coxa_l_bone_index, mesosoma_bone_index); + ::bone midleg_coxa_r_bone = make_bone(midleg_coxa_r_bone_index, mesosoma_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_coxa_l_bone = make_bone(hindleg_coxa_l_bone_index, mesosoma_bone_index); + ::bone hindleg_coxa_r_bone = make_bone(hindleg_coxa_r_bone_index, mesosoma_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); @@ -457,9 +454,9 @@ render::model* build_model 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()) 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()) + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_l"); it != legs_skeleton.bone_map.end()) 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()) + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_r"); it != legs_skeleton.bone_map.end()) bind_pose[foreleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second); // Skeleton midlegs pose @@ -475,9 +472,9 @@ render::model* build_model 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()) 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()) + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_l"); it != legs_skeleton.bone_map.end()) 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()) + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_r"); it != legs_skeleton.bone_map.end()) bind_pose[midleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second); // Skeleton hindlegs pose @@ -493,9 +490,9 @@ render::model* build_model 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()) 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()) + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_l"); it != legs_skeleton.bone_map.end()) 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()) + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_r"); it != legs_skeleton.bone_map.end()) bind_pose[hindleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second); // Skeleton head pose @@ -536,7 +533,10 @@ render::model* build_model // Calculate the skeleton-space bind pose pose bind_pose_ss; - concatenate(bind_pose, bind_pose_ss); + ::concatenate(bind_pose, bind_pose_ss); + + // Calculate inverse skeleton-space bind pose + ::inverse(bind_pose_ss, skeleton.inverse_bind_pose); // Get number of vertex indices for each body part std::size_t mesosoma_index_count = (*mesosoma->get_groups())[0]->get_index_count(); @@ -562,6 +562,160 @@ render::model* build_model + gaster_index_count + sting_index_count; + // Calculate transform from legs space to body space + const math::transform& legs_to_body = math::identity_transform; + + // Reskin leg bones + std::unordered_set old_foreleg_coxa_l_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_coxa_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_coxa_l_indices, foreleg_coxa_l_bone_index, legs_to_body); + std::unordered_set old_foreleg_femur_l_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_femur_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_femur_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_femur_l_indices, foreleg_femur_l_bone_index, legs_to_body); + std::unordered_set old_foreleg_tibia_l_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_tibia_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tibia_l_indices, foreleg_tibia_l_bone_index, legs_to_body); + std::unordered_set old_foreleg_tarsus_l_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus2_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus3_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus4_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus5_l"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tarsus_l_indices, foreleg_tarsus_l_bone_index, legs_to_body); + + std::unordered_set old_foreleg_coxa_r_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_coxa_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_coxa_r_indices, foreleg_coxa_r_bone_index, legs_to_body); + std::unordered_set old_foreleg_femur_r_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_femur_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_femur_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_femur_r_indices, foreleg_femur_r_bone_index, legs_to_body); + std::unordered_set old_foreleg_tibia_r_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_tibia_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tibia_r_indices, foreleg_tibia_r_bone_index, legs_to_body); + std::unordered_set old_foreleg_tarsus_r_indices; + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus2_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus3_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus4_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus5_r"); it != legs_skeleton.bone_map.end()) + old_foreleg_tarsus_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tarsus_r_indices, foreleg_tarsus_r_bone_index, legs_to_body); + + std::unordered_set old_midleg_coxa_l_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_coxa_l"); it != legs_skeleton.bone_map.end()) + old_midleg_coxa_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_coxa_l_indices, midleg_coxa_l_bone_index, legs_to_body); + std::unordered_set old_midleg_femur_l_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_femur_l"); it != legs_skeleton.bone_map.end()) + old_midleg_femur_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_femur_l_indices, midleg_femur_l_bone_index, legs_to_body); + std::unordered_set old_midleg_tibia_l_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_tibia_l"); it != legs_skeleton.bone_map.end()) + old_midleg_tibia_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tibia_l_indices, midleg_tibia_l_bone_index, legs_to_body); + std::unordered_set old_midleg_tarsus_l_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_l"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus2_l"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus3_l"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus4_l"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus5_l"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tarsus_l_indices, midleg_tarsus_l_bone_index, legs_to_body); + + std::unordered_set old_midleg_coxa_r_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_coxa_r"); it != legs_skeleton.bone_map.end()) + old_midleg_coxa_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_coxa_r_indices, midleg_coxa_r_bone_index, legs_to_body); + std::unordered_set old_midleg_femur_r_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_femur_r"); it != legs_skeleton.bone_map.end()) + old_midleg_femur_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_femur_r_indices, midleg_femur_r_bone_index, legs_to_body); + std::unordered_set old_midleg_tibia_r_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_tibia_r"); it != legs_skeleton.bone_map.end()) + old_midleg_tibia_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tibia_r_indices, midleg_tibia_r_bone_index, legs_to_body); + std::unordered_set old_midleg_tarsus_r_indices; + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_r"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus2_r"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus3_r"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus4_r"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("midleg_tarsus5_r"); it != legs_skeleton.bone_map.end()) + old_midleg_tarsus_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tarsus_r_indices, midleg_tarsus_r_bone_index, legs_to_body); + + std::unordered_set old_hindleg_coxa_l_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_coxa_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_coxa_l_indices, hindleg_coxa_l_bone_index, legs_to_body); + std::unordered_set old_hindleg_femur_l_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_femur_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_femur_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_femur_l_indices, hindleg_femur_l_bone_index, legs_to_body); + std::unordered_set old_hindleg_tibia_l_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_tibia_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tibia_l_indices, hindleg_tibia_l_bone_index, legs_to_body); + std::unordered_set old_hindleg_tarsus_l_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus2_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus3_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus4_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_l_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus5_l"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_l_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tarsus_l_indices, hindleg_tarsus_l_bone_index, legs_to_body); + + std::unordered_set old_hindleg_coxa_r_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_coxa_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_coxa_r_indices, hindleg_coxa_r_bone_index, legs_to_body); + std::unordered_set old_hindleg_femur_r_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_femur_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_femur_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_femur_r_indices, hindleg_femur_r_bone_index, legs_to_body); + std::unordered_set old_hindleg_tibia_r_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_tibia_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tibia_r_indices, hindleg_tibia_r_bone_index, legs_to_body); + std::unordered_set old_hindleg_tarsus_r_indices; + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus2_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus3_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus4_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_r_indices.emplace(it->second); + if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus5_r"); it != legs_skeleton.bone_map.end()) + old_hindleg_tarsus_r_indices.emplace(it->second); + reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tarsus_r_indices, hindleg_tarsus_r_bone_index, legs_to_body); + // Calculate transform from head space to body space math::transform head_to_body = bind_pose_ss.at(mesosoma_bone) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head")); diff --git a/src/render/operation.hpp b/src/render/operation.hpp index b233757..f371ece 100644 --- a/src/render/operation.hpp +++ b/src/render/operation.hpp @@ -35,7 +35,8 @@ class material; */ struct operation { - const pose* pose; + const float4x4* skinning_palette; + std::size_t bone_count; const material* material; const gl::vertex_array* vertex_array; gl::drawing_mode drawing_mode; diff --git a/src/render/passes/material-pass.cpp b/src/render/passes/material-pass.cpp index 302a500..4448a55 100644 --- a/src/render/passes/material-pass.cpp +++ b/src/render/passes/material-pass.cpp @@ -505,6 +505,12 @@ void material_pass::render(const render::context& ctx, render::queue& queue) con model_view = view * model; normal_model = math::transpose(math::inverse(math::resize<3, 3>(model))); normal_model_view = math::transpose(math::inverse(math::resize<3, 3>(model_view))); + + // Skinning palette + if (operation.bone_count && parameters->skinning_palette) + { + parameters->skinning_palette->upload(0, operation.skinning_palette, operation.bone_count); + } // Upload operation-dependent parameters if (parameters->model) @@ -577,6 +583,7 @@ const material_pass::parameter_set* material_pass::load_parameter_set(const gl:: parameters->shadow_map_directional = program->get_input("shadow_map_directional"); parameters->shadow_splits_directional = program->get_input("shadow_splits_directional"); parameters->shadow_matrices_directional = program->get_input("shadow_matrices_directional"); + parameters->skinning_palette = program->get_input("skinning_palette"); // Add parameter set to map of parameter sets parameter_sets[program] = parameters; diff --git a/src/render/passes/material-pass.hpp b/src/render/passes/material-pass.hpp index 005ecda..9fbf8a7 100644 --- a/src/render/passes/material-pass.hpp +++ b/src/render/passes/material-pass.hpp @@ -99,6 +99,8 @@ private: const gl::shader_input* shadow_map_directional; const gl::shader_input* shadow_splits_directional; const gl::shader_input* shadow_matrices_directional; + + const gl::shader_input* skinning_palette; }; const parameter_set* load_parameter_set(const gl::shader_program* program) const; @@ -111,6 +113,7 @@ private: int max_point_light_count; int max_directional_light_count; int max_spot_light_count; + int max_bone_count; mutable int ambient_light_count; mutable int point_light_count; diff --git a/src/render/passes/shadow-map-pass.cpp b/src/render/passes/shadow-map-pass.cpp index 4258357..4a9ed22 100644 --- a/src/render/passes/shadow-map-pass.cpp +++ b/src/render/passes/shadow-map-pass.cpp @@ -226,7 +226,7 @@ void shadow_map_pass::render(const render::context& ctx, render::queue& queue) c } // Switch shader programs if necessary - gl::shader_program* shader_program = (operation.pose != nullptr) ? skinned_shader_program : unskinned_shader_program; + gl::shader_program* shader_program = (operation.bone_count) ? skinned_shader_program : unskinned_shader_program; if (active_shader_program != shader_program) { active_shader_program = shader_program; @@ -265,8 +265,8 @@ void shadow_map_pass::set_light(const scene::directional_light* light) bool operation_compare(const render::operation& a, const render::operation& b) { // Determine transparency - bool skinned_a = (a.pose != nullptr); - bool skinned_b = (b.pose != nullptr); + bool skinned_a = (a.bone_count); + bool skinned_b = (b.bone_count); if (skinned_a) { diff --git a/src/render/renderer.cpp b/src/render/renderer.cpp index 6125ca1..68016c7 100644 --- a/src/render/renderer.cpp +++ b/src/render/renderer.cpp @@ -39,12 +39,21 @@ namespace render { renderer::renderer() { // Setup billboard render operation - billboard_op.pose = nullptr; + billboard_op.bone_count = 0; + billboard_op.skinning_palette = nullptr; billboard_op.drawing_mode = gl::drawing_mode::triangles; billboard_op.vertex_array = nullptr; billboard_op.start_index = 0; billboard_op.index_count = 6; billboard_op.instance_count = 0; + + // Allocate skinning palette + skinning_palette = new float4x4[MATERIAL_PASS_MAX_BONE_COUNT]; +} + +renderer::~renderer() +{ + delete[] skinning_palette; } void renderer::render(float t, float dt, float alpha, const scene::collection& collection) const @@ -161,10 +170,26 @@ void renderer::process_model_instance(const render::context& ctx, render::queue& const std::vector* instance_materials = model_instance->get_materials(); const std::vector* groups = model->get_groups(); + render::operation operation; + operation.transform = math::matrix_cast(model_instance->get_transform_tween().interpolate(ctx.alpha)); + operation.depth = ctx.clip_near.signed_distance(math::resize<3>(operation.transform[3])); + operation.vertex_array = model->get_vertex_array(); + operation.instance_count = model_instance->get_instance_count(); + + // Skinning parameters + operation.bone_count = model_instance->get_pose().size(); + if (operation.bone_count) + { + operation.skinning_palette = skinning_palette; + ::matrix_palette(model->get_skeleton().inverse_bind_pose, model_instance->get_pose(), skinning_palette); + } + else + { + operation.skinning_palette = nullptr; + } + for (model_group* group: *groups) { - render::operation operation; - // Determine operation material operation.material = group->get_material(); if ((*instance_materials)[group->get_index()]) @@ -172,16 +197,11 @@ void renderer::process_model_instance(const render::context& ctx, render::queue& // Override model group material with the instance's material operation.material = (*instance_materials)[group->get_index()]; } - - operation.pose = model_instance->get_pose(); - operation.vertex_array = model->get_vertex_array(); + operation.drawing_mode = group->get_drawing_mode(); operation.start_index = group->get_start_index(); operation.index_count = group->get_index_count(); - operation.transform = math::matrix_cast(model_instance->get_transform_tween().interpolate(ctx.alpha)); - operation.depth = ctx.clip_near.signed_distance(math::resize<3>(operation.transform[3])); - operation.instance_count = model_instance->get_instance_count(); - + queue.push_back(operation); } } diff --git a/src/render/renderer.hpp b/src/render/renderer.hpp index ec11628..ddf17e1 100644 --- a/src/render/renderer.hpp +++ b/src/render/renderer.hpp @@ -44,6 +44,7 @@ class renderer { public: renderer(); + ~renderer(); /** * Renders a collection of scene objects. @@ -68,6 +69,7 @@ private: void process_text(const render::context& ctx, render::queue& queue, const scene::text* text) const; mutable render::operation billboard_op; + float4x4* skinning_palette; }; } // namespace render diff --git a/src/resources/model-loader.cpp b/src/resources/model-loader.cpp index 1fce30d..6e45fa8 100644 --- a/src/resources/model-loader.cpp +++ b/src/resources/model-loader.cpp @@ -286,6 +286,10 @@ render::model* resource_loader::load(resource_manager* resource_m ++bone_index; } + + // Calculate inverse skeleton-space bind pose + ::concatenate(skeleton.bind_pose, skeleton.inverse_bind_pose); + ::inverse(skeleton.inverse_bind_pose, skeleton.inverse_bind_pose); } } diff --git a/src/scene/model-instance.cpp b/src/scene/model-instance.cpp index f21e1bb..54602e6 100644 --- a/src/scene/model-instance.cpp +++ b/src/scene/model-instance.cpp @@ -25,7 +25,6 @@ namespace scene { model_instance::model_instance(render::model* model): model(nullptr), - pose(nullptr), local_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, world_bounds{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, instanced(false), @@ -59,22 +58,23 @@ model_instance& model_instance::operator=(const model_instance& other) void model_instance::set_model(render::model* model) { this->model = model; - this->pose = nullptr; if (model) { materials.resize(model->get_groups()->size()); reset_materials(); + + pose = model->get_skeleton().bind_pose; + ::concatenate(pose, pose); + } + else + { + pose.clear(); } update_bounds(); } -void model_instance::set_pose(::pose* pose) -{ - this->pose = pose; -} - void model_instance::set_material(std::size_t group_index, render::material* material) { materials[group_index] = material; diff --git a/src/scene/model-instance.hpp b/src/scene/model-instance.hpp index 9fa1253..4fd290a 100644 --- a/src/scene/model-instance.hpp +++ b/src/scene/model-instance.hpp @@ -43,11 +43,6 @@ public: */ void set_model(render::model* model); - /** - * Sets the - */ - void set_pose(pose* pose); - /** * Overwrites the material of a model group for this model instance. * @@ -68,9 +63,12 @@ public: const render::model* get_model() const; render::model* get_model(); - - const pose* get_pose() const; - pose* get_pose(); + + /// Returns the skeletal animation pose of this model. + const pose& get_pose() const; + + /// @copydoc model_instance::get_pose() const + pose& get_pose(); const std::vector* get_materials() const; @@ -85,7 +83,7 @@ private: virtual void transformed(); render::model* model; - pose* pose; + ::pose pose; std::vector materials; aabb_type local_bounds; aabb_type world_bounds; @@ -113,12 +111,12 @@ inline render::model* model_instance::get_model() return model; } -inline const pose* model_instance::get_pose() const +inline const pose& model_instance::get_pose() const { return pose; } -inline pose* model_instance::get_pose() +inline pose&model_instance::get_pose() { return pose; } diff --git a/src/scene/text.cpp b/src/scene/text.cpp index a5b7277..a4ffd4b 100644 --- a/src/scene/text.cpp +++ b/src/scene/text.cpp @@ -83,7 +83,8 @@ text::text(): // Init render operation render_op.material = nullptr; - render_op.pose = nullptr; + render_op.bone_count = 0; + render_op.skinning_palette = nullptr; render_op.vertex_array = vao; render_op.drawing_mode = gl::drawing_mode::triangles; render_op.start_index = 0;