rest of animation coding

animation , animator , keyframe & quaterions
compiling but not debuged at all
This commit is contained in:
Youssef Assem
2019-12-17 04:48:20 +02:00
parent 23dd149d48
commit c2882035b5
16 changed files with 492 additions and 17 deletions
+53 -3
View File
@@ -6,7 +6,7 @@
#define PI 3.14159265358979323846 #define PI 3.14159265358979323846
#define DEG2RAD PI/180 #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(); Transform = Matrix::identity();
Rotation = 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() { ColladaModel::~ColladaModel() {
} }
@@ -220,12 +270,12 @@ Joint ColladaModel::getrootjoint()
void ColladaModel::doanimation(Animation animation) void ColladaModel::doanimation(Animation animation)
{ {
animator.doanimation(animation); //animator.doanimation(animation);
} }
void ColladaModel::updateanimator() void ColladaModel::updateanimator()
{ {
animator.update(); //animator.update();
} }
std::vector<Matrix> ColladaModel::getjointtransforms() std::vector<Matrix> ColladaModel::getjointtransforms()
+23 -5
View File
@@ -24,24 +24,40 @@ class ColladaModel {
private: private:
int face_count; int face_count;
int vertex_count; int vertex_count;
//int normal_count;
//int texcoord_count;
int joint_count; int joint_count;
Joint rootjoint; Joint rootjoint;
int rootindex=0; int rootindex=0;
Matrix roottransform; char* rootname;
Matrix root_transform;
Animator animator; //Animator animator;
std::vector<std::vector<Vec3i> > faces_; //vertex/normal/uv std::vector<std::vector<Vec3i> > faces_; //vertex/normal/uv
std::vector<Vec3f> vertices_; std::vector<Vec3f> vertices_;
std::vector<Vec3f> normals_; std::vector<Vec3f> normals_;
std::vector<Vec2f> texturecos_; std::vector<Vec2f> texturecos_;
// #include <map>
// map<const char*, int> joint_names;
// joints.add(pair<const char*, int>("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<std::vector<Vec2i>> vertexweights_; //joint/weight std::vector<std::vector<Vec2i>> vertexweights_; //joint/weight
std::vector<Vec3i> jointIDs_; std::vector<std::string> jointIDs_;
// { TORSO , LEG, TEZ}
// { 0, 1, 2}
// jointIDs[0]
std::vector<float> weights_; std::vector<float> weights_;
TGAImage diffusemap_; TGAImage diffusemap_;
@@ -50,6 +66,7 @@ private:
void load_texture(std::string filename, const char* suffix, TGAImage& img); void load_texture(std::string filename, const char* suffix, TGAImage& img);
public: public:
ColladaModel() = default;
ColladaModel(const char* filename); ColladaModel(const char* filename);
~ColladaModel(); ~ColladaModel();
@@ -65,6 +82,7 @@ public:
Vec2f uv(int iface, int nthvert); Vec2f uv(int iface, int nthvert);
Matrix Transform; Matrix Transform;
Matrix Rotation; Matrix Rotation;
Matrix Scale; Matrix Scale;
Matrix Translation; Matrix Translation;
+2 -1
View File
@@ -1,8 +1,9 @@
#include "Joint.h" #include "Joint.h"
Joint::Joint(int index, Matrix transform) { Joint::Joint(int index, Matrix transform, char* name) {
Joint::index = index; Joint::index = index;
_transform = transform; _transform = transform;
Joint::name = name;
} }
Joint::~Joint() { Joint::~Joint() {
+3 -1
View File
@@ -10,9 +10,11 @@ private:
public: public:
int index; int index;
char* name;
std::vector<Joint> children; std::vector<Joint> children;
Joint(int index,Matrix transform); Joint() = default;
Joint(int index,Matrix transform,char* name);
~Joint(); ~Joint();
void addChild(Joint child); void addChild(Joint child);
+6
View File
@@ -121,8 +121,11 @@
<ClCompile Include="colladamodel.cpp" /> <ClCompile Include="colladamodel.cpp" />
<ClCompile Include="geometry.cpp" /> <ClCompile Include="geometry.cpp" />
<ClCompile Include="joint.cpp" /> <ClCompile Include="joint.cpp" />
<ClCompile Include="jointtransform.cpp" />
<ClCompile Include="keyframe.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="model.cpp" /> <ClCompile Include="model.cpp" />
<ClCompile Include="quaternion.cpp" />
<ClCompile Include="renderer.cpp" /> <ClCompile Include="renderer.cpp" />
<ClCompile Include="tgaimage.cpp" /> <ClCompile Include="tgaimage.cpp" />
<ClCompile Include="tinyxml2.cpp" /> <ClCompile Include="tinyxml2.cpp" />
@@ -136,7 +139,10 @@
<ClInclude Include="geometry.h" /> <ClInclude Include="geometry.h" />
<ClInclude Include="camera.h" /> <ClInclude Include="camera.h" />
<ClInclude Include="joint.h" /> <ClInclude Include="joint.h" />
<ClInclude Include="jointtransform.h" />
<ClInclude Include="keyframe.h" />
<ClInclude Include="model.h" /> <ClInclude Include="model.h" />
<ClInclude Include="quaternion.h" />
<ClInclude Include="renderer.h" /> <ClInclude Include="renderer.h" />
<ClInclude Include="tgaimage.h" /> <ClInclude Include="tgaimage.h" />
<ClInclude Include="tinyxml2.h" /> <ClInclude Include="tinyxml2.h" />
+18
View File
@@ -54,6 +54,15 @@
<ClCompile Include="animation.cpp"> <ClCompile Include="animation.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="keyframe.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="jointtransform.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="quaternion.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="util_window.h"> <ClInclude Include="util_window.h">
@@ -92,5 +101,14 @@
<ClInclude Include="animation.h"> <ClInclude Include="animation.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="keyframe.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="jointtransform.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="quaternion.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
+16
View File
@@ -1 +1,17 @@
#include "animation.h" #include "animation.h"
Animation::Animation(float seconds, std::vector<Keyframe> keyframes)
{
length = seconds;
keyframes_ = keyframes;
}
float Animation::getlength()
{
return length;
}
std::vector<Keyframe> Animation::getkeyframe()
{
return keyframes_;
}
+14 -3
View File
@@ -1,5 +1,16 @@
#pragma once #pragma once
class Animation
{
};
#include "keyframe.h"
#include <vector>
class Animation {
private:
float length;
std::vector<Keyframe> keyframes_;
public:
Animation() = default;
Animation(float seconds, std::vector<Keyframe> keyframes);
float getlength();
std::vector<Keyframe>getkeyframe();
};
+99
View File
@@ -1,9 +1,108 @@
#include "animator.h" #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<std::string, Matrix> 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<Keyframe> Animator::getPreviousAndNextFrames()
{
std::vector<Keyframe> 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<Keyframe>{ 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<std::string, Matrix> Animator::interpolatePoses(Keyframe previousFrame, Keyframe nextFrame, float progression)
{
std::map<std::string, Matrix> currentPose ;
std::set<std::string> 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) void Animator::doanimation(Animation animation)
{ {
animation_time_ = 0;
current_animation_ = animation;
} }
void Animator::update() void Animator::update()
{ {
if (&current_animation_ == NULL) {
return;
}
increaseAnimationTime();
std::map<std::string, Matrix> currentPose = calculateCurrentAnimationPose();
applyPoseToJoints(currentPose, entity_->getrootjoint(), Matrix());
}
std::map<std::string, Matrix> Animator::calculateCurrentAnimationPose()
{
std::vector<Keyframe> frames = getPreviousAndNextFrames();
float progression = calculateProgression(frames[0], frames[1]);
return interpolatePoses(frames[0], frames[1], progression);
}
template<typename TK, typename TV>
std::vector<TK> extract_keys(std::map<TK, TV> const& input_map) {
std::vector<TK> retval;
for (auto const& element : input_map) {
retval.push_back(element.first);
}
return retval;
}
template<typename TK, typename TV>
std::vector<TV> extract_values(std::map<TK, TV> const& input_map) {
std::vector<TV> retval;
for (auto const& element : input_map) {
retval.push_back(element.second);
}
return retval;
} }
+38 -3
View File
@@ -1,11 +1,46 @@
#pragma once #pragma once
#include "animator.h"
#include "animation.h" #include "animation.h"
#include "geometry.h"
#include "keyframe.h"
#include "jointtransform.h"
#include "joint.h"
#include <map>
#include <set>
class ColladaModel;
class Animator {
private:
ColladaModel* entity_;
Animation current_animation_;
float animation_time_;
void increaseAnimationTime();
std::map<std::string,Matrix> calculateCurrentAnimationPose();
void applyPoseToJoints(std::map<std::string, Matrix> currentPose, Joint joint, Matrix parentTransform);
std::vector<Keyframe> getPreviousAndNextFrames();
float calculateProgression(Keyframe previousFrame, Keyframe nextFrame);
std::map<std::string, Matrix> interpolatePoses(Keyframe previousFrame, Keyframe nextFrame, float progression);
class Animator
{
public: public:
Animator(ColladaModel entity);
void doanimation(Animation animation); 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<Key, T, Comparator, MapAllocator>& map,
std::set<Key, Comparator, SetAllocator>& set)
{
set.clear();
typedef typename std::map<Key, T, Comparator, MapAllocator> map_type;
typename map_type::const_iterator itr = map.begin();
while (map.end() != itr)
{
set.insert((itr++)->first);
}
}
+34
View File
@@ -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);
}
+24
View File
@@ -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);
};
+17
View File
@@ -0,0 +1,17 @@
#include "keyframe.h"
Keyframe::Keyframe(float timestamp, std::map<std::string, JointTransform> pose)
{
timestamp_ = timestamp;
pose_ = pose;
}
float Keyframe::gettimestamp()
{
return timestamp_;
}
std::map<std::string, JointTransform> Keyframe::getJointKeyFrames()
{
return pose_;
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef HI
#define HI
// your declarations (and certain types of definitions) here
#include <map>
#include "jointtransform.h"
class Keyframe{
private:
float timestamp_;
std::map<std::string, JointTransform> pose_;
public:
Keyframe() = default;
Keyframe(float timestamp,std::map<std::string, JointTransform> pose);
float gettimestamp();
std::map<std::string, JointTransform> getJointKeyFrames();
};
#endif
+104
View File
@@ -0,0 +1,104 @@
#include "quaternion.h"
#include <math.h>
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;
}
+17
View File
@@ -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);
};