载入中...
搜索中...
未找到
AnimImporterAssimp.cpp
浏览该文件的文档.
4
5#include "common/Exception.h"
6
7#include <assimp/anim.h>
8#include <assimp/matrix4x4.h>
9#include <assimp/quaternion.h>
10#include <assimp/scene.h>
11#include <assimp/vector3.h>
12
13#include <vector>
14
15namespace eve::animation {
16
17namespace {
18
19void decomposeBind(const aiMatrix4x4 &m, float &px, float &py, float &pz, float &qx, float &qy,
20 float &qz, float &qw, float &sx, float &sy, float &sz) {
21 aiVector3D scaling, position;
22 aiQuaternion rotation;
23 m.Decompose(scaling, rotation, position);
24 px = position.x;
25 py = position.y;
26 pz = position.z;
27 qx = rotation.x;
28 qy = rotation.y;
29 qz = rotation.z;
30 qw = rotation.w;
31 sx = scaling.x;
32 sy = scaling.y;
33 sz = scaling.z;
34}
35
36float ticksToSeconds(const aiAnimation *anim, double ticks) {
37 double tps = anim->mTicksPerSecond;
38 if (tps <= 1e-8) tps = 25.0;
39 return static_cast<float>(ticks / tps);
40}
41
42} // namespace
43
44void AnimImporter::collectBones(const aiNode *node, int parent, AnimSkeleton *skeleton,
45 std::vector<const aiNode *> &order) {
46 if (!node) return;
47 const std::string name = node->mName.C_Str();
48 const std::string boneName = name.empty() ? ("node_" + std::to_string(order.size())) : name;
49 const int id = skeleton->addBone(boneName, parent);
50 order.push_back(node);
51
52 float px, py, pz, qx, qy, qz, qw, sx, sy, sz;
53 decomposeBind(node->mTransformation, px, py, pz, qx, qy, qz, qw, sx, sy, sz);
54 skeleton->setBindPosition(id, px, py, pz);
55 skeleton->setBindRotation(id, qx, qy, qz, qw);
56 skeleton->setBindScale(id, sx, sy, sz);
57
58 for (unsigned i = 0; i < node->mNumChildren; ++i) {
59 collectBones(node->mChildren[i], id, skeleton, order);
60 }
61}
62
64 if (!scene || !scene->mRootNode) {
65 throw Exception("AnimImporter.loadSkeleton: invalid scene");
66 }
67 auto *skeleton = new AnimSkeleton();
68 std::vector<const aiNode *> order;
69 collectBones(scene->mRootNode, -1, skeleton, order);
70 if (skeleton->getBoneCount() == 0) {
71 delete skeleton;
72 throw Exception("AnimImporter.loadSkeleton: no bones");
73 }
74 return skeleton;
75}
76
77AnimClip *AnimImporter::loadClip(const aiScene *scene, const AnimSkeleton *skeleton,
78 int animIndex) {
79 if (!scene || !skeleton) {
80 throw Exception("AnimImporter.loadClip: null scene/skeleton");
81 }
82 if (animIndex < 0 || animIndex >= getAnimationCount(scene)) {
83 throw Exception("AnimImporter.loadClip: invalid anim index %d", animIndex);
84 }
85 const aiAnimation *anim = scene->mAnimations[animIndex];
86 auto *clip = new AnimClip(anim->mName.length ? anim->mName.C_Str() : "anim");
87 clip->setDuration(ticksToSeconds(anim, anim->mDuration));
88 clip->setLoop(true);
89 clip->setSampleRate(30.f);
90
91 for (unsigned c = 0; c < anim->mNumChannels; ++c) {
92 const aiNodeAnim *channel = anim->mChannels[c];
93 if (!channel) continue;
94 const int bone = skeleton->findBone(channel->mNodeName.C_Str());
95 if (bone < 0) continue;
96
97 for (unsigned i = 0; i < channel->mNumPositionKeys; ++i) {
98 const aiVectorKey &k = channel->mPositionKeys[i];
99 clip->addPositionKey(bone, ticksToSeconds(anim, k.mTime), k.mValue.x, k.mValue.y,
100 k.mValue.z);
101 }
102 for (unsigned i = 0; i < channel->mNumRotationKeys; ++i) {
103 const aiQuatKey &k = channel->mRotationKeys[i];
104 clip->addRotationKey(bone, ticksToSeconds(anim, k.mTime), k.mValue.x, k.mValue.y,
105 k.mValue.z, k.mValue.w);
106 }
107 for (unsigned i = 0; i < channel->mNumScalingKeys; ++i) {
108 const aiVectorKey &k = channel->mScalingKeys[i];
109 clip->addScaleKey(bone, ticksToSeconds(anim, k.mTime), k.mValue.x, k.mValue.y,
110 k.mValue.z);
111 }
112 }
113 return clip;
114}
115
116int AnimImporter::getAnimationCount(const aiScene *scene) {
117 if (!scene) return 0;
118 return static_cast<int>(scene->mNumAnimations);
119}
120
121std::string AnimImporter::getAnimationName(const aiScene *scene, int animIndex) {
122 if (!scene || animIndex < 0 || animIndex >= getAnimationCount(scene)) return {};
123 const aiAnimation *a = scene->mAnimations[animIndex];
124 return a->mName.length ? a->mName.C_Str() : std::string("anim") + std::to_string(animIndex);
125}
126
127} // namespace eve::animation
float py
float pz
glm::vec4 clip
std::int32_t c
std::vector< Colorf > px
std::array< float, 4 > rotation
std::array< float, 3 > position
std::uint32_t bone
std::int32_t parent
std::string name
MeleePoint3 a
Definition MeleeHit.cpp:40
std::vector< std::int32_t > order
std::weak_ptr< PrimitiveScene > scene
const RoadNode * node
float m[16]
float qy
float qx
float qw
float qz
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Keyframed skeletal animation clip (local TRS tracks per bone). Script type: AnimClip.
Definition AnimClip.h:145
void setDuration(float seconds)
Sets the duration.
Definition AnimClip.cpp:22
static int getAnimationCount(const aiScene *scene)
Assimp scene helpers (AnimImporterAssimp.cpp; requires model3d).
static AnimClip * loadClip(const aiScene *scene, const AnimSkeleton *skeleton, int animIndex=0)
Load clip by index; maps node-name channels onto skeleton bones.
static std::string getAnimationName(const aiScene *scene, int animIndex)
Returns the animation name.
static AnimSkeleton * loadSkeleton(const aiScene *scene)
Build skeleton from the scene node hierarchy (depth-first).
3D bone hierarchy + bind-pose local TRS for skeletal animation. Independent of ik::Skeleton3D (FABRIK...
int findBone(const std::string &name) const
Finds bone.