From c2882035b5e4c1a7a5dcba2fe840b5924e32abf5 Mon Sep 17 00:00:00 2001 From: Youssef Assem Date: Tue, 17 Dec 2019 04:48:20 +0200 Subject: [PATCH] rest of animation coding animation , animator , keyframe & quaterions compiling but not debuged at all --- OpenWindow/ColladaModel.cpp | 56 +++++++++++++- OpenWindow/ColladaModel.h | 28 +++++-- OpenWindow/Joint.cpp | 3 +- OpenWindow/Joint.h | 4 +- OpenWindow/OpenWindow.vcxproj | 6 ++ OpenWindow/OpenWindow.vcxproj.filters | 18 +++++ OpenWindow/animation.cpp | 16 ++++ OpenWindow/animation.h | 17 ++++- OpenWindow/animator.cpp | 99 ++++++++++++++++++++++++ OpenWindow/animator.h | 43 ++++++++++- OpenWindow/jointtransform.cpp | 34 +++++++++ OpenWindow/jointtransform.h | 24 ++++++ OpenWindow/keyframe.cpp | 17 +++++ OpenWindow/keyframe.h | 23 ++++++ OpenWindow/quaternion.cpp | 104 ++++++++++++++++++++++++++ OpenWindow/quaternion.h | 17 +++++ 16 files changed, 492 insertions(+), 17 deletions(-) create mode 100644 OpenWindow/jointtransform.cpp create mode 100644 OpenWindow/jointtransform.h create mode 100644 OpenWindow/keyframe.cpp create mode 100644 OpenWindow/keyframe.h create mode 100644 OpenWindow/quaternion.cpp create mode 100644 OpenWindow/quaternion.h diff --git a/OpenWindow/ColladaModel.cpp b/OpenWindow/ColladaModel.cpp index 8d092ef..e47545d 100644 --- a/OpenWindow/ColladaModel.cpp +++ b/OpenWindow/ColladaModel.cpp @@ -6,7 +6,7 @@ #define PI 3.14159265358979323846 #define DEG2RAD PI/180 -ColladaModel::ColladaModel(const char* filename) : faces_(), vertices_(), normals_(), rootjoint(rootindex, roottransform) +ColladaModel::ColladaModel(const char* filename) : faces_(), vertices_(), normals_(), rootjoint() { Transform = Matrix::identity(); Rotation = Matrix::identity(); @@ -125,7 +125,57 @@ ColladaModel::ColladaModel(const char* filename) : faces_(), vertices_(), normal /////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// + /*joint_count = 0; + tinyxml2::XMLElement* xml_joint = doc.FirstChildElement("COLLADA")->FirstChildElement("library_controllers")->FirstChildElement()->FirstChildElement()->FirstChildElement("source")->FirstChildElement(); + xml_joint->QueryIntAttribute("count", &joint_count); + std::stringstream str_joint(xml_joint->GetText()); + */ + /*for (int i = 0; i < joint_count; i++) + { + Vec2f temp; + str_texcoord >> temp.x; + str_texcoord >> temp.y; + texturecos_.push_back(temp); + }*/ + /////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////// + //tinyxml2::XMLElement* xml_hierachy = doc.FirstChildElement("COLLADA")->FirstChildElement("library_visual_scenes")->FirstChildElement("visual_scene")->FirstChildElement("node")->FirstChildElement("node"); + //std::stringstream str_hierachy(xml_hierachy->GetText()); + + //ColladaModel::rootjoint = buildjoint(xml_hierachy); + joint_count = 0; + tinyxml2::XMLElement* xml_joint = doc.FirstChildElement("COLLADA")->FirstChildElement("library_controllers")->FirstChildElement("controller")->FirstChildElement("skin")->FirstChildElement("source")->FirstChildElement("Name_array"); + xml_joint->QueryIntAttribute("count", &joint_count); + std::stringstream str_joint(xml_joint->GetText()); + + for (int i = 0; i < vertex_count / 3; i++) + { + std::string temp; + str_vertex >> temp; + + jointIDs_.push_back(temp); + } + } + +//Joint buildjoint(tinyxml2::XMLElement* xml_hierachy) +//{ +// const char* name; +// xml_hierachy->QueryStringAttribute("name", &name); +// std::stringstream str_transform(xml_hierachy->FirstChildElement("matrix")->GetText()); +// Matrix transform; +// +// if (xml_hierachy->FirstChildElement("node") != NULL) +// { +// xml_hierachy = xml_hierachy->FirstChildElement("node"); +// do +// { +//// buildjoint +// } while (xml_hierachy->NextSiblingElement() != NULL); +// } +//} + ColladaModel::~ColladaModel() { } @@ -220,12 +270,12 @@ Joint ColladaModel::getrootjoint() void ColladaModel::doanimation(Animation animation) { - animator.doanimation(animation); + //animator.doanimation(animation); } void ColladaModel::updateanimator() { - animator.update(); + //animator.update(); } std::vector ColladaModel::getjointtransforms() diff --git a/OpenWindow/ColladaModel.h b/OpenWindow/ColladaModel.h index faab146..16dcbfb 100644 --- a/OpenWindow/ColladaModel.h +++ b/OpenWindow/ColladaModel.h @@ -24,24 +24,40 @@ class ColladaModel { private: int face_count; int vertex_count; - //int normal_count; - //int texcoord_count; int joint_count; Joint rootjoint; int rootindex=0; - Matrix roottransform; + char* rootname; + Matrix root_transform; - Animator animator; + //Animator animator; std::vector > faces_; //vertex/normal/uv std::vector vertices_; std::vector normals_; std::vector texturecos_; + // #include + // map joint_names; + // joints.add(pair("TORSO", 0)); + // {TORSO, 0} + // {LEG, 1} + // {HAND, 2} + + //joint_names.get("TORSO"); + + // 1. Get jointnames and map them to ids + // 2. get each joint and fill in the Joint class + // 3. get inversebindtransforms + + // Vector -> Vectors -> (joint , weight) std::vector> vertexweights_; //joint/weight - std::vector jointIDs_; + std::vector jointIDs_; + // { TORSO , LEG, TEZ} + // { 0, 1, 2} + // jointIDs[0] std::vector weights_; TGAImage diffusemap_; @@ -50,6 +66,7 @@ private: void load_texture(std::string filename, const char* suffix, TGAImage& img); public: + ColladaModel() = default; ColladaModel(const char* filename); ~ColladaModel(); @@ -65,6 +82,7 @@ public: Vec2f uv(int iface, int nthvert); Matrix Transform; + Matrix Rotation; Matrix Scale; Matrix Translation; diff --git a/OpenWindow/Joint.cpp b/OpenWindow/Joint.cpp index 2907789..c9d8ded 100644 --- a/OpenWindow/Joint.cpp +++ b/OpenWindow/Joint.cpp @@ -1,8 +1,9 @@ #include "Joint.h" -Joint::Joint(int index, Matrix transform) { +Joint::Joint(int index, Matrix transform, char* name) { Joint::index = index; _transform = transform; + Joint::name = name; } Joint::~Joint() { diff --git a/OpenWindow/Joint.h b/OpenWindow/Joint.h index 10197e2..76a53e8 100644 --- a/OpenWindow/Joint.h +++ b/OpenWindow/Joint.h @@ -10,9 +10,11 @@ private: public: int index; + char* name; std::vector children; - Joint(int index,Matrix transform); + Joint() = default; + Joint(int index,Matrix transform,char* name); ~Joint(); void addChild(Joint child); diff --git a/OpenWindow/OpenWindow.vcxproj b/OpenWindow/OpenWindow.vcxproj index 308c2df..6efea98 100644 --- a/OpenWindow/OpenWindow.vcxproj +++ b/OpenWindow/OpenWindow.vcxproj @@ -121,8 +121,11 @@ + + + @@ -136,7 +139,10 @@ + + + diff --git a/OpenWindow/OpenWindow.vcxproj.filters b/OpenWindow/OpenWindow.vcxproj.filters index 9077163..1cc26ab 100644 --- a/OpenWindow/OpenWindow.vcxproj.filters +++ b/OpenWindow/OpenWindow.vcxproj.filters @@ -54,6 +54,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -92,5 +101,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/OpenWindow/animation.cpp b/OpenWindow/animation.cpp index ac1d7f8..b0eb5cc 100644 --- a/OpenWindow/animation.cpp +++ b/OpenWindow/animation.cpp @@ -1 +1,17 @@ #include "animation.h" + +Animation::Animation(float seconds, std::vector keyframes) +{ + length = seconds; + keyframes_ = keyframes; +} + +float Animation::getlength() +{ + return length; +} + +std::vector Animation::getkeyframe() +{ + return keyframes_; +} diff --git a/OpenWindow/animation.h b/OpenWindow/animation.h index b7935fd..1b3ba9c 100644 --- a/OpenWindow/animation.h +++ b/OpenWindow/animation.h @@ -1,5 +1,16 @@ #pragma once -class Animation -{ -}; +#include "keyframe.h" +#include + +class Animation { +private: + float length; + std::vector keyframes_; + +public: + Animation() = default; + Animation(float seconds, std::vector keyframes); + float getlength(); + std::vectorgetkeyframe(); +}; \ No newline at end of file diff --git a/OpenWindow/animator.cpp b/OpenWindow/animator.cpp index 01dce8a..5252437 100644 --- a/OpenWindow/animator.cpp +++ b/OpenWindow/animator.cpp @@ -1,9 +1,108 @@ #include "animator.h" +#include "colladamodel.h" + +void Animator::increaseAnimationTime() +{ + animation_time_ += (1/60.f); + if (animation_time_ > current_animation_.getlength()) + { + animation_time_ = (int)(animation_time_) % (int)(current_animation_.getlength()); + } +} + + + +void Animator::applyPoseToJoints(std::map currentPose, Joint joint, Matrix parentTransform) +{ + Matrix currentLocalTransform = currentPose.at(joint.name); + Matrix currentTransform = parentTransform * currentLocalTransform; + for (Joint childJoint : joint.children) { + applyPoseToJoints(currentPose, childJoint, currentTransform); + } + currentTransform = currentTransform * joint.getInverseBindTransform(); + joint.setTransform(currentTransform); +} + +std::vector Animator::getPreviousAndNextFrames() +{ + std::vector allFrames = current_animation_.getkeyframe(); + Keyframe previousFrame = allFrames[0]; + Keyframe nextFrame = allFrames[0]; + for (int i = 1; i < allFrames.capacity(); i++) { + nextFrame = allFrames[i]; + if (nextFrame.gettimestamp() > animation_time_) { + break; + } + previousFrame = allFrames[i]; + } + return std::vector{ previousFrame, nextFrame }; +} + +float Animator::calculateProgression(Keyframe previousFrame, Keyframe nextFrame) +{ + float totalTime = nextFrame.gettimestamp() - previousFrame.gettimestamp(); + float currentTime = animation_time_ - previousFrame.gettimestamp(); + return currentTime / totalTime; +} + +std::map Animator::interpolatePoses(Keyframe previousFrame, Keyframe nextFrame, float progression) +{ + std::map currentPose ; + std::set key_set; + make_key_set(previousFrame.getJointKeyFrames(), key_set); + for (std::string jointName : key_set) + { + JointTransform previousTransform = previousFrame.getJointKeyFrames().at(jointName); + JointTransform nextTransform = nextFrame.getJointKeyFrames().at(jointName); + JointTransform currentTransform = JointTransform::interpolate(previousTransform, nextTransform, progression); + currentPose.insert_or_assign(jointName, currentTransform.getlocationtransform()); + make_key_set(previousFrame.getJointKeyFrames(), key_set); + } + return currentPose; +} + +Animator::Animator(ColladaModel entity) +{ + entity_ = &entity; +} void Animator::doanimation(Animation animation) { + animation_time_ = 0; + current_animation_ = animation; } void Animator::update() { + if (¤t_animation_ == NULL) { + return; + } + increaseAnimationTime(); + std::map currentPose = calculateCurrentAnimationPose(); + applyPoseToJoints(currentPose, entity_->getrootjoint(), Matrix()); } + +std::map Animator::calculateCurrentAnimationPose() +{ + std::vector frames = getPreviousAndNextFrames(); + float progression = calculateProgression(frames[0], frames[1]); + return interpolatePoses(frames[0], frames[1], progression); +} + +template +std::vector extract_keys(std::map const& input_map) { + std::vector retval; + for (auto const& element : input_map) { + retval.push_back(element.first); + } + return retval; +} + +template +std::vector extract_values(std::map const& input_map) { + std::vector retval; + for (auto const& element : input_map) { + retval.push_back(element.second); + } + return retval; +} \ No newline at end of file diff --git a/OpenWindow/animator.h b/OpenWindow/animator.h index 8378935..1322cbb 100644 --- a/OpenWindow/animator.h +++ b/OpenWindow/animator.h @@ -1,11 +1,46 @@ #pragma once -#include "animator.h" #include "animation.h" +#include "geometry.h" +#include "keyframe.h" +#include "jointtransform.h" +#include "joint.h" +#include +#include +class ColladaModel; + +class Animator { +private: + ColladaModel* entity_; + Animation current_animation_; + float animation_time_; + + void increaseAnimationTime(); + std::map calculateCurrentAnimationPose(); + void applyPoseToJoints(std::map currentPose, Joint joint, Matrix parentTransform); + std::vector getPreviousAndNextFrames(); + float calculateProgression(Keyframe previousFrame, Keyframe nextFrame); + std::map interpolatePoses(Keyframe previousFrame, Keyframe nextFrame, float progression); -class Animator -{ public: + Animator(ColladaModel entity); void doanimation(Animation animation); - void update(); + void update(); }; +template< class Key, + class T, + class Comparator, + class MapAllocator, + class SetAllocator> + void make_key_set(const std::map& map, + std::set& set) +{ + set.clear(); + typedef typename std::map map_type; + typename map_type::const_iterator itr = map.begin(); + while (map.end() != itr) + { + set.insert((itr++)->first); + } +} + diff --git a/OpenWindow/jointtransform.cpp b/OpenWindow/jointtransform.cpp new file mode 100644 index 0000000..d59ae00 --- /dev/null +++ b/OpenWindow/jointtransform.cpp @@ -0,0 +1,34 @@ +#include "jointtransform.h" + + + +JointTransform::JointTransform(Vec3f position, Quaternion rotation) +{ + position_ = position; + rotation_ = rotation; +} + +Matrix JointTransform::getlocationtransform() +{ + Matrix matrix; + Vec4f column = Vec4f(position_.x, position_.y, position_.z, 1); + matrix.set_col(3, column); + matrix = matrix * rotation_.toRotationMatrix(); + return matrix; +} + +JointTransform JointTransform::interpolate(JointTransform frame1, JointTransform frame2, float progression) +{ + Vec3f pos = interpolate(frame1.position_, frame2.position_, progression); + Quaternion rot = Quaternion::interpolate(frame1.rotation_, frame2.rotation_, progression); + return JointTransform(pos, rot); +} + +Vec3f JointTransform::interpolate(Vec3f start, Vec3f end, float progression) +{ + float x = start.x + (end.x - start.x) * progression; + float y = start.y + (end.y - start.y) * progression; + float z = start.z + (end.z - start.z) * progression; + + return Vec3f(x,y,z); +} diff --git a/OpenWindow/jointtransform.h b/OpenWindow/jointtransform.h new file mode 100644 index 0000000..ed39929 --- /dev/null +++ b/OpenWindow/jointtransform.h @@ -0,0 +1,24 @@ +#pragma once + +#include "quaternion.h" +#include "geometry.h" + +class JointTransform +{ +private: + + Vec3f position_; + + Quaternion rotation_; + +public: + JointTransform() = default; + JointTransform(Vec3f position,Quaternion rotation); + + Matrix getlocationtransform(); + + static JointTransform interpolate(JointTransform frame1, JointTransform frame2, float progression); + + static Vec3f interpolate(Vec3f start,Vec3f end, float progression); +}; + diff --git a/OpenWindow/keyframe.cpp b/OpenWindow/keyframe.cpp new file mode 100644 index 0000000..60311a4 --- /dev/null +++ b/OpenWindow/keyframe.cpp @@ -0,0 +1,17 @@ +#include "keyframe.h" + +Keyframe::Keyframe(float timestamp, std::map pose) +{ + timestamp_ = timestamp; + pose_ = pose; +} + +float Keyframe::gettimestamp() +{ + return timestamp_; +} + +std::map Keyframe::getJointKeyFrames() +{ + return pose_; +} diff --git a/OpenWindow/keyframe.h b/OpenWindow/keyframe.h new file mode 100644 index 0000000..61e272c --- /dev/null +++ b/OpenWindow/keyframe.h @@ -0,0 +1,23 @@ +#ifndef HI +#define HI + +// your declarations (and certain types of definitions) here + + +#include +#include "jointtransform.h" + + +class Keyframe{ +private: + float timestamp_; + std::map pose_; + +public: + Keyframe() = default; + Keyframe(float timestamp,std::map pose); + float gettimestamp(); + std::map getJointKeyFrames(); +}; + +#endif \ No newline at end of file diff --git a/OpenWindow/quaternion.cpp b/OpenWindow/quaternion.cpp new file mode 100644 index 0000000..5acd630 --- /dev/null +++ b/OpenWindow/quaternion.cpp @@ -0,0 +1,104 @@ +#include "quaternion.h" +#include + +Quaternion::Quaternion(float x, float y, float z, float w) +{ + x_ = x; + y_ = y; + z_ = z; + w_ = w; + normalize(); +} + +void Quaternion::normalize() +{ + float mag = (float)sqrt(w_ * w_ + x_ * x_ + y_ * y_ + z_ * z_); + w_ /= mag; + x_ /= mag; + y_ /= mag; + z_ /= mag; +} + +Matrix Quaternion::toRotationMatrix() +{ + Matrix matrix; + float xy = x_ * y_; + float xz = x_ * z_; + float xw = x_ * w_; + float yz = y_ * z_; + float yw = y_ * w_; + float zw = z_ * w_; + float xSquared = x_ * x_; + float ySquared = y_ * y_; + float zSquared = z_ * z_; + + Vec4f c0 = Vec4f(1 - 2 * (ySquared + zSquared), 2 * (xy - zw), 2 * (xz + yw),0); + Vec4f c1 = Vec4f(2 * (xy + zw), 1 - 2 * (xSquared + zSquared), 2 * (yz - xw), 0); + Vec4f c2 = Vec4f(2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xSquared + ySquared), 0); + Vec4f c3 = Vec4f(0,0,0,1); + + matrix.set_col(0,c0); + matrix.set_col(1, c1); + matrix.set_col(2, c2); + matrix.set_col(3, c3); + return matrix; +} + +Quaternion Quaternion::fromMatrix(Matrix matrix) +{ + float w_, x_, y_, z_; + float diagonal = matrix[0][0] + matrix[1][1] + matrix[2][2]; + if (diagonal > 0) { + float w4 = (float)(sqrt(diagonal + 1.f) * 2.f); + w_ = w4 / 4.f; + x_ = (matrix[2][1] - matrix[1][2]) / w4; + y_ = (matrix[0][2] - matrix[2][0]) / w4; + z_ = (matrix[1][0] - matrix[0][1]) / w4; + } + else if ((matrix[0][0] > matrix[1][1]) && (matrix[0][0] > matrix[2][2])) { + float x4 = (float)(sqrt(1.f + matrix[0][0] - matrix[1][1] - matrix[2][2]) * 2.f); + w_ = (matrix[2][1] - matrix[1][2]) / x4; + x_ = x4 / 4.f; + y_ = (matrix[0][1] + matrix[1][0]) / x4; + z_ = (matrix[0][2] + matrix[2][0]) / x4; + } + else if (matrix[1][1] > matrix[2][2]) { + float y4 = (float)(sqrt(1.f + matrix[1][1] - matrix[0][0] - matrix[2][2]) * 2.f); + w_ = (matrix[0][2] - matrix[2][0]) / y4; + x_ = (matrix[0][1] + matrix[1][0]) / y4; + y_ = y4 / 4.f; + z_ = (matrix[1][2] + matrix[2][1]) / y4; + } + else { + float z4 = (float)(sqrt(1.f + matrix[2][2] - matrix[0][0] - matrix[1][1]) * 2.f); + w_ = (matrix[1][0] - matrix[0][1]) / z4; + x_ = (matrix[0][2] + matrix[2][0]) / z4; + y_ = (matrix[1][2] + matrix[2][1]) / z4; + z_ = z4 / 4.f; + } + return Quaternion(x_, y_, z_, w_); +} + +Quaternion Quaternion::interpolate(Quaternion a, Quaternion b, float blend) + { + Quaternion result(0, 0, 0, 1); + float dot = a.w_ * b.w_ + a.x_ * b.x_ + a.y_ * b.y_ + a.z_ * b.z_; + float blendI = 1.f - blend; + if (dot < 0) { + result.w_ = blendI * a.w_ + blend * -b.w_; + result.x_ = blendI * a.x_ + blend * -b.x_; + result.y_ = blendI * a.y_ + blend * -b.y_; + result.z_ = blendI * a.z_ + blend * -b.z_; + } + else { + result.w_ = blendI * a.w_ + blend * b.w_; + result.x_ = blendI * a.x_ + blend * b.x_; + result.y_ = blendI * a.y_ + blend * b.y_; + result.z_ = blendI * a.z_ + blend * b.z_; + } + result.normalize(); + return result; +} + + + diff --git a/OpenWindow/quaternion.h b/OpenWindow/quaternion.h new file mode 100644 index 0000000..940ea5f --- /dev/null +++ b/OpenWindow/quaternion.h @@ -0,0 +1,17 @@ +#pragma once +#include "geometry.h" +class Quaternion +{ +private: + float x_, y_, z_, w_; + + +public: + Quaternion() = default; + Quaternion(float x, float y, float z, float w); + void normalize(); + Matrix toRotationMatrix(); + static Quaternion fromMatrix(Matrix matrix); + static Quaternion interpolate(Quaternion a, Quaternion b, float blend); +}; +