12void Skeleton3D::ensureSorted() {
13 if (sk_.bones().empty()) {
14 sk_.topologicalSort();
18void Skeleton3D::ensureStateSize() {
20 const unsigned n =
static_cast<unsigned>(sk_.bones().size());
21 if (state_.size() <
n) {
23 state_.position_.resize(
n);
24 state_.orientation_.resize(
n);
25 state_.scale_.resize(
n);
26 state_.rotation_.resize(
n);
30::ik::bone3d *Skeleton3D::boneAt(
int boneId)
const {
31 if (boneId < 0)
return nullptr;
32 const auto &bones = sk_.bones();
33 if (
static_cast<size_t>(boneId) >= bones.size())
return nullptr;
34 return bones[
static_cast<size_t>(boneId)];
37void Skeleton3D::requireBone(
int boneId)
const {
38 if (!boneAt(boneId)) {
39 throw Exception(
"Skeleton3D: invalid bone id %d", boneId);
45 requireBone(parentId);
47 throw Exception(
"Skeleton3D.createBone: length must be > 0");
49 ::ik::bone3d *
parent = boneAt(parentId);
50 ::ik::bone3d *child =
parent->createBone(length);
51 sk_.topologicalSort();
53 return static_cast<int>(child->
id);
57 const_cast<Skeleton3D *
>(
this)->ensureSorted();
58 return static_cast<int>(sk_.bones().size());
63 ::ik::bone3d *
b = boneAt(boneId);
64 if (!
b->parent)
return -1;
65 return static_cast<int>(
b->parent->id);
70 return static_cast<int>(boneAt(boneId)->children.size());
75 ::ik::bone3d *
b = boneAt(boneId);
76 if (childIndex < 0 ||
static_cast<size_t>(childIndex) >=
b->children.size()) {
77 throw Exception(
"Skeleton3D.getChild: childIndex out of range");
79 return static_cast<int>(
b->children[
static_cast<size_t>(childIndex)]->
id);
84 return boneAt(boneId)->length;
90 throw Exception(
"Skeleton3D.setLength: root length is always 0");
93 throw Exception(
"Skeleton3D.setLength: length must be > 0");
95 boneAt(boneId)->setLength(length);
101 boneAt(boneId)->position(state_) = {
x,
y,
z};
106 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
107 return boneAt(boneId)->position(state_)[0];
112 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
113 return boneAt(boneId)->position(state_)[1];
118 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
119 return boneAt(boneId)->position(state_)[2];
125 boneAt(boneId)->orientation(state_) = {
x,
y,
z};
130 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
131 return boneAt(boneId)->orientation(state_)[0];
136 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
137 return boneAt(boneId)->orientation(state_)[1];
142 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
143 return boneAt(boneId)->orientation(state_)[2];
149 boneAt(boneId)->rotation(state_) = {yaw, pitch};
154 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
155 return boneAt(boneId)->rotation(state_)[0];
160 const_cast<Skeleton3D *
>(
this)->ensureStateSize();
161 return boneAt(boneId)->rotation(state_)[1];
167 if (minYaw > maxYaw || minPitch > maxPitch) {
168 throw Exception(
"Skeleton3D.setConstraints: min must be <= max per axis");
170 boneAt(boneId)->setConstraints(::ik::vec2{minYaw, minPitch},
171 ::ik::vec2{maxYaw, maxPitch});
176 boneAt(boneId)->clearConstraints();
181 return boneAt(boneId)->constrained;
187 sk_.init_straight_pose(state_, ::ik::vec3{rootX, rootY, rootZ});
199 sk_.forward_kinematics(state_);
205 sk_.update_rotations(state_);
210 return sk_.total_length_to(boneAt(boneId));
Script-facing 3D skeleton + pose state (ik::skeleton3d + ik::ecs3d). Local angles are yaw/pitch in th...
void setPosition(int boneId, float x, float y, float z)
void setConstraints(int boneId, float minYaw, float minPitch, float maxYaw, float maxPitch)
float getLength(int boneId) const
void setLength(int boneId, float length)
int getChildCount(int boneId) const
int createBone(int parentId, float length=1.f)
float getRotationPitch(int boneId) const
void setRotation(int boneId, float yaw, float pitch)
void setOrientation(int boneId, float x, float y, float z)
void initStraightPose(float rootX=0.f, float rootY=0.f, float rootZ=0.f)
float totalLengthTo(int boneId) const
float getOrientationZ(int boneId) const
void clearConstraints(int boneId)
float getZ(int boneId) const
float getY(int boneId) const
float getOrientationY(int boneId) const
bool hasConstraints(int boneId) const
float getX(int boneId) const
int getChild(int boneId, int childIndex) const
float getOrientationX(int boneId) const
float getRotationYaw(int boneId) const
int getParent(int boneId) const