载入中...
搜索中...
未找到
AnimLattice.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4#include "model3d/ModelData.h"
5
6#include <assimp/mesh.h>
7#include <assimp/scene.h>
8
9#include <algorithm>
10#include <cmath>
11
12namespace eve::animation {
13
14namespace {
15
17void computeAxis(float u, int divisions, bool clamp, int& i0, float& fu) {
18 const float scaled = u * static_cast<float>(divisions - 1);
19 if (clamp) {
20 if (scaled <= 0.f) {
21 i0 = 0;
22 fu = 0.f;
23 return;
24 }
25 if (scaled >= static_cast<float>(divisions - 1)) {
26 i0 = divisions - 2;
27 fu = 1.f;
28 return;
29 }
30 }
31 i0 = static_cast<int>(std::floor(scaled));
32 fu = scaled - static_cast<float>(i0);
33 if (i0 < 0) {
34 i0 = 0;
35 } else if (i0 > divisions - 2) {
36 i0 = divisions - 2;
37 }
38}
39
40} // namespace
41
43
44AnimLattice::AnimLattice(int divX, int divY, int divZ) { setDivisions(divX, divY, divZ); }
45
46void AnimLattice::setDivisions(int divX, int divY, int divZ) {
47 if (divX < kMinDivisions || divY < kMinDivisions || divZ < kMinDivisions) {
48 throw Exception("AnimLattice.setDivisions: divisions must be >= %d", kMinDivisions);
49 }
50 divX_ = divX;
51 divY_ = divY;
52 divZ_ = divZ;
53 points_.assign(static_cast<size_t>(divX_) * static_cast<size_t>(divY_) * static_cast<size_t>(divZ_),
54 ControlPoint{});
55 clearBind();
56}
57
58void AnimLattice::setSize(float sx, float sy, float sz) {
59 if (sx <= 0.f || sy <= 0.f || sz <= 0.f) {
60 throw Exception("AnimLattice.setSize: size components must be > 0");
61 }
62 sizeX_ = sx;
63 sizeY_ = sy;
64 sizeZ_ = sz;
65}
66
67void AnimLattice::setOrigin(float ox, float oy, float oz) {
68 originX_ = ox;
69 originY_ = oy;
70 originZ_ = oz;
71}
72
73int AnimLattice::pointIndex(int ix, int iy, int iz) const { return (iz * divY_ + iy) * divX_ + ix; }
74
75void AnimLattice::requirePoint(int ix, int iy, int iz) const {
76 if (ix < 0 || ix >= divX_ || iy < 0 || iy >= divY_ || iz < 0 || iz >= divZ_) {
77 throw Exception("AnimLattice: invalid control point (%d,%d,%d) for divisions (%d,%d,%d)", ix, iy, iz, divX_,
78 divY_, divZ_);
79 }
80}
81
82void AnimLattice::requireVertex(int vertexIndex) const {
83 if (vertexIndex < 0 || vertexIndex >= vertexCount_) {
84 throw Exception("AnimLattice: invalid vertex index %d", vertexIndex);
85 }
86}
87
88void AnimLattice::setPointScale(int ix, int iy, int iz, float sx, float sy, float sz) {
89 requirePoint(ix, iy, iz);
90 ControlPoint& p = points_[static_cast<size_t>(pointIndex(ix, iy, iz))];
91 p.sx = sx;
92 p.sy = sy;
93 p.sz = sz;
94}
95
96void AnimLattice::setPointOffset(int ix, int iy, int iz, float dx, float dy, float dz) {
97 requirePoint(ix, iy, iz);
98 ControlPoint& p = points_[static_cast<size_t>(pointIndex(ix, iy, iz))];
99 p.ox = dx;
100 p.oy = dy;
101 p.oz = dz;
102}
103
104void AnimLattice::setScale(float sx, float sy, float sz) {
105 for (ControlPoint& p : points_) {
106 p.sx = sx;
107 p.sy = sy;
108 p.sz = sz;
109 }
110}
111
112void AnimLattice::reset() { std::fill(points_.begin(), points_.end(), ControlPoint{}); }
113
114float AnimLattice::getPointScaleX(int ix, int iy, int iz) const {
115 requirePoint(ix, iy, iz);
116 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].sx;
117}
118float AnimLattice::getPointScaleY(int ix, int iy, int iz) const {
119 requirePoint(ix, iy, iz);
120 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].sy;
121}
122float AnimLattice::getPointScaleZ(int ix, int iy, int iz) const {
123 requirePoint(ix, iy, iz);
124 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].sz;
125}
126float AnimLattice::getPointOffsetX(int ix, int iy, int iz) const {
127 requirePoint(ix, iy, iz);
128 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].ox;
129}
130float AnimLattice::getPointOffsetY(int ix, int iy, int iz) const {
131 requirePoint(ix, iy, iz);
132 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].oy;
133}
134float AnimLattice::getPointOffsetZ(int ix, int iy, int iz) const {
135 requirePoint(ix, iy, iz);
136 return points_[static_cast<size_t>(pointIndex(ix, iy, iz))].oz;
137}
138
139AnimLattice* AnimLattice::fromModel(const model3d::ModelData* model, int meshIndex, int divX, int divY, int divZ) {
140 if (!model) {
141 throw Exception("AnimLattice.fromModel: null model");
142 }
143 const aiMesh* mesh = model->getMesh(meshIndex);
144 if (!mesh) {
145 throw Exception("AnimLattice.fromModel: invalid mesh index %d", meshIndex);
146 }
147 if (mesh->mNumVertices == 0 || !mesh->mVertices) {
148 throw Exception("AnimLattice.fromModel: mesh %d has no vertices", meshIndex);
149 }
150 auto* lattice = new AnimLattice(divX, divY, divZ);
151 lattice->bindPositions(reinterpret_cast<const float*>(mesh->mVertices), static_cast<int>(mesh->mNumVertices));
152 return lattice;
153}
154
156 if (!model) {
157 throw Exception("AnimLattice.bindModel: null model");
158 }
159 const aiMesh* mesh = model->getMesh(meshIndex);
160 if (!mesh) {
161 throw Exception("AnimLattice.bindModel: invalid mesh index %d", meshIndex);
162 }
163 if (mesh->mNumVertices == 0 || !mesh->mVertices) {
164 throw Exception("AnimLattice.bindModel: mesh %d has no vertices", meshIndex);
165 }
166 bindPositions(reinterpret_cast<const float*>(mesh->mVertices), static_cast<int>(mesh->mNumVertices));
167}
168
169void AnimLattice::bindPositions(const float* posXYZ, int count) {
170 if (!posXYZ || count < 0) {
171 throw Exception("AnimLattice.bindPositions: invalid position data");
172 }
173 vertexCount_ = count;
174 bindPos_.resize(static_cast<size_t>(count) * 3u);
175 if (count > 0) {
176 std::copy(posXYZ, posXYZ + static_cast<size_t>(count) * 3u, bindPos_.begin());
177 }
178 deformedValid_ = false;
179 deformedNrmValid_ = false;
180}
181
183 vertexCount_ = 0;
184 bindPos_.clear();
185 deformedValid_ = false;
186 deformedNrmValid_ = false;
187}
188
189float AnimLattice::getBindPositionX(int vertexIndex) const {
190 requireVertex(vertexIndex);
191 return bindPos_[static_cast<size_t>(vertexIndex) * 3u + 0];
192}
193float AnimLattice::getBindPositionY(int vertexIndex) const {
194 requireVertex(vertexIndex);
195 return bindPos_[static_cast<size_t>(vertexIndex) * 3u + 1];
196}
197float AnimLattice::getBindPositionZ(int vertexIndex) const {
198 requireVertex(vertexIndex);
199 return bindPos_[static_cast<size_t>(vertexIndex) * 3u + 2];
200}
201
202void AnimLattice::computeCell(float x, float y, float z, int& i0, int& j0, int& k0, float& fu, float& fv,
203 float& fw) const {
204 const float u = (x - (originX_ - sizeX_ * 0.5f)) / sizeX_;
205 const float v = (y - (originY_ - sizeY_ * 0.5f)) / sizeY_;
206 const float w = (z - (originZ_ - sizeZ_ * 0.5f)) / sizeZ_;
207 computeAxis(u, divX_, clamp_, i0, fu);
208 computeAxis(v, divY_, clamp_, j0, fv);
209 computeAxis(w, divZ_, clamp_, k0, fw);
210}
211
212void AnimLattice::deformPositions(const float* inPosXYZ, float* outPosXYZ, int count) const {
213 if (!inPosXYZ || !outPosXYZ) {
214 throw Exception("AnimLattice.deformPositions: null position buffer");
215 }
216 if (count < 0) {
217 throw Exception("AnimLattice.deformPositions: negative vertex count");
218 }
219 for (int v = 0; v < count; ++v) {
220 const float x = inPosXYZ[static_cast<size_t>(v) * 3u + 0];
221 const float y = inPosXYZ[static_cast<size_t>(v) * 3u + 1];
222 const float z = inPosXYZ[static_cast<size_t>(v) * 3u + 2];
223
224 int i0, j0, k0;
225 float fu, fv, fw;
226 computeCell(x, y, z, i0, j0, k0, fu, fv, fw);
227
228 float ox = 0.f, oy = 0.f, oz = 0.f;
229 float sx = 0.f, sy = 0.f, sz = 0.f;
230 for (int di = 0; di < 2; ++di) {
231 const float wu = di ? fu : 1.f - fu;
232 for (int dj = 0; dj < 2; ++dj) {
233 const float wv = dj ? fv : 1.f - fv;
234 for (int dk = 0; dk < 2; ++dk) {
235 const float ww = dk ? fw : 1.f - fw;
236 const float weight = wu * wv * ww;
237 const ControlPoint& p = points_[static_cast<size_t>(pointIndex(i0 + di, j0 + dj, k0 + dk))];
238 ox += p.ox * weight;
239 oy += p.oy * weight;
240 oz += p.oz * weight;
241 sx += p.sx * weight;
242 sy += p.sy * weight;
243 sz += p.sz * weight;
244 }
245 }
246 }
247
248 const float rx = x - originX_;
249 const float ry = y - originY_;
250 const float rz = z - originZ_;
251 outPosXYZ[static_cast<size_t>(v) * 3u + 0] = originX_ + ox + sx * rx;
252 outPosXYZ[static_cast<size_t>(v) * 3u + 1] = originY_ + oy + sy * ry;
253 outPosXYZ[static_cast<size_t>(v) * 3u + 2] = originZ_ + oz + sz * rz;
254 }
255}
256
257bool AnimLattice::deformPositionsTo(const std::vector<float>& inPosXYZ, std::vector<float>& outPosXYZ) const {
258 if (inPosXYZ.empty() || inPosXYZ.size() % 3u != 0) return false;
259 const int count = static_cast<int>(inPosXYZ.size() / 3u);
260 outPosXYZ.resize(inPosXYZ.size());
261 deformPositions(inPosXYZ.data(), outPosXYZ.data(), count);
262 return true;
263}
264
265bool AnimLattice::deformNormals(const float* posXYZ, const float* inNrmXYZ, float* outNrmXYZ, int count) const {
266 if (!posXYZ || !inNrmXYZ || !outNrmXYZ || count < 0) return false;
267 if (vertexCount_ > 0 && count != vertexCount_) return false;
268 for (int v = 0; v < count; ++v) {
269 const float px = posXYZ[static_cast<size_t>(v) * 3u + 0];
270 const float py = posXYZ[static_cast<size_t>(v) * 3u + 1];
271 const float pz = posXYZ[static_cast<size_t>(v) * 3u + 2];
272
273 int i0, j0, k0;
274 float fu, fv, fw;
275 computeCell(px, py, pz, i0, j0, k0, fu, fv, fw);
276
277 float sx = 0.f, sy = 0.f, sz = 0.f;
278 for (int di = 0; di < 2; ++di) {
279 const float wu = di ? fu : 1.f - fu;
280 for (int dj = 0; dj < 2; ++dj) {
281 const float wv = dj ? fv : 1.f - fv;
282 for (int dk = 0; dk < 2; ++dk) {
283 const float ww = dk ? fw : 1.f - fw;
284 const float weight = wu * wv * ww;
285 const ControlPoint& p = points_[static_cast<size_t>(pointIndex(i0 + di, j0 + dj, k0 + dk))];
286 sx += p.sx * weight;
287 sy += p.sy * weight;
288 sz += p.sz * weight;
289 }
290 }
291 }
292
293 const float nx = sx * inNrmXYZ[static_cast<size_t>(v) * 3u + 0];
294 const float ny = sy * inNrmXYZ[static_cast<size_t>(v) * 3u + 1];
295 const float nz = sz * inNrmXYZ[static_cast<size_t>(v) * 3u + 2];
296 const float len = std::sqrt(nx * nx + ny * ny + nz * nz);
297 if (len > 1e-8f) {
298 outNrmXYZ[static_cast<size_t>(v) * 3u + 0] = nx / len;
299 outNrmXYZ[static_cast<size_t>(v) * 3u + 1] = ny / len;
300 outNrmXYZ[static_cast<size_t>(v) * 3u + 2] = nz / len;
301 } else {
302 outNrmXYZ[static_cast<size_t>(v) * 3u + 0] = inNrmXYZ[static_cast<size_t>(v) * 3u + 0];
303 outNrmXYZ[static_cast<size_t>(v) * 3u + 1] = inNrmXYZ[static_cast<size_t>(v) * 3u + 1];
304 outNrmXYZ[static_cast<size_t>(v) * 3u + 2] = inNrmXYZ[static_cast<size_t>(v) * 3u + 2];
305 }
306 }
307 return true;
308}
309
310bool AnimLattice::updateDeformedPositions(const std::vector<float>& inPosXYZ) {
311 if (vertexCount_ <= 0 || inPosXYZ.size() < static_cast<size_t>(vertexCount_) * 3u) {
312 deformedValid_ = false;
313 return false;
314 }
315 deformedPos_.resize(static_cast<size_t>(vertexCount_) * 3u);
316 deformPositions(inPosXYZ.data(), deformedPos_.data(), vertexCount_);
317 deformedValid_ = true;
318 return true;
319}
320
322 if (vertexCount_ <= 0) {
323 deformedValid_ = false;
324 return false;
325 }
326 return updateDeformedPositions(bindPos_);
327}
328
329bool AnimLattice::updateDeformedNormals(const std::vector<float>& posXYZ, const std::vector<float>& inNrmXYZ) {
330 if (vertexCount_ <= 0 || posXYZ.size() < static_cast<size_t>(vertexCount_) * 3u ||
331 inNrmXYZ.size() < static_cast<size_t>(vertexCount_) * 3u) {
332 deformedNrmValid_ = false;
333 return false;
334 }
335 deformedNrm_.resize(static_cast<size_t>(vertexCount_) * 3u);
336 if (!deformNormals(posXYZ.data(), inNrmXYZ.data(), deformedNrm_.data(), vertexCount_)) {
337 deformedNrmValid_ = false;
338 return false;
339 }
340 deformedNrmValid_ = true;
341 return true;
342}
343
344float AnimLattice::getDeformedPositionX(int vertexIndex) const {
345 requireVertex(vertexIndex);
346 if (!deformedValid_) {
347 throw Exception("AnimLattice.getDeformedPositionX: call updateDeformedPositions first");
348 }
349 return deformedPos_[static_cast<size_t>(vertexIndex) * 3u + 0];
350}
351float AnimLattice::getDeformedPositionY(int vertexIndex) const {
352 requireVertex(vertexIndex);
353 if (!deformedValid_) {
354 throw Exception("AnimLattice.getDeformedPositionY: call updateDeformedPositions first");
355 }
356 return deformedPos_[static_cast<size_t>(vertexIndex) * 3u + 1];
357}
358float AnimLattice::getDeformedPositionZ(int vertexIndex) const {
359 requireVertex(vertexIndex);
360 if (!deformedValid_) {
361 throw Exception("AnimLattice.getDeformedPositionZ: call updateDeformedPositions first");
362 }
363 return deformedPos_[static_cast<size_t>(vertexIndex) * 3u + 2];
364}
365
366std::vector<float> AnimLattice::getDeformedPositions() const {
367 return deformedValid_ ? deformedPos_ : std::vector<float>();
368}
369
370std::vector<float> AnimLattice::getDeformedNormals() const {
371 return deformedNrmValid_ ? deformedNrm_ : std::vector<float>();
372}
373
374} // namespace eve::animation
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
uint32_t i0
Definition Grass.cpp:62
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
int w
std::vector< Colorf > px
glm::vec4 p[6]
Mesh * mesh
glm::mat4 model
int v
CPU 3D lattice scale-deformer (晶格缩放变形).
Definition AnimLattice.h:41
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
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
void setOrigin(float ox, float oy, float oz)
Center of the lattice box in model space.
void bindModel(const model3d::ModelData *model, int meshIndex)
Binds the current lattice to meshIndex of model (uses current divisions).
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
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
float getDeformedPositionY(int vertexIndex) const
void setSize(float sx, float sy, float sz)
World-space size of the lattice box (components must be > 0).
float getDeformedPositionZ(int vertexIndex) const
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
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:43
static AnimLattice * fromModel(const model3d::ModelData *model, int meshIndex, int divX, int divY, int divZ)
Builds a lattice bound to meshIndex of model (Assimp vertices). Throws on null model / invalid mesh /...
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
void reset()
Resets every control point to identity (offset 0, scale 1).
float getPointScaleZ(int ix, int iy, int iz) const
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
CPU-side decoded 3D model (Assimp scene owned via medialoader::ModelScene). Does not upload to GPU — ...
Definition ModelData.h:23