载入中...
搜索中...
未找到
AnimLattice.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4
5
6#include <algorithm>
7#include <cmath>
8
9namespace eve::animation {
10
11namespace {
12
14void computeAxis(float u, int divisions, bool clamp, int& i0, float& fu) {
15 const float scaled = u * static_cast<float>(divisions - 1);
16 if (clamp) {
17 if (scaled <= 0.f) {
18 i0 = 0;
19 fu = 0.f;
20 return;
21 }
22 if (scaled >= static_cast<float>(divisions - 1)) {
23 i0 = divisions - 2;
24 fu = 1.f;
25 return;
26 }
27 }
28 i0 = static_cast<int>(std::floor(scaled));
29 fu = scaled - static_cast<float>(i0);
30 if (i0 < 0) {
31 i0 = 0;
32 } else if (i0 > divisions - 2) {
33 i0 = divisions - 2;
34 }
35}
36
37} // namespace
38
40
41AnimLattice::AnimLattice(int divX, int divY, int divZ) { setDivisions(divX, divY, divZ); }
42
43void AnimLattice::setDivisions(int divX, int divY, int divZ) {
44 if (divX < kMinDivisions || divY < kMinDivisions || divZ < kMinDivisions) {
45 throw Exception("AnimLattice.setDivisions: divisions must be >= %d", kMinDivisions);
46 }
47 divX_ = divX;
48 divY_ = divY;
49 divZ_ = divZ;
50 points_.assign(static_cast<size_t>(divX_) * static_cast<size_t>(divY_) * static_cast<size_t>(divZ_),
51 ControlPoint{});
52 clearBind();
53}
54
55void AnimLattice::setSize(float sx, float sy, float sz) {
56 if (sx <= 0.f || sy <= 0.f || sz <= 0.f) {
57 throw Exception("AnimLattice.setSize: size components must be > 0");
58 }
59 sizeX_ = sx;
60 sizeY_ = sy;
61 sizeZ_ = sz;
62}
63
64void AnimLattice::setOrigin(float ox, float oy, float oz) {
65 originX_ = ox;
66 originY_ = oy;
67 originZ_ = oz;
68}
69
70int AnimLattice::pointIndex(int ix, int iy, int iz) const { return (iz * divY_ + iy) * divX_ + ix; }
71
72void AnimLattice::requirePoint(int ix, int iy, int iz) const {
73 if (ix < 0 || ix >= divX_ || iy < 0 || iy >= divY_ || iz < 0 || iz >= divZ_) {
74 throw Exception("AnimLattice: invalid control point (%d,%d,%d) for divisions (%d,%d,%d)", ix, iy, iz, divX_,
75 divY_, divZ_);
76 }
77}
78
79void AnimLattice::requireVertex(int vertexIndex) const {
80 if (vertexIndex < 0 || vertexIndex >= vertexCount_) {
81 throw Exception("AnimLattice: invalid vertex index %d", vertexIndex);
82 }
83}
84
85void AnimLattice::setPointScale(int ix, int iy, int iz, float sx, float sy, float sz) {
86 requirePoint(ix, iy, iz);
87 ControlPoint& p = points_[static_cast<size_t>(pointIndex(ix, iy, iz))];
88 p.sx = sx;
89 p.sy = sy;
90 p.sz = sz;
91}
92
93void AnimLattice::setPointOffset(int ix, int iy, int iz, float dx, float dy, float dz) {
94 requirePoint(ix, iy, iz);
95 ControlPoint& p = points_[static_cast<size_t>(pointIndex(ix, iy, iz))];
96 p.ox = dx;
97 p.oy = dy;
98 p.oz = dz;
99}
100
101void AnimLattice::setScale(float sx, float sy, float sz) {
102 for (ControlPoint& p : points_) {
103 p.sx = sx;
104 p.sy = sy;
105 p.sz = sz;
106 }
107}
108
109void AnimLattice::reset() { std::fill(points_.begin(), points_.end(), ControlPoint{}); }
110
111float AnimLattice::getPointScaleX(int ix, int iy, int iz) const {
112 requirePoint(ix, iy, iz);
113 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].sx;
114}
115float AnimLattice::getPointScaleY(int ix, int iy, int iz) const {
116 requirePoint(ix, iy, iz);
117 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].sy;
118}
119float AnimLattice::getPointScaleZ(int ix, int iy, int iz) const {
120 requirePoint(ix, iy, iz);
121 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].sz;
122}
123float AnimLattice::getPointOffsetX(int ix, int iy, int iz) const {
124 requirePoint(ix, iy, iz);
125 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].ox;
126}
127float AnimLattice::getPointOffsetY(int ix, int iy, int iz) const {
128 requirePoint(ix, iy, iz);
129 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].oy;
130}
131float AnimLattice::getPointOffsetZ(int ix, int iy, int iz) const {
132 requirePoint(ix, iy, iz);
133 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].oz;
134}
135
136void AnimLattice::bindPositions(const float* posXYZ, int count) {
137 if (!posXYZ || count < 0) {
138 throw Exception("AnimLattice.bindPositions: invalid position data");
139 }
140 vertexCount_ = count;
141 bindPos_.resize(static_cast<size_t>(count) * 3u);
142 if (count > 0) {
143 std::copy(posXYZ, posXYZ + static_cast<size_t>(count) * 3u, bindPos_.begin());
144 }
145 deformedValid_ = false;
146 deformedNrmValid_ = false;
147}
148
150 vertexCount_ = 0;
151 bindPos_.clear();
152 deformedValid_ = false;
153 deformedNrmValid_ = false;
154}
155
156float AnimLattice::getBindPositionX(int vertexIndex) const {
157 requireVertex(vertexIndex);
158 return bindPos_[static_cast<size_t>(vertexIndex) * 3u + 0];
159}
160float AnimLattice::getBindPositionY(int vertexIndex) const {
161 requireVertex(vertexIndex);
162 return bindPos_[static_cast<size_t>(vertexIndex) * 3u + 1];
163}
164float AnimLattice::getBindPositionZ(int vertexIndex) const {
165 requireVertex(vertexIndex);
166 return bindPos_[static_cast<size_t>(vertexIndex) * 3u + 2];
167}
168
169void AnimLattice::computeCell(float x, float y, float z, int& i0, int& j0, int& k0, float& fu, float& fv,
170 float& fw) const {
171 const float u = (x - (originX_ - sizeX_ * 0.5f)) / sizeX_;
172 const float v = (y - (originY_ - sizeY_ * 0.5f)) / sizeY_;
173 const float w = (z - (originZ_ - sizeZ_ * 0.5f)) / sizeZ_;
174 computeAxis(u, divX_, clamp_, i0, fu);
175 computeAxis(v, divY_, clamp_, j0, fv);
176 computeAxis(w, divZ_, clamp_, k0, fw);
177}
178
179void AnimLattice::deformPositions(const float* inPosXYZ, float* outPosXYZ, int count) const {
180 if (!inPosXYZ || !outPosXYZ) {
181 throw Exception("AnimLattice.deformPositions: null position buffer");
182 }
183 if (count < 0) {
184 throw Exception("AnimLattice.deformPositions: negative vertex count");
185 }
186 for (int v = 0; v < count; ++v) {
187 const float x = inPosXYZ[static_cast<size_t>(v) * 3u + 0];
188 const float y = inPosXYZ[static_cast<size_t>(v) * 3u + 1];
189 const float z = inPosXYZ[static_cast<size_t>(v) * 3u + 2];
190
191 int i0, j0, k0;
192 float fu, fv, fw;
193 computeCell(x, y, z, i0, j0, k0, fu, fv, fw);
194
195 float ox = 0.f, oy = 0.f, oz = 0.f;
196 float sx = 0.f, sy = 0.f, sz = 0.f;
197 for (int di = 0; di < 2; ++di) {
198 const float wu = di ? fu : 1.f - fu;
199 for (int dj = 0; dj < 2; ++dj) {
200 const float wv = dj ? fv : 1.f - fv;
201 for (int dk = 0; dk < 2; ++dk) {
202 const float ww = dk ? fw : 1.f - fw;
203 const float weight = wu * wv * ww;
204 const ControlPoint& p = points_[static_cast<size_t>(pointIndex(i0 + di, j0 + dj, k0 + dk))];
205 ox += p.ox * weight;
206 oy += p.oy * weight;
207 oz += p.oz * weight;
208 sx += p.sx * weight;
209 sy += p.sy * weight;
210 sz += p.sz * weight;
211 }
212 }
213 }
214
215 const float rx = x - originX_;
216 const float ry = y - originY_;
217 const float rz = z - originZ_;
218 outPosXYZ[static_cast<size_t>(v) * 3u + 0] = originX_ + ox + sx * rx;
219 outPosXYZ[static_cast<size_t>(v) * 3u + 1] = originY_ + oy + sy * ry;
220 outPosXYZ[static_cast<size_t>(v) * 3u + 2] = originZ_ + oz + sz * rz;
221 }
222}
223
224bool AnimLattice::deformPositionsTo(const std::vector<float>& inPosXYZ, std::vector<float>& outPosXYZ) const {
225 if (inPosXYZ.empty() || inPosXYZ.size() % 3u != 0) return false;
226 const int count = static_cast<int>(inPosXYZ.size() / 3u);
227 outPosXYZ.resize(inPosXYZ.size());
228 deformPositions(inPosXYZ.data(), outPosXYZ.data(), count);
229 return true;
230}
231
232bool AnimLattice::deformNormals(const float* posXYZ, const float* inNrmXYZ, float* outNrmXYZ, int count) const {
233 if (!posXYZ || !inNrmXYZ || !outNrmXYZ || count < 0) return false;
234 if (vertexCount_ > 0 && count != vertexCount_) return false;
235 for (int v = 0; v < count; ++v) {
236 const float px = posXYZ[static_cast<size_t>(v) * 3u + 0];
237 const float py = posXYZ[static_cast<size_t>(v) * 3u + 1];
238 const float pz = posXYZ[static_cast<size_t>(v) * 3u + 2];
239
240 int i0, j0, k0;
241 float fu, fv, fw;
242 computeCell(px, py, pz, i0, j0, k0, fu, fv, fw);
243
244 float sx = 0.f, sy = 0.f, sz = 0.f;
245 for (int di = 0; di < 2; ++di) {
246 const float wu = di ? fu : 1.f - fu;
247 for (int dj = 0; dj < 2; ++dj) {
248 const float wv = dj ? fv : 1.f - fv;
249 for (int dk = 0; dk < 2; ++dk) {
250 const float ww = dk ? fw : 1.f - fw;
251 const float weight = wu * wv * ww;
252 const ControlPoint& p = points_[static_cast<size_t>(pointIndex(i0 + di, j0 + dj, k0 + dk))];
253 sx += p.sx * weight;
254 sy += p.sy * weight;
255 sz += p.sz * weight;
256 }
257 }
258 }
259
260 const float nx = sx * inNrmXYZ[static_cast<size_t>(v) * 3u + 0];
261 const float ny = sy * inNrmXYZ[static_cast<size_t>(v) * 3u + 1];
262 const float nz = sz * inNrmXYZ[static_cast<size_t>(v) * 3u + 2];
263 const float len = std::sqrt(nx * nx + ny * ny + nz * nz);
264 if (len > 1e-8f) {
265 outNrmXYZ[static_cast<size_t>(v) * 3u + 0] = nx / len;
266 outNrmXYZ[static_cast<size_t>(v) * 3u + 1] = ny / len;
267 outNrmXYZ[static_cast<size_t>(v) * 3u + 2] = nz / len;
268 } else {
269 outNrmXYZ[static_cast<size_t>(v) * 3u + 0] = inNrmXYZ[static_cast<size_t>(v) * 3u + 0];
270 outNrmXYZ[static_cast<size_t>(v) * 3u + 1] = inNrmXYZ[static_cast<size_t>(v) * 3u + 1];
271 outNrmXYZ[static_cast<size_t>(v) * 3u + 2] = inNrmXYZ[static_cast<size_t>(v) * 3u + 2];
272 }
273 }
274 return true;
275}
276
277bool AnimLattice::updateDeformedPositions(const std::vector<float>& inPosXYZ) {
278 if (vertexCount_ <= 0 || inPosXYZ.size() < static_cast<size_t>(vertexCount_) * 3u) {
279 deformedValid_ = false;
280 return false;
281 }
282 deformedPos_.resize(static_cast<size_t>(vertexCount_) * 3u);
283 deformPositions(inPosXYZ.data(), deformedPos_.data(), vertexCount_);
284 deformedValid_ = true;
285 return true;
286}
287
289 if (vertexCount_ <= 0) {
290 deformedValid_ = false;
291 return false;
292 }
293 return updateDeformedPositions(bindPos_);
294}
295
296bool AnimLattice::updateDeformedNormals(const std::vector<float>& posXYZ, const std::vector<float>& inNrmXYZ) {
297 if (vertexCount_ <= 0 || posXYZ.size() < static_cast<size_t>(vertexCount_) * 3u ||
298 inNrmXYZ.size() < static_cast<size_t>(vertexCount_) * 3u) {
299 deformedNrmValid_ = false;
300 return false;
301 }
302 deformedNrm_.resize(static_cast<size_t>(vertexCount_) * 3u);
303 if (!deformNormals(posXYZ.data(), inNrmXYZ.data(), deformedNrm_.data(), vertexCount_)) {
304 deformedNrmValid_ = false;
305 return false;
306 }
307 deformedNrmValid_ = true;
308 return true;
309}
310
311float AnimLattice::getDeformedPositionX(int vertexIndex) const {
312 requireVertex(vertexIndex);
313 if (!deformedValid_) {
314 throw Exception("AnimLattice.getDeformedPositionX: call updateDeformedPositions first");
315 }
316 return deformedPos_[static_cast<size_t>(vertexIndex) * 3u + 0];
317}
318float AnimLattice::getDeformedPositionY(int vertexIndex) const {
319 requireVertex(vertexIndex);
320 if (!deformedValid_) {
321 throw Exception("AnimLattice.getDeformedPositionY: call updateDeformedPositions first");
322 }
323 return deformedPos_[static_cast<size_t>(vertexIndex) * 3u + 1];
324}
325float AnimLattice::getDeformedPositionZ(int vertexIndex) const {
326 requireVertex(vertexIndex);
327 if (!deformedValid_) {
328 throw Exception("AnimLattice.getDeformedPositionZ: call updateDeformedPositions first");
329 }
330 return deformedPos_[static_cast<size_t>(vertexIndex) * 3u + 2];
331}
332
333std::vector<float> AnimLattice::getDeformedPositions() const {
334 return deformedValid_ ? deformedPos_ : std::vector<float>();
335}
336
337std::vector<float> AnimLattice::getDeformedNormals() const {
338 return deformedNrmValid_ ? deformedNrm_ : std::vector<float>();
339}
340
341} // namespace eve::animation
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
float py
float nx
float nz
float ny
float pz
glm::vec4 p[6]
uint32_t i0
Definition Grass.cpp:61
float u
Definition Grass.cpp:233
float v
std::vector< Colorf > px
float dz
float dy
float dx
std::uint32_t count
double oy
double ox
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
void setDivisions(int divX, int divY, int divZ)
Changes divisions; resets all control points to identity and clears the bind.
float getDeformedPositionX(int vertexIndex) const
Cached deformed position component (requires updateDeformedPositions).
std::vector< float > getDeformedNormals() const
Copy of the cached deformed normals (xyz packed; empty when not updated).
std::vector< float > getDeformedPositions() const
Copy of the cached deformed positions (xyz packed; empty when not updated).
void setPointScale(int ix, int iy, int iz, float sx, float sy, float sz)
Per-control-point scale (squash / stretch about the lattice origin).
float getPointOffsetX(int ix, int iy, int iz) const
Returns the point offset x.
bool updateDeformedPositions()
Deform the bound bind positions into the internal cache.
bool deformNormals(const float *posXYZ, const float *inNrmXYZ, float *outNrmXYZ, int count) const
Transforms normals with the interpolated scale field and renormalizes. posXYZ provides the (deformed)...
float getBindPositionZ(int vertexIndex) const
Returns the bind position z.
void setOrigin(float ox, float oy, float oz)
Center of the lattice box in model space.
bool updateDeformedNormals(const std::vector< float > &posXYZ, const std::vector< float > &inNrmXYZ)
Deform packed xyz normals (with packed positions for cell lookup) into the internal normal cache.
float getPointScaleX(int ix, int iy, int iz) const
Returns the point scale x.
void deformPositions(const float *inPosXYZ, float *outPosXYZ, int count) const
Deforms count packed xyz positions into outPosXYZ. Both buffers must hold count * 3 floats; count mus...
float getPointOffsetY(int ix, int iy, int iz) const
Returns the point offset y.
float getDeformedPositionY(int vertexIndex) const
Returns the deformed position y.
void clearBind()
Clears bind.
void setSize(float sx, float sy, float sz)
World-space size of the lattice box (components must be > 0).
float getDeformedPositionZ(int vertexIndex) const
Returns the deformed position z.
void setPointOffset(int ix, int iy, int iz, float dx, float dy, float dz)
Per-control-point translation offset (local bulge / pinch).
float getPointScaleY(int ix, int iy, int iz) const
Returns the point scale y.
void setScale(float sx, float sy, float sz)
Applies one scale to every control point (whole-lattice squash & stretch).
static constexpr int kMinDivisions
Definition AnimLattice.h:44
bool deformPositionsTo(const std::vector< float > &inPosXYZ, std::vector< float > &outPosXYZ) const
Convenience: deform into a vector sized count*3.
float getBindPositionX(int vertexIndex) const
Bind-pose position component for vertex v (0..vertexCount-1).
float getPointOffsetZ(int ix, int iy, int iz) const
Returns the point offset z.
void reset()
Resets every control point to identity (offset 0, scale 1).
float getPointScaleZ(int ix, int iy, int iz) const
Returns the point scale z.
void bindPositions(const float *posXYZ, int count)
Binds a packed xyz array (count * 3 floats). Uses current divisions/size/origin.
float getBindPositionY(int vertexIndex) const
Returns the bind position y.