Loading...
Searching...
No Matches
HumanoidPose.hpp
1#pragma once
2
3// humanoid_pose: canonical intermediate for live mocap -> rigged-character
4// retargeting. One fixed set of 22 bones that every source adapter populates and
5// HumanoidRetarget consumes.
6//
7// Flows through halp's structured-value port machinery, matching the existing
8// DetectedPose pattern; no new libossia port type.
9//
10// Rotations are local parent-relative quaternions (x, y, z, w); adapters convert
11// their source's native representation into that shape. `validity` is a 0..1
12// per-bone confidence -- BlazePose visibility, tracker occlusion -- that
13// downstream uses to freeze a bone rather than trust it. `hip_position` is the
14// only world-space translation that flows through, since every other bone's
15// position is implied by the target rig's proportions, and it is used only with
16// HumanoidRetarget's root-motion toggle on.
17
18#include <halp/controls.hpp>
19
20#include <array>
21#include <cstdint>
22#include <vector>
23
24namespace Threedim
25{
26
27// Canonical bone set. Indexed access via the enum; iterate with
28// humanoid_bone_index::Count. Order is stable — adapters and retargeter
29// presets both depend on it.
30enum class humanoid_bone_index : uint8_t
31{
32 Hips = 0,
33 Spine,
34 Chest,
35 Neck,
36 Head,
37
38 LeftShoulder,
39 LeftUpperArm,
40 LeftLowerArm,
41 LeftHand,
42
43 RightShoulder,
44 RightUpperArm,
45 RightLowerArm,
46 RightHand,
47
48 LeftUpperLeg,
49 LeftLowerLeg,
50 LeftFoot,
51 LeftToes,
52
53 RightUpperLeg,
54 RightLowerLeg,
55 RightFoot,
56 RightToes,
57
58 Count
59};
60
61// Per-bone pose. 20-byte halp-structured record (5 floats).
63{
64 // Parent-relative rotation quaternion, (x, y, z, w). Identity = {0,0,0,1}.
65 float qx{0.f};
66 float qy{0.f};
67 float qz{0.f};
68 float qw{1.f};
69
70 // 0..1 confidence. 0 means "no reliable data for this bone, retargeter
71 // should ignore this frame for this bone". 1 = fully trusted.
72 float validity{1.f};
73
74 halp_field_names(qx, qy, qz, qw, validity);
75};
76
77// Fixed-size bone array — std::array plays nicely with halp serialization
78// (same way DetectedPose uses std::vector, except the size is known and
79// we can index by enum without a lookup).
81{
82 std::array<humanoid_bone, std::size_t(humanoid_bone_index::Count)> bones{};
83
84 // World-space translation of the hip (Hips) root. Only consumed when
85 // root-motion is enabled on HumanoidRetarget; otherwise ignored.
86 float hip_x{0.f};
87 float hip_y{0.f};
88 float hip_z{0.f};
89
90 // Frame counter, incremented on every adapter emit. Consumers use it for
91 // dirty tracking: skip the work when it has not advanced.
92 int64_t version{0};
93
94 humanoid_bone& operator[](humanoid_bone_index b) noexcept
95 {
96 return bones[std::size_t(b)];
97 }
98 const humanoid_bone& operator[](humanoid_bone_index b) const noexcept
99 {
100 return bones[std::size_t(b)];
101 }
102
103 halp_field_names(bones, hip_x, hip_y, hip_z, version);
104};
105
106// =============================================================================
107// Keypoint ingestion type — structurally compatible with the DetectedPose
108// struct from score-addon-onnx (same field names, same layout) so halp's
109// field-name-based port marshalling can carry a DetectedPose through a
110// port typed as keypoint_stream without cross-addon header dependency.
111//
112// Kept in Threedim deliberately: HumanoidRetarget consumes it, but we
113// don't want score-plugin-threedim to link against score-addon-onnx.
114// =============================================================================
116{
117 float x{0.f};
118 float y{0.f};
119 float z{0.f};
120 float confidence{0.f};
121
122 halp_field_names(x, y, z, confidence);
123};
124
126{
127 std::vector<keypoint_3d> keypoints;
128 float mean_confidence{0.f};
129
130 halp_field_names(keypoints, mean_confidence);
131};
132
133// =============================================================================
134// Tracker bundle: 6 slots matching a common VR / optical-mocap full-body layout
135// (head, hips, 2 hands, 2 feet). Each carries a world-space position, a
136// world-space quaternion, and a validity, so lost tracking skips instead of
137// slamming the character to the origin.
138//
139// Richer layouts (10-point Vive Full-Body, Xsens 17-IMU, OptiTrack marker sets)
140// would be additional bundle_N struct types; users with those rigs can drive
141// these 6 slots from the subset they trust.
142// =============================================================================
144{
145 // World-space translation.
146 float x{0.f};
147 float y{0.f};
148 float z{0.f};
149
150 // World-space quaternion (x, y, z, w). Identity = {0, 0, 0, 1}.
151 float qx{0.f};
152 float qy{0.f};
153 float qz{0.f};
154 float qw{1.f};
155
156 // 0..1 tracking confidence. 0 = "tracker offline, ignore this frame".
157 float validity{0.f};
158
159 halp_field_names(x, y, z, qx, qy, qz, qw, validity);
160};
161
163{
164 tracker_pose head;
165 tracker_pose hips;
166 tracker_pose left_hand;
167 tracker_pose right_hand;
168 tracker_pose left_foot;
169 tracker_pose right_foot;
170
171 halp_field_names(head, hips, left_hand, right_hand, left_foot, right_foot);
172};
173
174} // namespace Threedim
Definition HumanoidPose.hpp:63
Definition HumanoidPose.hpp:81
Definition HumanoidPose.hpp:116
Definition HumanoidPose.hpp:126
Definition HumanoidPose.hpp:163
Definition HumanoidPose.hpp:144