2#include <hpp/utility/overload.hpp>
18 result.
set_translation(base.get_translation() + weight * (additive.get_translation() - ref.get_translation()));
21 math::quat additive_delta = additive.get_rotation() * glm::inverse(ref.get_rotation());
23 math::quat weighted_delta = math::slerp(math::identity<math::quat>(), additive_delta, weight);
25 result.
set_rotation(math::normalize(weighted_delta * base.get_rotation()));
28 result.
set_scale(base.get_scale() + weight * (additive.get_scale() - ref.get_scale()));
56 additive.motion_result.root_transform_delta,
76 for(
const auto& ref_node : ref_pose.
nodes)
79 blended_node.
desc = ref_node.desc;
86 while(i_base < base.
nodes.size() && base.
nodes[i_base].desc.index < ref_node.desc.index)
91 if(i_base < base.
nodes.size() && base.
nodes[i_base].desc.index == ref_node.desc.index)
93 base_transform = base.
nodes[i_base].transform;
97 while(i_add < additive.nodes.size() && additive.nodes[i_add].desc.index < ref_node.desc.index)
101 if(i_add < additive.nodes.size() && additive.nodes[i_add].desc.index == ref_node.desc.index)
103 additive_transform = additive.nodes[i_add].transform;
111 result.
nodes.push_back(blended_node);
127 result.
set_translation(math::lerp(lhs.get_translation(), rhs.get_translation(), factor));
128 result.
set_rotation(math::slerp(lhs.get_rotation(), rhs.get_rotation(), factor));
129 result.
set_scale(math::lerp(lhs.get_scale(), rhs.get_scale(), factor));
144 if(r1.root_position_node_index == -1)
149 else if(r2.root_position_node_index == -1)
160 if(r1.root_rotation_node_index == -1)
165 else if(r2.root_rotation_node_index == -1)
188 result.
nodes.clear();
196 while(i1 < pose1.
nodes.size() && i2 < pose2.
nodes.size())
198 const auto& node1 = pose1.
nodes[i1];
199 const auto& node2 = pose2.
nodes[i2];
201 if(node1.desc.index < node2.desc.index)
204 result.
nodes.push_back(node1);
207 else if(node1.desc.index > node2.desc.index)
210 result.
nodes.push_back(node2);
215 auto& node = result.
nodes.emplace_back();
217 node.desc = node1.desc;
218 node.transform =
blend(node1.transform, node2.transform, factor);
226 while(i1 < pose1.
nodes.size())
233 while(i2 < pose2.
nodes.size())
246 const std::vector<float>& weights,
250 if(poses.size() == 1)
258 size_t k = poses.size();
259 std::vector<size_t> idx(k, 0);
261 result.
nodes.clear();
267 size_t min_index = (size_t)-1;
268 bool all_finished =
true;
273 for(
size_t p = 0; p < k; ++p)
275 if(idx[p] < poses[p].nodes.size())
277 all_finished =
false;
278 size_t node_index = poses[p].nodes[idx[p]].desc.index;
279 if(min_index == (
size_t)-1 || node_index < min_index)
281 min_index = node_index;
293 float total_weight{0.0f};
295 bool first_transform_set{
false};
297 for(
size_t p = 0; p < k; ++p)
299 if(idx[p] < poses[p].nodes.size())
301 const auto& node = poses[p].nodes[idx[p]];
302 if(node.desc.index == min_index)
305 float w = weights[p];
306 if(!first_transform_set)
308 accum_transform = node.transform;
310 first_transform_set =
true;
317 float factor = w / (total_weight + w);
318 accum_transform =
blend(accum_transform, node.transform, factor);
330 auto& out = result.
nodes.emplace_back();
331 out.desc.index = min_index;
332 out.transform = accum_transform;
341 const std::vector<float>& weights,
350 parameter_count_ = params.size();
359 if(parameter_count_ == 1)
363 compute_blend_1d(current_params, out_clips);
366 if(parameter_count_ == 2)
368 compute_blend_2d(current_params, out_clips);
375void blend_space_def::compute_blend_1d(
const parameters_t& current_params,
379 float param = current_params[0];
382 std::set<float> unique_values;
383 for(
const auto&
point : points_)
385 unique_values.insert(
point.parameters[0]);
389 std::vector<float> sorted_values(unique_values.begin(), unique_values.end());
392 if(sorted_values.size() <= 1)
397 out_clips.emplace_back(points_.front().clip, 1.0f);
405 auto find_index_1d = [&](
float p)
407 for(
size_t i = 0;
i < sorted_values.size() - 1; ++
i)
409 if(p >= sorted_values[i] && p <= sorted_values[i + 1])
413 return sorted_values.size() - 2;
416 size_t idx = find_index_1d(param);
417 float v0 = sorted_values[idx];
418 float v1 = sorted_values[idx + 1];
422 if(fabs(v1 - v0) > 1e-5f)
423 t = (param - v0) / (v1 - v0);
425 t = math::clamp(t, 0.0f, 1.0f);
428 const blend_space_point* p0 =
nullptr;
429 const blend_space_point* p1 =
nullptr;
433 for(
const auto&
point : points_)
435 if(fabs(
point.parameters[0] - v0) < 1e-5f)
437 if(fabs(
point.parameters[0] - v1) < 1e-5f)
444 if(p0 && p1 && p0 != p1)
449 out_clips.emplace_back(p0->clip, w0);
450 out_clips.emplace_back(p1->clip, w1);
455 out_clips.emplace_back(p0->clip, 1.0f);
460 out_clips.emplace_back(p1->clip, 1.0f);
464void blend_space_def::compute_blend_2d(
const parameters_t& current_params,
471 if(parameter_count_ != 2)
481 std::set<float> param0_values;
482 std::set<float> param1_values;
483 for(
const auto&
point : points_)
485 param0_values.insert(
point.parameters[0]);
486 param1_values.insert(
point.parameters[1]);
490 std::vector<float> param0_vector(param0_values.begin(), param0_values.end());
491 std::vector<float> param1_vector(param1_values.begin(), param1_values.end());
494 auto find_index = [](
const std::vector<float>& values,
float param) ->
size_t
496 for(
size_t i = 0;
i < values.size() - 1; ++
i)
498 if(param >= values[i] && param <= values[i + 1])
503 return values.size() - 2;
506 size_t index0 = find_index(param0_vector, current_params[0]);
507 size_t index1 = find_index(param1_vector, current_params[1]);
510 float p00 = param0_vector[index0];
511 float p01 = param0_vector[index0 + 1];
512 float p10 = param1_vector[index1];
513 float p11 = param1_vector[index1 + 1];
516 std::array<const blend_space_point*, 4> corner_points = {
nullptr,
nullptr,
nullptr,
nullptr};
518 for(
const auto&
point : points_)
520 const auto& params =
point.parameters;
521 if(params[0] == p00 && params[1] == p10)
522 corner_points[0] = &
point;
523 if(params[0] == p01 && params[1] == p10)
524 corner_points[1] = &
point;
525 if(params[0] == p00 && params[1] == p11)
526 corner_points[2] = &
point;
527 if(params[0] == p01 && params[1] == p11)
528 corner_points[3] = &
point;
532 for(
const auto* cp : corner_points)
539 float tx = (current_params[0] - p00) / (p01 - p00);
540 float ty = (current_params[1] - p10) / (p11 - p10);
543 float w_bl = (1 - tx) * (1 - ty);
544 float w_br = tx * (1 - ty);
545 float w_tl = (1 - tx) * ty;
546 float w_tr = tx * ty;
549 out_clips.emplace_back(corner_points[0]->clip, w_bl);
550 out_clips.emplace_back(corner_points[1]->clip, w_br);
551 out_clips.emplace_back(corner_points[2]->clip, w_tl);
552 out_clips.emplace_back(corner_points[3]->clip, w_tr);
557 return parameter_count_;
void add_clip(const parameters_t ¶ms, const asset_handle< animation_clip > &clip)
void compute_blend(const parameters_t ¤t_params, std::vector< std::pair< asset_handle< animation_clip >, float > > &out_clips) const
std::vector< parameter_t > parameters_t
auto get_parameter_count() const -> size_t
void blend_poses_by_node_index_sorted_additive(const animation_pose &base, const animation_pose &additive, const animation_pose &ref_pose, float weight, animation_pose &result)
void blend_poses_by_node_index_sorted_multiway(const std::vector< animation_pose > &poses, const std::vector< float > &weights, animation_pose &result)
@ blend
Transparent (lit pass); does not cast shadows.
void blend_poses(const animation_pose &pose1, const animation_pose &pose2, float factor, animation_pose &result_pose)
void blend_poses_by_node_index_sorted(const animation_pose &pose1, const animation_pose &pose2, float factor, animation_pose &result)
void blend_poses_additive(const animation_pose &base, const animation_pose &additive, const animation_pose &ref_pose, float weight, animation_pose &result)
auto blend_additive(const math::transform &base, const math::transform &additive, const math::transform &ref, float weight) -> math::transform
Thread-safe handle to an asset.
math::transform transform
std::string root_position_node_name
float bone_rotation_weight
float root_rotation_weight
math::vec3 bone_position_weights
std::string root_rotation_node_name
math::vec3 root_position_weights
math::transform root_transform_delta
int root_position_node_index
int root_rotation_node_index
std::vector< node > nodes
root_motion_result motion_result