载入中...
搜索中...
未找到
Solver3D.cpp
浏览该文件的文档.
1#include "ik/Solver3D.h"
2
3#include "common/Exception.h"
4
5#include <algorithm>
6
7namespace eve::ik {
8
9void Solver3D::setKeepTrace(bool keep) {
10 keepTrace_ = keep;
11 solver_.setKeepTrace(keep);
12}
13
14bool Solver3D::getKeepTrace() const { return keepTrace_; }
15
17 if (iterations < 0) {
18 throw Exception("Solver3D.setMaxIterations: iterations must be >= 0");
19 }
20 maxIterations_ = iterations;
21 solver_.setMaxIterations(static_cast<unsigned>(iterations));
22}
23
24int Solver3D::getMaxIterations() const { return maxIterations_; }
25
26void Solver3D::setTolerance(float tol) {
27 if (tol < 0.f) {
28 throw Exception("Solver3D.setTolerance: tolerance must be >= 0");
29 }
30 tolerance_ = tol;
31 solver_.setTolerance(tol);
32}
33
34float Solver3D::getTolerance() const { return tolerance_; }
35
36void Solver3D::setForce(float force) {
37 force_ = force;
38 solver_.setForce(force);
39}
40
41float Solver3D::getForce() const { return force_; }
42
43void Solver3D::setInfluence(float influence) {
44 if (influence < 0.f || influence > 1.f) {
45 throw Exception("Solver3D.setInfluence: influence must be in [0, 1]");
46 }
47 influence_ = influence;
48}
49
50float Solver3D::getInfluence() const { return influence_; }
51
52void Solver3D::clearTargets() { solver_.clearTargets(); }
53
54void Solver3D::addTarget(int boneId, float x, float y, float z, float weight) {
55 if (boneId < 0) {
56 throw Exception("Solver3D.addTarget: boneId must be >= 0");
57 }
58 solver_.addTarget(static_cast<unsigned>(boneId), ::ik::vec3{x, y, z}, weight);
59}
60
62 return static_cast<int>(solver_.targets().size());
63}
64
65bool Solver3D::solve(Skeleton3D *skeleton) {
66 if (!skeleton) {
67 throw Exception("Solver3D.solve: skeleton is null");
68 }
69 ::ik::ecs3d &state = skeleton->state();
70 std::vector<::ik::vec3> original;
71 if (influence_ < 1.f) {
72 original = state.position_;
73 }
74 const bool reached = solver_.solve(skeleton->native(), state);
75 if (influence_ < 1.f) {
76 const float t = influence_;
77 for (size_t i = 0; i < state.position_.size(); ++i) {
78 state.position_[i] = original[i] + (state.position_[i] - original[i]) * t;
79 }
80 skeleton->native().update_rotations(state);
81 }
82 applyTipRotation(skeleton);
83 return reached;
84}
85
86void Solver3D::step(Skeleton3D *skeleton, float dt) {
87 if (!skeleton) {
88 throw Exception("Solver3D.step: skeleton is null");
89 }
90 ::ik::ecs3d &state = skeleton->state();
91 std::vector<::ik::vec3> original;
92 if (influence_ < 1.f) {
93 original = state.position_;
94 }
95 solver_.step(skeleton->native(), skeleton->state(), dt);
96 if (influence_ < 1.f) {
97 const float t = influence_;
98 for (size_t i = 0; i < state.position_.size(); ++i) {
99 state.position_[i] = original[i] + (state.position_[i] - original[i]) * t;
100 }
101 skeleton->native().update_rotations(state);
102 }
103 applyTipRotation(skeleton);
104}
105
106bool Solver3D::solveChain(Skeleton3D *skeleton, int rootBoneId, int tipBoneId) {
108 options.tolerance = tolerance_;
109 options.max_iterations = static_cast<unsigned>(maxIterations_);
110 options.force = force_;
111 options.influence = influence_;
112 options.use_pole = usePole_;
113 options.pole = pole_;
114 options.pole_weight = poleWeight_;
115 return solveChainImpl(skeleton, rootBoneId, tipBoneId, options);
116}
117
118void Solver3D::stepChain(Skeleton3D *skeleton, int rootBoneId, int tipBoneId, float dt) {
120 options.tolerance = tolerance_;
121 options.max_iterations = 1;
122 options.influence = influence_;
123 options.use_pole = usePole_;
124 options.pole = pole_;
125 options.pole_weight = poleWeight_;
126 float f = force_;
127 if (f <= 0.f) {
128 f = std::min(1.f, std::max(0.f, dt));
129 } else {
130 f = std::min(1.f, f * std::max(0.f, dt));
131 }
132 options.force = f;
133 solveChainImpl(skeleton, rootBoneId, tipBoneId, options);
134}
135
136bool Solver3D::solveChainImpl(Skeleton3D *skeleton, int rootBoneId, int tipBoneId,
137 const detail::ChainOptions<3> &options) {
138 if (!skeleton) {
139 throw Exception("Solver3D.solveChain: skeleton is null");
140 }
141 if (rootBoneId < 0 || tipBoneId < 0) {
142 throw Exception("Solver3D.solveChain: bone ids must be >= 0");
143 }
144 const int count = skeleton->getBoneCount();
145 if (rootBoneId >= count || tipBoneId >= count) {
146 throw Exception("Solver3D.solveChain: bone id out of range");
147 }
148 if (rootBoneId == tipBoneId) {
149 throw Exception("Solver3D.solveChain: root and tip must differ");
150 }
151 int b = tipBoneId;
152 bool found = false;
153 while (b >= 0) {
154 if (b == rootBoneId) {
155 found = true;
156 break;
157 }
158 b = skeleton->getParent(b);
159 }
160 if (!found) {
161 throw Exception("Solver3D.solveChain: tipBoneId is not a descendant of rootBoneId");
162 }
163 const bool reached =
164 detail::solveChain<3>(skeleton->native(), skeleton->state(),
165 static_cast<unsigned>(rootBoneId),
166 static_cast<unsigned>(tipBoneId), solver_.targets(), options);
167 applyTipRotation(skeleton);
168 return reached;
169}
170
171void Solver3D::setPole(float x, float y, float z, float weight) {
172 pole_ = ::ik::vec3{x, y, z};
173 poleWeight_ = std::min(1.f, std::max(0.f, weight));
174 usePole_ = true;
175}
176
178 usePole_ = false;
179 poleWeight_ = 1.f;
180}
181
182bool Solver3D::hasPole() const { return usePole_; }
183
184float Solver3D::getPoleWeight() const { return usePole_ ? poleWeight_ : 0.f; }
185
186void Solver3D::setTipRotation(int boneId, float yaw, float pitch, float weight) {
187 if (boneId < 0) {
188 throw Exception("Solver3D.setTipRotation: boneId must be >= 0");
189 }
190 tipBoneId_ = boneId;
191 tipYaw_ = yaw;
192 tipPitch_ = pitch;
193 tipRotWeight_ = std::min(1.f, std::max(0.f, weight));
194}
195
197 tipBoneId_ = -1;
198 tipYaw_ = 0.f;
199 tipPitch_ = 0.f;
200 tipRotWeight_ = 0.f;
201}
202
203float Solver3D::getTipRotationWeight() const { return tipRotWeight_; }
204
205void Solver3D::applyTipRotation(Skeleton3D *skeleton) {
206 if (!skeleton || tipRotWeight_ <= 0.f || tipBoneId_ < 0) {
207 return;
208 }
209 ::ik::skeleton3d &sk = skeleton->native();
210 if (sk.bones().empty()) {
211 sk.topologicalSort();
212 }
213 if (static_cast<size_t>(tipBoneId_) >= sk.bones().size()) {
214 throw Exception("Solver3D.applyTipRotation: bone id out of range");
215 }
216 ::ik::bone3d *b = sk.bones()[static_cast<size_t>(tipBoneId_)];
217 if (!b->parent) {
218 return; // orienting the root would fight the pinned chain root
219 }
220 ::ik::ecs3d &state = skeleton->state();
221 const float w = tipRotWeight_;
222 ::ik::vec2 rot = b->rotation(state);
223 rot[0] = rot[0] + ::ik::wrap_angle(tipYaw_ - rot[0]) * w;
224 rot[1] = rot[1] + ::ik::wrap_angle(tipPitch_ - rot[1]) * w;
225 b->rotation(state) = rot;
226
227 const ::ik::vec3 *gp = nullptr;
228 ::ik::vec3 gp_pos;
229 if (b->parent->parent) {
230 gp_pos = b->parent->parent->position(state);
231 gp = &gp_pos;
232 }
233 const ::ik::vec3 parent_fwd = ::ik::detail::parent_forward_of(
234 b->parent->orientation(state), b->parent->position(state), gp);
235 b->orientation(state) = ::ik::detail::direction_from_local_angles<3>(parent_fwd, rot);
236}
237
238int Solver3D::getTraceSize() const { return static_cast<int>(solver_.traceSize()); }
239
240void Solver3D::clearTrace() { solver_.clearTrace(); }
241
242} // namespace eve::ik
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
int w
JobSystemThreadPool::State * state
uint32_t b
float f
int iterations
Definition TreeMesh.cpp:193
Script-facing 3D skeleton + pose state (ik::skeleton3d + ik::ecs3d). Local angles are yaw/pitch in th...
Definition Skeleton3D.h:11
::ik::skeleton3d & native()
Definition Skeleton3D.h:56
::ik::ecs3d & state()
Definition Skeleton3D.h:57
int getParent(int boneId) const
int getBoneCount() const
void addTarget(int boneId, float x, float y, float z, float weight=1.f)
Definition Solver3D.cpp:54
void setTipRotation(int boneId, float yaw, float pitch, float weight)
Tip orientation override: after solving, blends the tip bone's local yaw/pitch toward the given angle...
Definition Solver3D.cpp:186
float getTipRotationWeight() const
Definition Solver3D.cpp:203
float getPoleWeight() const
Definition Solver3D.cpp:184
float getForce() const
Definition Solver3D.cpp:41
void setTolerance(float tol)
Definition Solver3D.cpp:26
void clearTipRotation()
Definition Solver3D.cpp:196
bool solve(Skeleton3D *skeleton)
Definition Solver3D.cpp:65
void setInfluence(float influence)
Overall pose blend: 0 = keep the input pose, 1 = full solve (default).
Definition Solver3D.cpp:43
int getMaxIterations() const
Definition Solver3D.cpp:24
void stepChain(Skeleton3D *skeleton, int rootBoneId, int tipBoneId, float dt=1.f)
Definition Solver3D.cpp:118
void setForce(float force)
Definition Solver3D.cpp:36
bool solveChain(Skeleton3D *skeleton, int rootBoneId, int tipBoneId)
FABRIK solve restricted to the bone chain rootBoneId..tipBoneId. The chain root stays pinned and bone...
Definition Solver3D.cpp:106
float getInfluence() const
Definition Solver3D.cpp:50
bool hasPole() const
Definition Solver3D.cpp:182
void setMaxIterations(int iterations)
Definition Solver3D.cpp:16
void step(Skeleton3D *skeleton, float dt=1.f)
Definition Solver3D.cpp:86
int getTargetCount() const
Definition Solver3D.cpp:61
int getTraceSize() const
Definition Solver3D.cpp:238
bool getKeepTrace() const
Definition Solver3D.cpp:14
void setPole(float x, float y, float z, float weight)
Pole vector (magnet / hint): pulls the middle joints of a chain toward a point so the limb bends in t...
Definition Solver3D.cpp:171
float getTolerance() const
Definition Solver3D.cpp:34
void setKeepTrace(bool keep)
Definition Solver3D.cpp:9
Options shared by the chain-scoped FABRIK solve used by Solver2D / Solver3D. These mirror the knobs o...
Definition ChainSolver.h:18