From 53bf4f41bd6a509a13303de84fa5f4bab1ac8781 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Mon, 22 Feb 2021 20:03:02 +0200 Subject: [PATCH] first animatable object interface iteration --- CMakeLists.txt | 2 +- animatable.cpp | 13 +++++++ animatable.h | 25 +++++++++++++ animation.cpp | 8 ++-- animation.h | 9 ++--- animationChannel.h | 8 ++-- animationChannelTest.cpp | 4 +- animationController.cpp | 80 ++-------------------------------------- animationController.h | 8 +--- bone.cpp | 41 ++++++++++++++++++++ bone.h | 5 ++- mesh.h | 4 +- node.cpp | 49 +++++++++++++++++++++--- node.h | 11 +++--- skeleton.cpp | 1 - skeleton.h | 6 +-- vbModelReader.cpp | 31 +++++++--------- vbModelReader.h | 3 +- vbModelReaderTest.cpp | 5 ++- 19 files changed, 174 insertions(+), 139 deletions(-) create mode 100644 animatable.cpp create mode 100644 animatable.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 286a67c..a47c3d0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ set(utils util.cpp) set(math quaternion.cpp vector.cpp matrix.cpp ray.cpp) set(render particleEmitter.cpp camera.cpp light.cpp material.cpp mesh.cpp model.cpp node.cpp quad.cpp box.cpp root.cpp shader.cpp texture.cpp) set(model modelReader.cpp assimpModelReader.cpp vbModelReader.cpp) -set(anim animationController.cpp animationChannel.cpp animation.cpp) +set(anim animationController.cpp animationChannel.cpp animation.cpp animatable.cpp) set(armature skeleton.cpp bone.cpp ikSolver.cpp) set(library ${render} ${math} ${model} ${utils} ${gui} ${armature} ${assetManager} ${anim}) diff --git a/animatable.cpp b/animatable.cpp new file mode 100644 index 0000000..31dee57 --- /dev/null +++ b/animatable.cpp @@ -0,0 +1,13 @@ +#include "animatable.h" +#include "animationController.h" + +namespace vb01{ + Animatable::Animatable(AnimationController *controller){ + this->animationController = controller; + } + + void Animatable::update(){ + if(animationController) + animationController->update(); + } +} diff --git a/animatable.h b/animatable.h new file mode 100644 index 0000000..d2bc1d1 --- /dev/null +++ b/animatable.h @@ -0,0 +1,25 @@ +#ifndef ANIMATABLE_H +#define ANIMATABLE_H + +#include "animation.h" + +namespace vb01{ + class AnimationController; + + class Animatable{ + public: + enum Type{NODE, BONE}; + + Animatable(AnimationController*); + void update(); + virtual void animate(float, KeyframeChannel){} + inline AnimationController *getAnimationController(){return animationController;} + inline Type getType(){return type;} + private: + AnimationController *animationController = nullptr; + protected: + Type type; + }; +} + +#endif diff --git a/animation.cpp b/animation.cpp index 7dbd593..1342361 100644 --- a/animation.cpp +++ b/animation.cpp @@ -38,11 +38,11 @@ namespace vb01{ return type; } - KeyframeChannel* Animation::getKeyframeChannel(Node *bone, KeyframeChannelType type){ + KeyframeChannel* Animation::getKeyframeChannel(Animatable *animatable, KeyframeChannelType type){ KeyframeChannel *k = nullptr; for(KeyframeChannel &channel : keyframeChannels) - if(channel.type == type && channel.bone == bone){ + if(channel.type == type && channel.animatable == animatable){ k = &channel; break; } @@ -50,11 +50,11 @@ namespace vb01{ return k; } - vector Animation::getKeyframeChannelsByNode(Node *bone){ + vector Animation::getKeyframeChannelsByAnimatable(Animatable *animatable){ vector channels; for(KeyframeChannel channel : keyframeChannels) - if(channel.bone == bone) + if(channel.animatable == animatable) channels.push_back(channel); return channels; diff --git a/animation.h b/animation.h index b55d045..8e546ae 100644 --- a/animation.h +++ b/animation.h @@ -5,8 +5,7 @@ #include namespace vb01{ - class Bone; - class Node; + class Animatable; class Animation{ public: @@ -33,7 +32,7 @@ namespace vb01{ }; Type type; - Node *bone = nullptr; + Animatable *animatable = nullptr; std::vector keyframes; }; @@ -41,8 +40,8 @@ namespace vb01{ ~Animation(); void update(); static KeyframeChannel::Type getKeyframeChannelType(std::string); - KeyframeChannel* getKeyframeChannel(Node*, KeyframeChannel::Type); - std::vector getKeyframeChannelsByNode(Node*); + KeyframeChannel* getKeyframeChannel(Animatable*, KeyframeChannel::Type); + std::vector getKeyframeChannelsByAnimatable(Animatable*); inline void addKeyframeChannel(KeyframeChannel channel){keyframeChannels.push_back(channel);} inline std::string getName(){return name;} inline const std::vector& getKeyframeChannels(){return keyframeChannels;} diff --git a/animationChannel.h b/animationChannel.h index 13a13f6..a7aa5e3 100644 --- a/animationChannel.h +++ b/animationChannel.h @@ -17,9 +17,9 @@ namespace vb01{ ~AnimationChannel(); void update(); void setAnimationName(std::string name); - inline std::vector getBones(){return bones;} - inline void addBone(Bone *bone){bones.push_back(bone);} - inline void removeAllBones(){bones.clear();} + inline std::vector getAnimatables(){return animatables;} + inline void addAnimatable(Animatable *animatable){animatables.push_back(animatable);} + inline void removeAllBones(){animatables.clear();} inline void setUpdateRate(float updateRate){this->updateRate = updateRate;} inline int getUpdateRate(){return updateRate;} inline int getFirstFrame(){return firstFrame;} @@ -43,7 +43,7 @@ namespace vb01{ int firstFrame = 0, currentFrame = 1, numFrames = 0; bool loop = false, forward = true; std::string animationName; - std::vector bones; + std::vector animatables; friend class AnimationChannelTest; friend class AnimationControllerTest; diff --git a/animationChannelTest.cpp b/animationChannelTest.cpp index 67ec201..228761b 100644 --- a/animationChannelTest.cpp +++ b/animationChannelTest.cpp @@ -22,14 +22,14 @@ namespace vb01{ KeyframeChannel kc; kc.type = KeyframeChannel::Type::POS_X; kc.keyframes = vector({k1, k2}); - kc.bone = bone; + kc.animatable = bone; Animation *anim = new Animation("anim"); anim->addKeyframeChannel(kc); channel = new AnimationChannel(controller); controller->addAnimationChannel(channel); controller->addAnimation(anim); - channel->addBone(bone); + channel->addAnimatable(bone); channel->setAnimationName("anim"); } diff --git a/animationController.cpp b/animationController.cpp index 6ad9d26..885877f 100644 --- a/animationController.cpp +++ b/animationController.cpp @@ -31,91 +31,19 @@ namespace vb01{ } void AnimationController::transform(AnimationChannel *channel){ - vector transformNodes; - if(node) - transformNodes.push_back(node); - for(Bone *channelBone : channel->getBones()) - transformNodes.push_back((Node*)channelBone); - Animation *animation = getAnimation(channel->getAnimationName()); - for(Node *transformNode : transformNodes){ - Vector3 currentPos; - Quaternion currentRot; - Vector3 currentScale; - bool objectNode = node && node->getName() == transformNode->getName(); - if(objectNode){ - currentPos = transformNode->getPosition(); - currentRot = transformNode->getOrientation(); - currentScale = transformNode->getScale(); - } - else{ - Bone *channelBone = (Bone*)transformNode; - currentPos = channelBone->getPosePos(); - currentRot = channelBone->getPoseRot(); - currentScale = channelBone->getPoseScale(); - } - - vector keyframeChannels = animation->getKeyframeChannelsByNode(transformNode); + for(Animatable *animatable : channel->getAnimatables()){ + vector keyframeChannels = animation->getKeyframeChannelsByAnimatable(animatable); for(KeyframeChannel keyframeChannel : keyframeChannels){ Keyframe pastKeyframe = findKeyframe(channel, keyframeChannel, true); Keyframe nextKeyframe = findKeyframe(channel, keyframeChannel, false); int pastFrame = pastKeyframe.frame; int nextFrame = nextKeyframe.frame; - - Keyframe::Interpolation interp = pastKeyframe.interpolation; float ratio = (float)(max(0, channel->getCurrentFrame() - pastFrame)) / (nextFrame - pastFrame); + Keyframe::Interpolation interp = pastKeyframe.interpolation; float value = interpolate(pastKeyframe.value, nextKeyframe.value, interp, ratio); - setFrameValue(value, keyframeChannel.type, currentPos, currentRot, currentScale); + animatable->animate(value, keyframeChannel); } - - if(objectNode){ - transformNode->setPosition(currentPos); - transformNode->setOrientation(currentRot); - transformNode->setScale(currentScale); - } - else{ - Bone *channelBone = (Bone*)transformNode; - channelBone->setPosePos(currentPos); - channelBone->setPoseRot(currentRot); - channelBone->setPoseScale(currentScale); - } - } - } - - void AnimationController::setFrameValue(float value, KeyframeChannelType type, Vector3 ¤tPos, Quaternion ¤tRot, Vector3 ¤tScale){ - switch(type){ - case KeyframeChannel::POS_X: - currentPos.x = value; - break; - case KeyframeChannel::POS_Y: - currentPos.y = value; - break; - case KeyframeChannel::POS_Z: - currentPos.z = value; - break; - case KeyframeChannel::ROT_W: - currentRot.w = value; - break; - case KeyframeChannel::ROT_X: - currentRot.x = value; - break; - case KeyframeChannel::ROT_Y: - currentRot.y = value; - break; - case KeyframeChannel::ROT_Z: - currentRot.z = value; - break; - case KeyframeChannel::SCALE_X: - currentScale.x = value; - break; - case KeyframeChannel::SCALE_Y: - currentScale.y = value; - break; - case KeyframeChannel::SCALE_Z: - currentScale.z = value; - break; - case KeyframeChannel::VALUE: - break; } } diff --git a/animationController.h b/animationController.h index 9da7dc8..500a5b7 100644 --- a/animationController.h +++ b/animationController.h @@ -10,6 +10,7 @@ namespace vb01{ class AnimationChannel; class Vector3; class Quaternion; + class Animatable; class AnimationController{ public: @@ -20,18 +21,11 @@ namespace vb01{ inline std::vector getAnimations(){return animations;} inline void addAnimation(Animation *anim){animations.push_back(anim);} inline void addAnimationChannel(AnimationChannel *channel){channels.push_back(channel);} - inline void setSkeleton(Skeleton *sk){this->skeleton = sk;} - inline void setNode(Node *node){this->node = node;} - inline Skeleton* getSkeleton(){return skeleton;} - inline Node* getNode(){return node;} private: - Skeleton *skeleton = nullptr; - Node *node = nullptr; std::vector animations; std::vector channels; void transform(AnimationChannel*); - void setFrameValue(float, KeyframeChannelType, Vector3&, Quaternion&, Vector3&); Keyframe findKeyframe(AnimationChannel*, KeyframeChannel, bool); float interpolate(float, float, Keyframe::Interpolation, float); protected: diff --git a/bone.cpp b/bone.cpp index f246a04..40ec8b0 100644 --- a/bone.cpp +++ b/bone.cpp @@ -7,6 +7,7 @@ namespace vb01{ Bone::Bone(string name, float length, Vector3 pos, Quaternion rot, Vector3 scale) : Node(pos, rot, scale, name){ this->name = name; this->length = length; + Animatable::type = Animatable::BONE; } void Bone::lookAt(Vector3 newDir, Vector3 newUp){ @@ -77,4 +78,44 @@ namespace vb01{ this->poseScale = s; //setScale(restScale+poseScale); } + + void Bone::animate(float value, KeyframeChannel keyframeChannel){ + Vector3 newPos = getPosePos(), newScale = getPoseScale(); + Quaternion newRot = getPoseRot(); + switch(keyframeChannel.type){ + case KeyframeChannel::POS_X: + newPos.x = value; + break; + case KeyframeChannel::POS_Y: + newPos.y = value; + break; + case KeyframeChannel::POS_Z: + newPos.z = value; + break; + case KeyframeChannel::ROT_W: + newRot.w = value; + break; + case KeyframeChannel::ROT_X: + newRot.x = value; + break; + case KeyframeChannel::ROT_Y: + newRot.y = value; + break; + case KeyframeChannel::ROT_Z: + newRot.z = value; + break; + case KeyframeChannel::SCALE_X: + newScale.x = value; + break; + case KeyframeChannel::SCALE_Y: + newScale.y = value; + break; + case KeyframeChannel::SCALE_Z: + newScale.z = value; + break; + } + setPosePos(newPos); + setPoseRot(newRot); + setPoseScale(newScale); + } } diff --git a/bone.h b/bone.h index eb1845e..44251cf 100644 --- a/bone.h +++ b/bone.h @@ -1,8 +1,8 @@ #ifndef BONE_H #define BONE_H -#include"node.h" -#include +#include "node.h" +#include namespace vb01{ class Skeleton; @@ -34,6 +34,7 @@ namespace vb01{ inline Vector3 getPoseScale(){return poseScale;} private: void updateBoneInfo(); + void animate(float, KeyframeChannel); float length; Bone *ikTarget = nullptr; diff --git a/mesh.h b/mesh.h index 22d87c7..36f6c86 100755 --- a/mesh.h +++ b/mesh.h @@ -24,7 +24,7 @@ namespace vb01{ Vector3 shapeKeyOffsets[100]; }; - Mesh(Vertex*, unsigned int*, int, std::string *vg = nullptr, int = 0, std::string *sk = nullptr, int = 0, std::string = ""); + Mesh(Vertex*, u32*, int, std::string *vg = nullptr, int = 0, std::string *sk = nullptr, int = 0, std::string = ""); ~Mesh(); void construct(); virtual void update(); @@ -45,7 +45,7 @@ namespace vb01{ inline Skeleton* getSkeleton(){return skeleton;} inline std::string* getVertexGroups(){return vertexGroups;} inline int getNumVertexGroups(){return numVertexGroups;} - inline unsigned int* getIndices(){return indices;} + inline u32* getIndices(){return indices;} private: void initMesh(); void initFramebuffer(); diff --git a/node.cpp b/node.cpp index 6dbdc78..4b6f021 100755 --- a/node.cpp +++ b/node.cpp @@ -15,14 +15,12 @@ using namespace std; using namespace glm; namespace vb01{ - Node::Node(Vector3 pos, Quaternion orientation, Vector3 scale, string name, AnimationController *controller){ + Node::Node(Vector3 pos, Quaternion orientation, Vector3 scale, string name, AnimationController *controller) : Animatable(controller){ this->pos = pos; this->scale = scale; this->orientation = orientation; this->name = name; - this->controller = controller; - if(this->controller) - this->controller->setNode(this); + Animatable::type = Animatable::NODE; globalAxis[0] = Vector3::VEC_I; globalAxis[1] = Vector3::VEC_J; @@ -56,8 +54,7 @@ namespace vb01{ c->update(); for(ParticleEmitter *p : emitters) p->update(); - if(controller) - controller->update(); + Animatable::update(); } } @@ -312,4 +309,44 @@ namespace vb01{ this->orientation = q; updateAxis(); } + + void Node::animate(float value, KeyframeChannel keyframeChannel){ + Vector3 newPos = pos, newScale = scale; + Quaternion newRot = orientation; + switch(keyframeChannel.type){ + case KeyframeChannel::POS_X: + newPos.x = value; + break; + case KeyframeChannel::POS_Y: + newPos.y = value; + break; + case KeyframeChannel::POS_Z: + newPos.z = value; + break; + case KeyframeChannel::ROT_W: + newRot.w = value; + break; + case KeyframeChannel::ROT_X: + newRot.x = value; + break; + case KeyframeChannel::ROT_Y: + newRot.y = value; + break; + case KeyframeChannel::ROT_Z: + newRot.z = value; + break; + case KeyframeChannel::SCALE_X: + newScale.x = value; + break; + case KeyframeChannel::SCALE_Y: + newScale.y = value; + break; + case KeyframeChannel::SCALE_Z: + newScale.z = value; + break; + } + setPosition(newPos); + setOrientation(newRot); + setScale(newScale); + } } diff --git a/node.h b/node.h index cd651a5..6352da3 100755 --- a/node.h +++ b/node.h @@ -4,6 +4,7 @@ #include "quaternion.h" #include "vector.h" #include "root.h" +#include "animatable.h" #include #include @@ -16,7 +17,7 @@ namespace vb01{ class Text; class AnimationController; - class Node{ + class Node : public Animatable{ public: struct Transform{ Vector3 position = Vector3::VEC_ZERO, scale = Vector3::VEC_IJK; @@ -65,14 +66,14 @@ namespace vb01{ inline bool isVisible(){return visible;} inline std::string getName(){return name;} inline void setVisible(bool v){this->visible = v;} - inline AnimationController* getAnimationController(){return controller;} private: void adjustUp(Vector3); void adjustDir(Vector3); - Quaternion adjustRot(std::vector, Quaternion, bool); - AnimationController *controller = nullptr; - protected: void updateShaders(); + + Quaternion adjustRot(std::vector, Quaternion, bool); + protected: + virtual void animate(float, KeyframeChannel); bool visible = true; Vector3 pos, scale, globalAxis[3]; diff --git a/skeleton.cpp b/skeleton.cpp index 93854f2..d7c3114 100644 --- a/skeleton.cpp +++ b/skeleton.cpp @@ -13,7 +13,6 @@ namespace vb01{ Skeleton::Skeleton(AnimationController *controller, string name){ this->name = name; this->controller = controller; - this->controller->setSkeleton(this); } void Skeleton::update(){ diff --git a/skeleton.h b/skeleton.h index 136604d..f3afe57 100644 --- a/skeleton.h +++ b/skeleton.h @@ -1,9 +1,9 @@ #ifndef SKELETON_H #define SKELETON_H -#include -#include -#include"bone.h" +#include +#include +#include "bone.h" namespace vb01{ class Animation; diff --git a/vbModelReader.cpp b/vbModelReader.cpp index 67bb9f8..3b71fc7 100644 --- a/vbModelReader.cpp +++ b/vbModelReader.cpp @@ -150,8 +150,6 @@ namespace vb01{ yAxis.z = -yAxis.z; swap(zAxis.y, zAxis.z); zAxis.z = -zAxis.z; - /* - */ } else pos = pos + Vector3(0, ((Bone*)parent)->getLength(), 0); @@ -172,33 +170,27 @@ namespace vb01{ } } - void VbModelReader::readAnimations(AnimationController *controller, vector &skeletonData, int numAnimations){ + void VbModelReader::readAnimations(Animatable *animatable, vector &animationData, int numAnimations){ int animStartLine = 0; for(int i = 0; i < numAnimations; i++){ - string animLine = skeletonData[animStartLine]; + string animLine = animationData[animStartLine]; currentAnim = animLine.substr(animLine.find_first_of(':') + 2); - string groupsLine = skeletonData[animStartLine + 1]; + string groupsLine = animationData[animStartLine + 1]; Animation *animation = new Animation(currentAnim); + AnimationController *controller = (animatable ? animatable->getAnimationController() : currentSkeleton->getAnimationController()); controller->addAnimation(animation); int numKeyframeGroups = atoi(groupsLine.substr(groupsLine.find_first_of(':') + 2).c_str()); int keyframeGroupStartLine = animStartLine + 2; for(int j = 0; j < numKeyframeGroups; j++){ string dataLine[2]; - getLineData(skeletonData[keyframeGroupStartLine], dataLine, 2); - - string nodeName = dataLine[0]; - Node *transformNode = nullptr; - if(controller->getSkeleton()) - transformNode = (Node*)controller->getSkeleton()->getBone(nodeName); - if(!transformNode) - transformNode = controller->getNode(); + getLineData(animationData[keyframeGroupStartLine], dataLine, 2); int numKeyframeChannels = atoi(dataLine[1].c_str()); string channelData[2 * numKeyframeChannels]; - getLineData(skeletonData[keyframeGroupStartLine], channelData, 2 * numKeyframeChannels, 2); + getLineData(animationData[keyframeGroupStartLine], channelData, 2 * numKeyframeChannels, 2); vector keyframeChannels; int numTypeKeyframes[numKeyframeChannels]; @@ -209,7 +201,7 @@ namespace vb01{ keyframeChannel.type = Animation::getKeyframeChannelType(channelData[2 * k]); numTypeKeyframes[k] = atoi(channelData[2 * k + 1].c_str()); numKeyframes += numTypeKeyframes[k]; - keyframeChannel.bone = transformNode; + keyframeChannel.animatable = (animatable ? animatable : currentSkeleton->getBone(dataLine[0])); keyframeChannels.push_back(keyframeChannel); } @@ -217,7 +209,7 @@ namespace vb01{ int keyframeStartLine = keyframeGroupStartLine + 1; int currentChannel = 0, numCurrentTypeKeyframes = 0; for(int k = 0; k < numKeyframes; k++){ - string keyframeLine = skeletonData[keyframeStartLine + k]; + string keyframeLine = animationData[keyframeStartLine + k]; string keyframeData[9]; getLineData(keyframeLine, keyframeData, 9); @@ -258,15 +250,18 @@ namespace vb01{ AnimationController *controller = new AnimationController(); Skeleton *skeleton = new Skeleton(controller, name); + currentSkeleton = skeleton; vector skeletonSubData = vector(skeletonData.begin() + boneStartLine, skeletonData.begin() + boneStartLine + numBones); createBones(skeleton, skeletonSubData); skeletonSubData.clear(); skeletonSubData = vector(skeletonData.begin() + (boneStartLine + numBones + 1), skeletonData.end()); - readAnimations(controller, skeletonSubData, numAnimations); + readAnimations(nullptr, skeletonSubData, numAnimations); skeletonSubData.clear(); + currentSkeleton = nullptr; + return skeleton; } @@ -441,7 +436,7 @@ namespace vb01{ int numAnimLineId = shapeKeyStartLine + numShapes * (1 + numVertices); int numAnimations = atoi(meshData[numAnimLineId].substr(meshData[numAnimLineId].find_first_of(':') + 1).c_str()); meshSubData = vector(meshData.begin() + (numAnimLineId + 1), meshData.end()); - readAnimations(controller, meshSubData, numAnimations); + readAnimations(node, meshSubData, numAnimations); meshSubData.clear(); string skeletonLine = meshData[5]; diff --git a/vbModelReader.h b/vbModelReader.h index 0c305be..66dfdc2 100644 --- a/vbModelReader.h +++ b/vbModelReader.h @@ -25,7 +25,7 @@ namespace vb01{ void connectNodes(); void createBones(Skeleton*, std::vector&); - void readAnimations(AnimationController*, std::vector&, int); + void readAnimations(Animatable*, std::vector&, int); Skeleton* readSkeleton(std::vector&); void readVertices(std::vector&, std::vector&, std::vector&, std::vector&, int); void readFaces(std::vector&, std::vector&, std::vector&, std::vector&, std::vector&, int, Mesh::Vertex*, u32*); @@ -36,6 +36,7 @@ namespace vb01{ void readLights(std::vector&); std::map relationships; + Skeleton *currentSkeleton = nullptr; std::vector skeletons; std::vector meshes; std::vector nodes; diff --git a/vbModelReaderTest.cpp b/vbModelReaderTest.cpp index d9a1444..f127a3b 100644 --- a/vbModelReaderTest.cpp +++ b/vbModelReaderTest.cpp @@ -167,9 +167,10 @@ namespace vb01{ const vector &keyframeChannels = animation->getKeyframeChannels(); vector leftBipodChannels, rightBipodChannels; for(KeyframeChannel ch : keyframeChannels){ - if(ch.bone->getName() == "bipod.L") + vb01::Bone *bone = (vb01::Bone*)ch.animatable; + if(bone->getName() == "bipod.L") leftBipodChannels.push_back(ch); - else if(ch.bone->getName() == "bipod.R") + else if(bone->getName() == "bipod.R") rightBipodChannels.push_back(ch); } CPPUNIT_ASSERT(!leftBipodChannels.empty());