1 | /* |
---|---|
2 | --------------------------------------------------------------------------- |
3 | Open Asset Import Library (assimp) |
4 | --------------------------------------------------------------------------- |
5 | |
6 | Copyright (c) 2006-2024, assimp team |
7 | |
8 | All rights reserved. |
9 | |
10 | Redistribution and use of this software in source and binary forms, |
11 | with or without modification, are permitted provided that the following |
12 | conditions are met: |
13 | |
14 | * Redistributions of source code must retain the above |
15 | copyright notice, this list of conditions and the |
16 | following disclaimer. |
17 | |
18 | * Redistributions in binary form must reproduce the above |
19 | copyright notice, this list of conditions and the |
20 | following disclaimer in the documentation and/or other |
21 | materials provided with the distribution. |
22 | |
23 | * Neither the name of the assimp team, nor the names of its |
24 | contributors may be used to endorse or promote products |
25 | derived from this software without specific prior |
26 | written permission of the assimp team. |
27 | |
28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
29 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
31 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
32 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
33 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
34 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
35 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
36 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
37 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
38 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | --------------------------------------------------------------------------- |
40 | */ |
41 | |
42 | /** @file mesh.h |
43 | * @brief Declares the data structures in which the imported geometry is |
44 | returned by ASSIMP: aiMesh, aiFace and aiBone data structures. |
45 | */ |
46 | #pragma once |
47 | #ifndef AI_MESH_H_INC |
48 | #define AI_MESH_H_INC |
49 | |
50 | #ifdef __GNUC__ |
51 | #pragma GCC system_header |
52 | #endif |
53 | |
54 | #ifdef _MSC_VER |
55 | #pragma warning(disable : 4351) |
56 | #endif // _MSC_VER |
57 | |
58 | #include <assimp/aabb.h> |
59 | #include <assimp/types.h> |
60 | |
61 | #ifdef __cplusplus |
62 | #include <unordered_set> |
63 | |
64 | extern "C"{ |
65 | #endif |
66 | |
67 | // --------------------------------------------------------------------------- |
68 | // Limits. These values are required to match the settings Assimp was |
69 | // compiled against. Therefore, do not redefine them unless you build the |
70 | // library from source using the same definitions. |
71 | // --------------------------------------------------------------------------- |
72 | |
73 | /** @def AI_MAX_FACE_INDICES |
74 | * Maximum number of indices per face (polygon). */ |
75 | |
76 | #ifndef AI_MAX_FACE_INDICES |
77 | #define AI_MAX_FACE_INDICES 0x7fff |
78 | #endif |
79 | |
80 | /** @def AI_MAX_BONE_WEIGHTS |
81 | * Maximum number of indices per face (polygon). */ |
82 | |
83 | #ifndef AI_MAX_BONE_WEIGHTS |
84 | #define AI_MAX_BONE_WEIGHTS 0x7fffffff |
85 | #endif |
86 | |
87 | /** @def AI_MAX_VERTICES |
88 | * Maximum number of vertices per mesh. */ |
89 | |
90 | #ifndef AI_MAX_VERTICES |
91 | #define AI_MAX_VERTICES 0x7fffffff |
92 | #endif |
93 | |
94 | /** @def AI_MAX_FACES |
95 | * Maximum number of faces per mesh. */ |
96 | |
97 | #ifndef AI_MAX_FACES |
98 | #define AI_MAX_FACES 0x7fffffff |
99 | #endif |
100 | |
101 | /** @def AI_MAX_NUMBER_OF_COLOR_SETS |
102 | * Supported number of vertex color sets per mesh. */ |
103 | |
104 | #ifndef AI_MAX_NUMBER_OF_COLOR_SETS |
105 | #define AI_MAX_NUMBER_OF_COLOR_SETS 0x8 |
106 | #endif // !! AI_MAX_NUMBER_OF_COLOR_SETS |
107 | |
108 | /** @def AI_MAX_NUMBER_OF_TEXTURECOORDS |
109 | * Supported number of texture coord sets (UV(W) channels) per mesh */ |
110 | |
111 | #ifndef AI_MAX_NUMBER_OF_TEXTURECOORDS |
112 | #define AI_MAX_NUMBER_OF_TEXTURECOORDS 0x8 |
113 | #endif // !! AI_MAX_NUMBER_OF_TEXTURECOORDS |
114 | |
115 | // --------------------------------------------------------------------------- |
116 | /** |
117 | * @brief A single face in a mesh, referring to multiple vertices. |
118 | * |
119 | * If mNumIndices is 3, we call the face 'triangle', for mNumIndices > 3 |
120 | * it's called 'polygon' (hey, that's just a definition!). |
121 | * <br> |
122 | * aiMesh::mPrimitiveTypes can be queried to quickly examine which types of |
123 | * primitive are actually present in a mesh. The #aiProcess_SortByPType flag |
124 | * executes a special post-processing algorithm which splits meshes with |
125 | * *different* primitive types mixed up (e.g. lines and triangles) in several |
126 | * 'clean' sub-meshes. Furthermore there is a configuration option ( |
127 | * #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove |
128 | * specific kinds of primitives from the imported scene, completely and forever. |
129 | * In many cases you'll probably want to set this setting to |
130 | * @code |
131 | * aiPrimitiveType_LINE|aiPrimitiveType_POINT |
132 | * @endcode |
133 | * Together with the #aiProcess_Triangulate flag you can then be sure that |
134 | * #aiFace::mNumIndices is always 3. |
135 | * @note Take a look at the @link data Data Structures page @endlink for |
136 | * more information on the layout and winding order of a face. |
137 | */ |
138 | struct aiFace { |
139 | //! Number of indices defining this face. |
140 | //! The maximum value for this member is #AI_MAX_FACE_INDICES. |
141 | unsigned int mNumIndices; |
142 | |
143 | //! Pointer to the indices array. Size of the array is given in numIndices. |
144 | unsigned int *mIndices; |
145 | |
146 | #ifdef __cplusplus |
147 | |
148 | //! @brief Default constructor. |
149 | aiFace() AI_NO_EXCEPT |
150 | : mNumIndices(0), |
151 | mIndices(nullptr) { |
152 | // empty |
153 | } |
154 | |
155 | //! @brief Default destructor. Delete the index array |
156 | ~aiFace() { |
157 | delete[] mIndices; |
158 | } |
159 | |
160 | //! @brief Copy constructor. Copy the index array |
161 | aiFace(const aiFace &o) : |
162 | mNumIndices(0), mIndices(nullptr) { |
163 | *this = o; |
164 | } |
165 | |
166 | //! @brief Assignment operator. Copy the index array |
167 | aiFace &operator=(const aiFace &o) { |
168 | if (&o == this) { |
169 | return *this; |
170 | } |
171 | |
172 | delete[] mIndices; |
173 | mNumIndices = o.mNumIndices; |
174 | if (mNumIndices) { |
175 | mIndices = new unsigned int[mNumIndices]; |
176 | ::memcpy(dest: mIndices, src: o.mIndices, n: mNumIndices * sizeof(unsigned int)); |
177 | } else { |
178 | mIndices = nullptr; |
179 | } |
180 | |
181 | return *this; |
182 | } |
183 | |
184 | //! @brief Comparison operator. Checks whether the index array of two faces is identical. |
185 | bool operator==(const aiFace &o) const { |
186 | if (mIndices == o.mIndices) { |
187 | return true; |
188 | } |
189 | |
190 | if (nullptr != mIndices && mNumIndices != o.mNumIndices) { |
191 | return false; |
192 | } |
193 | |
194 | if (nullptr == mIndices) { |
195 | return false; |
196 | } |
197 | |
198 | for (unsigned int i = 0; i < this->mNumIndices; ++i) { |
199 | if (mIndices[i] != o.mIndices[i]) { |
200 | return false; |
201 | } |
202 | } |
203 | |
204 | return true; |
205 | } |
206 | |
207 | //! @brief Inverse comparison operator. Checks whether the index |
208 | //! array of two faces is NOT identical |
209 | bool operator!=(const aiFace &o) const { |
210 | return !(*this == o); |
211 | } |
212 | #endif // __cplusplus |
213 | }; // struct aiFace |
214 | |
215 | // --------------------------------------------------------------------------- |
216 | /** @brief A single influence of a bone on a vertex. |
217 | */ |
218 | struct aiVertexWeight { |
219 | //! Index of the vertex which is influenced by the bone. |
220 | unsigned int mVertexId; |
221 | |
222 | //! The strength of the influence in the range (0...1). |
223 | //! The influence from all bones at one vertex amounts to 1. |
224 | ai_real mWeight; |
225 | |
226 | #ifdef __cplusplus |
227 | |
228 | //! @brief Default constructor |
229 | aiVertexWeight() AI_NO_EXCEPT |
230 | : mVertexId(0), |
231 | mWeight(0.0f) { |
232 | // empty |
233 | } |
234 | |
235 | //! @brief Initialization from a given index and vertex weight factor |
236 | //! \param pID ID |
237 | //! \param pWeight Vertex weight factor |
238 | aiVertexWeight(unsigned int pID, float pWeight) : |
239 | mVertexId(pID), mWeight(pWeight) { |
240 | // empty |
241 | } |
242 | |
243 | bool operator==(const aiVertexWeight &rhs) const { |
244 | return (mVertexId == rhs.mVertexId && mWeight == rhs.mWeight); |
245 | } |
246 | |
247 | bool operator!=(const aiVertexWeight &rhs) const { |
248 | return (*this == rhs); |
249 | } |
250 | |
251 | #endif // __cplusplus |
252 | }; |
253 | |
254 | // Forward declare aiNode (pointer use only) |
255 | struct aiNode; |
256 | |
257 | // --------------------------------------------------------------------------- |
258 | /** @brief A single bone of a mesh. |
259 | * |
260 | * A bone has a name by which it can be found in the frame hierarchy and by |
261 | * which it can be addressed by animations. In addition it has a number of |
262 | * influences on vertices, and a matrix relating the mesh position to the |
263 | * position of the bone at the time of binding. |
264 | */ |
265 | struct aiBone { |
266 | /** |
267 | * The name of the bone. |
268 | */ |
269 | C_STRUCT aiString mName; |
270 | |
271 | /** |
272 | * The number of vertices affected by this bone. |
273 | * The maximum value for this member is #AI_MAX_BONE_WEIGHTS. |
274 | */ |
275 | unsigned int mNumWeights; |
276 | |
277 | #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS |
278 | /** |
279 | * The bone armature node - used for skeleton conversion |
280 | * you must enable aiProcess_PopulateArmatureData to populate this |
281 | */ |
282 | C_STRUCT aiNode *mArmature; |
283 | |
284 | /** |
285 | * The bone node in the scene - used for skeleton conversion |
286 | * you must enable aiProcess_PopulateArmatureData to populate this |
287 | */ |
288 | C_STRUCT aiNode *mNode; |
289 | |
290 | #endif |
291 | /** |
292 | * The influence weights of this bone, by vertex index. |
293 | */ |
294 | C_STRUCT aiVertexWeight *mWeights; |
295 | |
296 | /** |
297 | * Matrix that transforms from mesh space to bone space in bind pose. |
298 | * |
299 | * This matrix describes the position of the mesh |
300 | * in the local space of this bone when the skeleton was bound. |
301 | * Thus it can be used directly to determine a desired vertex position, |
302 | * given the world-space transform of the bone when animated, |
303 | * and the position of the vertex in mesh space. |
304 | * |
305 | * It is sometimes called an inverse-bind matrix, |
306 | * or inverse bind pose matrix. |
307 | */ |
308 | C_STRUCT aiMatrix4x4 mOffsetMatrix; |
309 | |
310 | #ifdef __cplusplus |
311 | |
312 | /// @brief Default constructor |
313 | aiBone() AI_NO_EXCEPT |
314 | : mName(), |
315 | mNumWeights(0), |
316 | #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS |
317 | mArmature(nullptr), |
318 | mNode(nullptr), |
319 | #endif |
320 | mWeights(nullptr), |
321 | mOffsetMatrix() { |
322 | // empty |
323 | } |
324 | |
325 | /// @brief Copy constructor |
326 | aiBone(const aiBone &other) : |
327 | mName(other.mName), |
328 | mNumWeights(other.mNumWeights), |
329 | #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS |
330 | mArmature(nullptr), |
331 | mNode(nullptr), |
332 | #endif |
333 | mWeights(nullptr), |
334 | mOffsetMatrix(other.mOffsetMatrix) { |
335 | copyVertexWeights(other); |
336 | } |
337 | |
338 | void copyVertexWeights( const aiBone &other ) { |
339 | if (other.mWeights == nullptr || other.mNumWeights == 0) { |
340 | mWeights = nullptr; |
341 | mNumWeights = 0; |
342 | return; |
343 | } |
344 | |
345 | mNumWeights = other.mNumWeights; |
346 | if (mWeights) { |
347 | delete[] mWeights; |
348 | } |
349 | |
350 | mWeights = new aiVertexWeight[mNumWeights]; |
351 | ::memcpy(dest: mWeights, src: other.mWeights, n: mNumWeights * sizeof(aiVertexWeight)); |
352 | } |
353 | |
354 | //! @brief Assignment operator |
355 | aiBone &operator = (const aiBone &other) { |
356 | if (this == &other) { |
357 | return *this; |
358 | } |
359 | |
360 | mName = other.mName; |
361 | mNumWeights = other.mNumWeights; |
362 | mOffsetMatrix = other.mOffsetMatrix; |
363 | copyVertexWeights(other); |
364 | |
365 | return *this; |
366 | } |
367 | |
368 | /// @brief Compare operator. |
369 | bool operator==(const aiBone &rhs) const { |
370 | if (mName != rhs.mName || mNumWeights != rhs.mNumWeights ) { |
371 | return false; |
372 | } |
373 | |
374 | for (size_t i = 0; i < mNumWeights; ++i) { |
375 | if (mWeights[i] != rhs.mWeights[i]) { |
376 | return false; |
377 | } |
378 | } |
379 | |
380 | return true; |
381 | } |
382 | //! @brief Destructor - deletes the array of vertex weights |
383 | ~aiBone() { |
384 | delete[] mWeights; |
385 | } |
386 | #endif // __cplusplus |
387 | }; |
388 | |
389 | // --------------------------------------------------------------------------- |
390 | /** @brief Enumerates the types of geometric primitives supported by Assimp. |
391 | * |
392 | * @see aiFace Face data structure |
393 | * @see aiProcess_SortByPType Per-primitive sorting of meshes |
394 | * @see aiProcess_Triangulate Automatic triangulation |
395 | * @see AI_CONFIG_PP_SBP_REMOVE Removal of specific primitive types. |
396 | */ |
397 | enum aiPrimitiveType { |
398 | /** |
399 | * @brief A point primitive. |
400 | * |
401 | * This is just a single vertex in the virtual world, |
402 | * #aiFace contains just one index for such a primitive. |
403 | */ |
404 | aiPrimitiveType_POINT = 0x1, |
405 | |
406 | /** |
407 | * @brief A line primitive. |
408 | * |
409 | * This is a line defined through a start and an end position. |
410 | * #aiFace contains exactly two indices for such a primitive. |
411 | */ |
412 | aiPrimitiveType_LINE = 0x2, |
413 | |
414 | /** |
415 | * @brief A triangular primitive. |
416 | * |
417 | * A triangle consists of three indices. |
418 | */ |
419 | aiPrimitiveType_TRIANGLE = 0x4, |
420 | |
421 | /** |
422 | * @brief A higher-level polygon with more than 3 edges. |
423 | * |
424 | * A triangle is a polygon, but polygon in this context means |
425 | * "all polygons that are not triangles". The "Triangulate"-Step |
426 | * is provided for your convenience, it splits all polygons in |
427 | * triangles (which are much easier to handle). |
428 | */ |
429 | aiPrimitiveType_POLYGON = 0x8, |
430 | |
431 | /** |
432 | * @brief A flag to determine whether this triangles only mesh is NGON encoded. |
433 | * |
434 | * NGON encoding is a special encoding that tells whether 2 or more consecutive triangles |
435 | * should be considered as a triangle fan. This is identified by looking at the first vertex index. |
436 | * 2 consecutive triangles with the same 1st vertex index are part of the same |
437 | * NGON. |
438 | * |
439 | * At the moment, only quads (concave or convex) are supported, meaning that polygons are 'seen' as |
440 | * triangles, as usual after a triangulation pass. |
441 | * |
442 | * To get an NGON encoded mesh, please use the aiProcess_Triangulate post process. |
443 | * |
444 | * @see aiProcess_Triangulate |
445 | * @link https://github.com/KhronosGroup/glTF/pull/1620 |
446 | */ |
447 | aiPrimitiveType_NGONEncodingFlag = 0x10, |
448 | |
449 | /** |
450 | * This value is not used. It is just here to force the |
451 | * compiler to map this enum to a 32 Bit integer. |
452 | */ |
453 | #ifndef SWIG |
454 | _aiPrimitiveType_Force32Bit = INT_MAX |
455 | #endif |
456 | }; //! enum aiPrimitiveType |
457 | |
458 | // Get the #aiPrimitiveType flag for a specific number of face indices |
459 | #define AI_PRIMITIVE_TYPE_FOR_N_INDICES(n) \ |
460 | ((n) > 3 ? aiPrimitiveType_POLYGON : (aiPrimitiveType)(1u << ((n)-1))) |
461 | |
462 | // --------------------------------------------------------------------------- |
463 | /** @brief An AnimMesh is an attachment to an #aiMesh stores per-vertex |
464 | * animations for a particular frame. |
465 | * |
466 | * You may think of an #aiAnimMesh as a `patch` for the host mesh, which |
467 | * replaces only certain vertex data streams at a particular time. |
468 | * Each mesh stores n attached attached meshes (#aiMesh::mAnimMeshes). |
469 | * The actual relationship between the time line and anim meshes is |
470 | * established by #aiMeshAnim, which references singular mesh attachments |
471 | * by their ID and binds them to a time offset. |
472 | */ |
473 | struct aiAnimMesh { |
474 | /**Anim Mesh name */ |
475 | C_STRUCT aiString mName; |
476 | |
477 | /** Replacement for aiMesh::mVertices. If this array is non-nullptr, |
478 | * it *must* contain mNumVertices entries. The corresponding |
479 | * array in the host mesh must be non-nullptr as well - animation |
480 | * meshes may neither add or nor remove vertex components (if |
481 | * a replacement array is nullptr and the corresponding source |
482 | * array is not, the source data is taken instead)*/ |
483 | C_STRUCT aiVector3D *mVertices; |
484 | |
485 | /** Replacement for aiMesh::mNormals. */ |
486 | C_STRUCT aiVector3D *mNormals; |
487 | |
488 | /** Replacement for aiMesh::mTangents. */ |
489 | C_STRUCT aiVector3D *mTangents; |
490 | |
491 | /** Replacement for aiMesh::mBitangents. */ |
492 | C_STRUCT aiVector3D *mBitangents; |
493 | |
494 | /** Replacement for aiMesh::mColors */ |
495 | C_STRUCT aiColor4D *mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; |
496 | |
497 | /** Replacement for aiMesh::mTextureCoords */ |
498 | C_STRUCT aiVector3D *mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; |
499 | |
500 | /** The number of vertices in the aiAnimMesh, and thus the length of all |
501 | * the member arrays. |
502 | * |
503 | * This has always the same value as the mNumVertices property in the |
504 | * corresponding aiMesh. It is duplicated here merely to make the length |
505 | * of the member arrays accessible even if the aiMesh is not known, e.g. |
506 | * from language bindings. |
507 | */ |
508 | unsigned int mNumVertices; |
509 | |
510 | /** |
511 | * Weight of the AnimMesh. |
512 | */ |
513 | float mWeight; |
514 | |
515 | #ifdef __cplusplus |
516 | /// @brief The class constructor. |
517 | aiAnimMesh() AI_NO_EXCEPT : |
518 | mVertices(nullptr), |
519 | mNormals(nullptr), |
520 | mTangents(nullptr), |
521 | mBitangents(nullptr), |
522 | mColors {nullptr}, |
523 | mTextureCoords{nullptr}, |
524 | mNumVertices(0), |
525 | mWeight(0.0f) { |
526 | // empty |
527 | } |
528 | |
529 | /// @brief The class destructor. |
530 | ~aiAnimMesh() { |
531 | delete[] mVertices; |
532 | delete[] mNormals; |
533 | delete[] mTangents; |
534 | delete[] mBitangents; |
535 | for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { |
536 | delete[] mTextureCoords[a]; |
537 | } |
538 | for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { |
539 | delete[] mColors[a]; |
540 | } |
541 | } |
542 | |
543 | /** |
544 | * @brief Check whether the anim-mesh overrides the vertex positions |
545 | * of its host mesh. |
546 | * @return true if positions are stored, false if not. |
547 | */ |
548 | bool HasPositions() const { |
549 | return mVertices != nullptr; |
550 | } |
551 | |
552 | /** |
553 | * @brief Check whether the anim-mesh overrides the vertex normals |
554 | * of its host mesh |
555 | * @return true if normals are stored, false if not. |
556 | */ |
557 | bool HasNormals() const { |
558 | return mNormals != nullptr; |
559 | } |
560 | |
561 | /** |
562 | * @brief Check whether the anim-mesh overrides the vertex tangents |
563 | * and bitangents of its host mesh. As for aiMesh, |
564 | * tangents and bitangents always go together. |
565 | * @return true if tangents and bi-tangents are stored, false if not. |
566 | */ |
567 | bool HasTangentsAndBitangents() const { |
568 | return mTangents != nullptr; |
569 | } |
570 | |
571 | /** |
572 | * @brief Check whether the anim mesh overrides a particular |
573 | * set of vertex colors on his host mesh. |
574 | * @param pIndex 0<index<AI_MAX_NUMBER_OF_COLOR_SETS |
575 | * @return true if vertex colors are stored, false if not. |
576 | */ |
577 | |
578 | bool HasVertexColors(unsigned int pIndex) const { |
579 | return pIndex >= AI_MAX_NUMBER_OF_COLOR_SETS ? false : mColors[pIndex] != nullptr; |
580 | } |
581 | |
582 | /** |
583 | * @brief Check whether the anim mesh overrides a particular |
584 | * set of texture coordinates on his host mesh. |
585 | * @param pIndex 0<index<AI_MAX_NUMBER_OF_TEXTURECOORDS |
586 | * @return true if texture coordinates are stored, false if not. |
587 | */ |
588 | bool HasTextureCoords(unsigned int pIndex) const { |
589 | return pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? false : mTextureCoords[pIndex] != nullptr; |
590 | } |
591 | |
592 | #endif |
593 | }; |
594 | |
595 | // --------------------------------------------------------------------------- |
596 | /** @brief Enumerates the methods of mesh morphing supported by Assimp. |
597 | */ |
598 | enum aiMorphingMethod { |
599 | /** Morphing method to be determined */ |
600 | aiMorphingMethod_UNKNOWN = 0x0, |
601 | |
602 | /** Interpolation between morph targets */ |
603 | aiMorphingMethod_VERTEX_BLEND = 0x1, |
604 | |
605 | /** Normalized morphing between morph targets */ |
606 | aiMorphingMethod_MORPH_NORMALIZED = 0x2, |
607 | |
608 | /** Relative morphing between morph targets */ |
609 | aiMorphingMethod_MORPH_RELATIVE = 0x3, |
610 | |
611 | /** This value is not used. It is just here to force the |
612 | * compiler to map this enum to a 32 Bit integer. |
613 | */ |
614 | #ifndef SWIG |
615 | _aiMorphingMethod_Force32Bit = INT_MAX |
616 | #endif |
617 | }; //! enum aiMorphingMethod |
618 | |
619 | // --------------------------------------------------------------------------- |
620 | /** @brief A mesh represents a geometry or model with a single material. |
621 | * |
622 | * It usually consists of a number of vertices and a series of primitives/faces |
623 | * referencing the vertices. In addition there might be a series of bones, each |
624 | * of them addressing a number of vertices with a certain weight. Vertex data |
625 | * is presented in channels with each channel containing a single per-vertex |
626 | * information such as a set of texture coordinates or a normal vector. |
627 | * If a data pointer is non-null, the corresponding data stream is present. |
628 | * From C++-programs you can also use the comfort functions Has*() to |
629 | * test for the presence of various data streams. |
630 | * |
631 | * A Mesh uses only a single material which is referenced by a material ID. |
632 | * @note The mPositions member is usually not optional. However, vertex positions |
633 | * *could* be missing if the #AI_SCENE_FLAGS_INCOMPLETE flag is set in |
634 | * @code |
635 | * aiScene::mFlags |
636 | * @endcode |
637 | */ |
638 | struct aiMesh { |
639 | /** |
640 | * Bitwise combination of the members of the #aiPrimitiveType enum. |
641 | * This specifies which types of primitives are present in the mesh. |
642 | * The "SortByPrimitiveType"-Step can be used to make sure the |
643 | * output meshes consist of one primitive type each. |
644 | */ |
645 | unsigned int mPrimitiveTypes; |
646 | |
647 | /** |
648 | * The number of vertices in this mesh. |
649 | * This is also the size of all of the per-vertex data arrays. |
650 | * The maximum value for this member is #AI_MAX_VERTICES. |
651 | */ |
652 | unsigned int mNumVertices; |
653 | |
654 | /** |
655 | * The number of primitives (triangles, polygons, lines) in this mesh. |
656 | * This is also the size of the mFaces array. |
657 | * The maximum value for this member is #AI_MAX_FACES. |
658 | */ |
659 | unsigned int mNumFaces; |
660 | |
661 | /** |
662 | * @brief Vertex positions. |
663 | * |
664 | * This array is always present in a mesh. The array is |
665 | * mNumVertices in size. |
666 | */ |
667 | C_STRUCT aiVector3D *mVertices; |
668 | |
669 | /** |
670 | * @brief Vertex normals. |
671 | * |
672 | * The array contains normalized vectors, nullptr if not present. |
673 | * The array is mNumVertices in size. Normals are undefined for |
674 | * point and line primitives. A mesh consisting of points and |
675 | * lines only may not have normal vectors. Meshes with mixed |
676 | * primitive types (i.e. lines and triangles) may have normals, |
677 | * but the normals for vertices that are only referenced by |
678 | * point or line primitives are undefined and set to QNaN (WARN: |
679 | * qNaN compares to inequal to *everything*, even to qNaN itself. |
680 | * Using code like this to check whether a field is qnan is: |
681 | * @code |
682 | * #define IS_QNAN(f) (f != f) |
683 | * @endcode |
684 | * still dangerous because even 1.f == 1.f could evaluate to false! ( |
685 | * remember the subtleties of IEEE754 artithmetics). Use stuff like |
686 | * @c fpclassify instead. |
687 | * @note Normal vectors computed by Assimp are always unit-length. |
688 | * However, this needn't apply for normals that have been taken |
689 | * directly from the model file. |
690 | */ |
691 | C_STRUCT aiVector3D *mNormals; |
692 | |
693 | /** |
694 | * @brief Vertex tangents. |
695 | * |
696 | * The tangent of a vertex points in the direction of the positive |
697 | * X texture axis. The array contains normalized vectors, nullptr if |
698 | * not present. The array is mNumVertices in size. A mesh consisting |
699 | * of points and lines only may not have normal vectors. Meshes with |
700 | * mixed primitive types (i.e. lines and triangles) may have |
701 | * normals, but the normals for vertices that are only referenced by |
702 | * point or line primitives are undefined and set to qNaN. See |
703 | * the #mNormals member for a detailed discussion of qNaNs. |
704 | * @note If the mesh contains tangents, it automatically also |
705 | * contains bitangents. |
706 | */ |
707 | C_STRUCT aiVector3D *mTangents; |
708 | |
709 | /** |
710 | * @brief Vertex bitangents. |
711 | * |
712 | * The bitangent of a vertex points in the direction of the positive |
713 | * Y texture axis. The array contains normalized vectors, nullptr if not |
714 | * present. The array is mNumVertices in size. |
715 | * @note If the mesh contains tangents, it automatically also contains |
716 | * bitangents. |
717 | */ |
718 | C_STRUCT aiVector3D *mBitangents; |
719 | |
720 | /** |
721 | * @brief Vertex color sets. |
722 | * |
723 | * A mesh may contain 0 to #AI_MAX_NUMBER_OF_COLOR_SETS vertex |
724 | * colors per vertex. nullptr if not present. Each array is |
725 | * mNumVertices in size if present. |
726 | */ |
727 | C_STRUCT aiColor4D *mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; |
728 | |
729 | /** |
730 | * @brief Vertex texture coordinates, also known as UV channels. |
731 | * |
732 | * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS channels per |
733 | * vertex. Used and unused (nullptr) channels may go in any order. |
734 | * The array is mNumVertices in size. |
735 | */ |
736 | C_STRUCT aiVector3D *mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; |
737 | |
738 | /** |
739 | * @brief Specifies the number of components for a given UV channel. |
740 | * |
741 | * Up to three channels are supported (UVW, for accessing volume |
742 | * or cube maps). If the value is 2 for a given channel n, the |
743 | * component p.z of mTextureCoords[n][p] is set to 0.0f. |
744 | * If the value is 1 for a given channel, p.y is set to 0.0f, too. |
745 | * @note 4D coordinates are not supported |
746 | */ |
747 | unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; |
748 | |
749 | /** |
750 | * @brief The faces the mesh is constructed from. |
751 | * |
752 | * Each face refers to a number of vertices by their indices. |
753 | * This array is always present in a mesh, its size is given |
754 | * in mNumFaces. If the #AI_SCENE_FLAGS_NON_VERBOSE_FORMAT |
755 | * is NOT set each face references an unique set of vertices. |
756 | */ |
757 | C_STRUCT aiFace *mFaces; |
758 | |
759 | /** |
760 | * The number of bones this mesh contains. Can be 0, in which case the mBones array is nullptr. |
761 | */ |
762 | unsigned int mNumBones; |
763 | |
764 | /** |
765 | * @brief The bones of this mesh. |
766 | * |
767 | * A bone consists of a name by which it can be found in the |
768 | * frame hierarchy and a set of vertex weights. |
769 | */ |
770 | C_STRUCT aiBone **mBones; |
771 | |
772 | /** |
773 | * @brief The material used by this mesh. |
774 | * |
775 | * A mesh uses only a single material. If an imported model uses |
776 | * multiple materials, the import splits up the mesh. Use this value |
777 | * as index into the scene's material list. |
778 | */ |
779 | unsigned int mMaterialIndex; |
780 | |
781 | /** |
782 | * Name of the mesh. Meshes can be named, but this is not a |
783 | * requirement and leaving this field empty is totally fine. |
784 | * There are mainly three uses for mesh names: |
785 | * - some formats name nodes and meshes independently. |
786 | * - importers tend to split meshes up to meet the |
787 | * one-material-per-mesh requirement. Assigning |
788 | * the same (dummy) name to each of the result meshes |
789 | * aids the caller at recovering the original mesh |
790 | * partitioning. |
791 | * - Vertex animations refer to meshes by their names. |
792 | */ |
793 | C_STRUCT aiString mName; |
794 | |
795 | /** |
796 | * The number of attachment meshes. |
797 | * Currently known to work with loaders: |
798 | * - Collada |
799 | * - gltf |
800 | */ |
801 | unsigned int mNumAnimMeshes; |
802 | |
803 | /** |
804 | * Attachment meshes for this mesh, for vertex-based animation. |
805 | * Attachment meshes carry replacement data for some of the |
806 | * mesh'es vertex components (usually positions, normals). |
807 | * Currently known to work with loaders: |
808 | * - Collada |
809 | * - gltf |
810 | */ |
811 | C_STRUCT aiAnimMesh **mAnimMeshes; |
812 | |
813 | /** |
814 | * Method of morphing when anim-meshes are specified. |
815 | * @see aiMorphingMethod to learn more about the provided morphing targets. |
816 | */ |
817 | enum aiMorphingMethod mMethod; |
818 | |
819 | /** |
820 | * The bounding box. |
821 | */ |
822 | C_STRUCT aiAABB mAABB; |
823 | |
824 | /** |
825 | * Vertex UV stream names. Pointer to array of size AI_MAX_NUMBER_OF_TEXTURECOORDS |
826 | */ |
827 | C_STRUCT aiString **mTextureCoordsNames; |
828 | |
829 | #ifdef __cplusplus |
830 | |
831 | //! The default class constructor. |
832 | aiMesh() AI_NO_EXCEPT |
833 | : mPrimitiveTypes(0), |
834 | mNumVertices(0), |
835 | mNumFaces(0), |
836 | mVertices(nullptr), |
837 | mNormals(nullptr), |
838 | mTangents(nullptr), |
839 | mBitangents(nullptr), |
840 | mColors{nullptr}, |
841 | mTextureCoords{nullptr}, |
842 | mNumUVComponents{0}, |
843 | mFaces(nullptr), |
844 | mNumBones(0), |
845 | mBones(nullptr), |
846 | mMaterialIndex(0), |
847 | mNumAnimMeshes(0), |
848 | mAnimMeshes(nullptr), |
849 | mMethod(aiMorphingMethod_UNKNOWN), |
850 | mAABB(), |
851 | mTextureCoordsNames(nullptr) { |
852 | // empty |
853 | } |
854 | |
855 | //! @brief The class destructor. |
856 | ~aiMesh() { |
857 | delete[] mVertices; |
858 | delete[] mNormals; |
859 | delete[] mTangents; |
860 | delete[] mBitangents; |
861 | for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { |
862 | delete[] mTextureCoords[a]; |
863 | } |
864 | |
865 | if (mTextureCoordsNames) { |
866 | for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { |
867 | delete mTextureCoordsNames[a]; |
868 | } |
869 | delete[] mTextureCoordsNames; |
870 | } |
871 | |
872 | for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { |
873 | delete[] mColors[a]; |
874 | } |
875 | |
876 | // DO NOT REMOVE THIS ADDITIONAL CHECK |
877 | if (mNumBones && mBones) { |
878 | std::unordered_set<const aiBone *> bones; |
879 | for (unsigned int a = 0; a < mNumBones; a++) { |
880 | if (mBones[a]) { |
881 | bones.insert(x: mBones[a]); |
882 | } |
883 | } |
884 | for (const aiBone *bone: bones) { |
885 | delete bone; |
886 | } |
887 | delete[] mBones; |
888 | } |
889 | |
890 | if (mNumAnimMeshes && mAnimMeshes) { |
891 | for (unsigned int a = 0; a < mNumAnimMeshes; a++) { |
892 | delete mAnimMeshes[a]; |
893 | } |
894 | delete[] mAnimMeshes; |
895 | } |
896 | |
897 | delete[] mFaces; |
898 | } |
899 | |
900 | //! @brief Check whether the mesh contains positions. Provided no special |
901 | //! scene flags are set, this will always be true |
902 | //! @return true, if positions are stored, false if not. |
903 | bool HasPositions() const { |
904 | return mVertices != nullptr && mNumVertices > 0; |
905 | } |
906 | |
907 | //! @brief Check whether the mesh contains faces. If no special scene flags |
908 | //! are set this should always return true |
909 | //! @return true, if faces are stored, false if not. |
910 | bool HasFaces() const { |
911 | return mFaces != nullptr && mNumFaces > 0; |
912 | } |
913 | |
914 | //! @brief Check whether the mesh contains normal vectors |
915 | //! @return true, if normals are stored, false if not. |
916 | bool HasNormals() const { |
917 | return mNormals != nullptr && mNumVertices > 0; |
918 | } |
919 | |
920 | //! @brief Check whether the mesh contains tangent and bitangent vectors. |
921 | //! |
922 | //! It is not possible that it contains tangents and no bitangents |
923 | //! (or the other way round). The existence of one of them |
924 | //! implies that the second is there, too. |
925 | //! @return true, if tangents and bi-tangents are stored, false if not. |
926 | bool HasTangentsAndBitangents() const { |
927 | return mTangents != nullptr && mBitangents != nullptr && mNumVertices > 0; |
928 | } |
929 | |
930 | //! @brief Check whether the mesh contains a vertex color set |
931 | //! @param index Index of the vertex color set |
932 | //! @return true, if vertex colors are stored, false if not. |
933 | bool HasVertexColors(unsigned int index) const { |
934 | if (index >= AI_MAX_NUMBER_OF_COLOR_SETS) { |
935 | return false; |
936 | } |
937 | return mColors[index] != nullptr && mNumVertices > 0; |
938 | } |
939 | |
940 | //! @brief Check whether the mesh contains a texture coordinate set |
941 | //! @param index Index of the texture coordinates set |
942 | //! @return true, if texture coordinates are stored, false if not. |
943 | bool HasTextureCoords(unsigned int index) const { |
944 | if (index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { |
945 | return false; |
946 | } |
947 | return (mTextureCoords[index] != nullptr && mNumVertices > 0); |
948 | } |
949 | |
950 | //! @brief Get the number of UV channels the mesh contains. |
951 | //! @return the number of stored uv-channels. |
952 | unsigned int GetNumUVChannels() const { |
953 | unsigned int n(0); |
954 | for (unsigned i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) { |
955 | if (mTextureCoords[i]) { |
956 | ++n; |
957 | } |
958 | } |
959 | |
960 | return n; |
961 | } |
962 | |
963 | //! @brief Get the number of vertex color channels the mesh contains. |
964 | //! @return The number of stored color channels. |
965 | unsigned int GetNumColorChannels() const { |
966 | unsigned int n(0); |
967 | while (n < AI_MAX_NUMBER_OF_COLOR_SETS && mColors[n]) { |
968 | ++n; |
969 | } |
970 | return n; |
971 | } |
972 | |
973 | //! @brief Check whether the mesh contains bones. |
974 | //! @return true, if bones are stored. |
975 | bool HasBones() const { |
976 | return mBones != nullptr && mNumBones > 0; |
977 | } |
978 | |
979 | //! @brief Check whether the mesh contains a texture coordinate set name |
980 | //! @param pIndex Index of the texture coordinates set |
981 | //! @return true, if texture coordinates for the index exists. |
982 | bool HasTextureCoordsName(unsigned int pIndex) const { |
983 | if (mTextureCoordsNames == nullptr || pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { |
984 | return false; |
985 | } |
986 | return mTextureCoordsNames[pIndex] != nullptr; |
987 | } |
988 | |
989 | //! @brief Set a texture coordinate set name |
990 | //! @param pIndex Index of the texture coordinates set |
991 | //! @param texCoordsName name of the texture coordinate set |
992 | void SetTextureCoordsName(unsigned int pIndex, const aiString &texCoordsName) { |
993 | if (pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { |
994 | return; |
995 | } |
996 | |
997 | if (mTextureCoordsNames == nullptr) { |
998 | // Construct and null-init array |
999 | mTextureCoordsNames = new aiString *[AI_MAX_NUMBER_OF_TEXTURECOORDS]; |
1000 | for (size_t i=0; i<AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { |
1001 | mTextureCoordsNames[i] = nullptr; |
1002 | } |
1003 | } |
1004 | |
1005 | if (texCoordsName.length == 0) { |
1006 | delete mTextureCoordsNames[pIndex]; |
1007 | mTextureCoordsNames[pIndex] = nullptr; |
1008 | return; |
1009 | } |
1010 | |
1011 | if (mTextureCoordsNames[pIndex] == nullptr) { |
1012 | mTextureCoordsNames[pIndex] = new aiString(texCoordsName); |
1013 | return; |
1014 | } |
1015 | |
1016 | *mTextureCoordsNames[pIndex] = texCoordsName; |
1017 | } |
1018 | |
1019 | //! @brief Get a texture coordinate set name |
1020 | //! @param pIndex Index of the texture coordinates set |
1021 | //! @return The texture coordinate name. |
1022 | const aiString *GetTextureCoordsName(unsigned int index) const { |
1023 | if (mTextureCoordsNames == nullptr || index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { |
1024 | return nullptr; |
1025 | } |
1026 | |
1027 | return mTextureCoordsNames[index]; |
1028 | } |
1029 | |
1030 | #endif // __cplusplus |
1031 | }; |
1032 | |
1033 | /** |
1034 | * @brief A skeleton bone represents a single bone is a skeleton structure. |
1035 | * |
1036 | * Skeleton-Animations can be represented via a skeleton struct, which describes |
1037 | * a hierarchical tree assembled from skeleton bones. A bone is linked to a mesh. |
1038 | * The bone knows its parent bone. If there is no parent bone the parent id is |
1039 | * marked with -1. |
1040 | * The skeleton-bone stores a pointer to its used armature. If there is no |
1041 | * armature this value if set to nullptr. |
1042 | * A skeleton bone stores its offset-matrix, which is the absolute transformation |
1043 | * for the bone. The bone stores the locale transformation to its parent as well. |
1044 | * You can compute the offset matrix by multiplying the hierarchy like: |
1045 | * Tree: s1 -> s2 -> s3 |
1046 | * Offset-Matrix s3 = locale-s3 * locale-s2 * locale-s1 |
1047 | */ |
1048 | struct aiSkeletonBone { |
1049 | /// The parent bone index, is -1 one if this bone represents the root bone. |
1050 | int mParent; |
1051 | |
1052 | |
1053 | #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS |
1054 | /// @brief The bone armature node - used for skeleton conversion |
1055 | /// you must enable aiProcess_PopulateArmatureData to populate this |
1056 | C_STRUCT aiNode *mArmature; |
1057 | |
1058 | /// @brief The bone node in the scene - used for skeleton conversion |
1059 | /// you must enable aiProcess_PopulateArmatureData to populate this |
1060 | C_STRUCT aiNode *mNode; |
1061 | |
1062 | #endif |
1063 | /// @brief The number of weights |
1064 | unsigned int mNumnWeights; |
1065 | |
1066 | /// The mesh index, which will get influenced by the weight. |
1067 | C_STRUCT aiMesh *mMeshId; |
1068 | |
1069 | /// The influence weights of this bone, by vertex index. |
1070 | C_STRUCT aiVertexWeight *mWeights; |
1071 | |
1072 | /** Matrix that transforms from bone space to mesh space in bind pose. |
1073 | * |
1074 | * This matrix describes the position of the mesh |
1075 | * in the local space of this bone when the skeleton was bound. |
1076 | * Thus it can be used directly to determine a desired vertex position, |
1077 | * given the world-space transform of the bone when animated, |
1078 | * and the position of the vertex in mesh space. |
1079 | * |
1080 | * It is sometimes called an inverse-bind matrix, |
1081 | * or inverse bind pose matrix. |
1082 | */ |
1083 | C_STRUCT aiMatrix4x4 mOffsetMatrix; |
1084 | |
1085 | /// Matrix that transforms the locale bone in bind pose. |
1086 | C_STRUCT aiMatrix4x4 mLocalMatrix; |
1087 | |
1088 | #ifdef __cplusplus |
1089 | /// @brief The class constructor. |
1090 | aiSkeletonBone() : |
1091 | mParent(-1), |
1092 | #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS |
1093 | mArmature(nullptr), |
1094 | mNode(nullptr), |
1095 | #endif |
1096 | mNumnWeights(0), |
1097 | mMeshId(nullptr), |
1098 | mWeights(nullptr), |
1099 | mOffsetMatrix(), |
1100 | mLocalMatrix() { |
1101 | // empty |
1102 | } |
1103 | |
1104 | /// @brief The class constructor with its parent |
1105 | /// @param parent The parent node index. |
1106 | aiSkeletonBone(unsigned int parent) : |
1107 | mParent(parent), |
1108 | #ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS |
1109 | mArmature(nullptr), |
1110 | mNode(nullptr), |
1111 | #endif |
1112 | mNumnWeights(0), |
1113 | mMeshId(nullptr), |
1114 | mWeights(nullptr), |
1115 | mOffsetMatrix(), |
1116 | mLocalMatrix() { |
1117 | // empty |
1118 | } |
1119 | /// @brief The class destructor. |
1120 | ~aiSkeletonBone() { |
1121 | delete[] mWeights; |
1122 | mWeights = nullptr; |
1123 | } |
1124 | #endif // __cplusplus |
1125 | }; |
1126 | /** |
1127 | * @brief A skeleton represents the bone hierarchy of an animation. |
1128 | * |
1129 | * Skeleton animations can be described as a tree of bones: |
1130 | * root |
1131 | * | |
1132 | * node1 |
1133 | * / \ |
1134 | * node3 node4 |
1135 | * If you want to calculate the transformation of node three you need to compute the |
1136 | * transformation hierarchy for the transformation chain of node3: |
1137 | * root->node1->node3 |
1138 | * Each node is represented as a skeleton instance. |
1139 | */ |
1140 | struct aiSkeleton { |
1141 | /** |
1142 | * @brief The name of the skeleton instance. |
1143 | */ |
1144 | C_STRUCT aiString mName; |
1145 | |
1146 | /** |
1147 | * @brief The number of bones in the skeleton. |
1148 | */ |
1149 | unsigned int mNumBones; |
1150 | |
1151 | /** |
1152 | * @brief The bone instance in the skeleton. |
1153 | */ |
1154 | C_STRUCT aiSkeletonBone **mBones; |
1155 | |
1156 | #ifdef __cplusplus |
1157 | /** |
1158 | * @brief The class constructor. |
1159 | */ |
1160 | aiSkeleton() AI_NO_EXCEPT : mName(), mNumBones(0), mBones(nullptr) { |
1161 | // empty |
1162 | } |
1163 | |
1164 | /** |
1165 | * @brief The class destructor. |
1166 | */ |
1167 | ~aiSkeleton() { |
1168 | delete[] mBones; |
1169 | } |
1170 | #endif // __cplusplus |
1171 | }; |
1172 | #ifdef __cplusplus |
1173 | } |
1174 | #endif //! extern "C" |
1175 | |
1176 | #endif // AI_MESH_H_INC |
1177 | |
1178 |
Definitions
- aiFace
- aiFace
- ~aiFace
- aiFace
- operator=
- operator==
- operator!=
- aiVertexWeight
- aiVertexWeight
- aiVertexWeight
- operator==
- operator!=
- aiBone
- aiBone
- aiBone
- copyVertexWeights
- operator =
- operator==
- ~aiBone
- aiPrimitiveType
- aiAnimMesh
- aiAnimMesh
- ~aiAnimMesh
- HasPositions
- HasNormals
- HasTangentsAndBitangents
- HasVertexColors
- HasTextureCoords
- aiMorphingMethod
- aiMesh
- aiMesh
- ~aiMesh
- HasPositions
- HasFaces
- HasNormals
- HasTangentsAndBitangents
- HasVertexColors
- HasTextureCoords
- GetNumUVChannels
- GetNumColorChannels
- HasBones
- HasTextureCoordsName
- SetTextureCoordsName
- GetTextureCoordsName
- aiSkeletonBone
- aiSkeletonBone
- aiSkeletonBone
- ~aiSkeletonBone
- aiSkeleton
- aiSkeleton
Learn Advanced QML with KDAB
Find out more