Merge solution and next task
This commit is contained in:
parent
b5748c2902
commit
3b55561ce2
10 changed files with 225 additions and 364 deletions
BIN
03_IK.pdf
Normal file
BIN
03_IK.pdf
Normal file
Binary file not shown.
BIN
3-intro.pdf
Normal file
BIN
3-intro.pdf
Normal file
Binary file not shown.
|
@ -79,3 +79,13 @@ bool Animation::read_amc_file(std::string filename, Skeleton* s)
|
||||||
|
|
||||||
int Animation::frame_count() const { return frames.size(); }
|
int Animation::frame_count() const { return frames.size(); }
|
||||||
|
|
||||||
|
void Animation::apply_frame(int frame) const
|
||||||
|
{
|
||||||
|
for (auto& bone : frames.at(frame))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < bone.bone->dof_count(); ++i)
|
||||||
|
{
|
||||||
|
bone.bone->get_dof(i)->set_value(bone.dof_values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ public:
|
||||||
bool read_amc_file(std::string filename, Skeleton*);
|
bool read_amc_file(std::string filename, Skeleton*);
|
||||||
int frame_count() const;
|
int frame_count() const;
|
||||||
|
|
||||||
|
void apply_frame(int frame) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//Contains a std::vector<AnimationFrameBone> for each frame, which contains animation data for a set of bones.
|
//Contains a std::vector<AnimationFrameBone> for each frame, which contains animation data for a set of bones.
|
||||||
|
|
|
@ -40,7 +40,45 @@ Mat4 AtomicRotationTransform::calculate_matrix()
|
||||||
return rotate(axis, (float)value);
|
return rotate(axis, (float)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AtomicRotationTransform::drawIndicator(float size)
|
||||||
|
{
|
||||||
|
if (lower_limit == upper_limit)
|
||||||
|
return;
|
||||||
|
//Calculate rotation matrix from x-axis to current axis
|
||||||
|
Vec3 rot_axis = cgv::math::cross(Vec3(1, 0, 0), axis);
|
||||||
|
float angle = acosf(axis.x() / axis.length());
|
||||||
|
Mat4 t;
|
||||||
|
if (angle == 0)
|
||||||
|
t.identity();
|
||||||
|
else
|
||||||
|
t = rotate(rot_axis, angle * 180.0f / 3.1415926f);
|
||||||
|
glBegin(GL_TRIANGLE_FAN);
|
||||||
|
glVertex3f(0, 0, 0);
|
||||||
|
for (float v = (float)lower_limit; v <= upper_limit; v += 5)
|
||||||
|
{
|
||||||
|
auto p = t * size * Vec4(0, -cosf(v * PI / 180.0f), -sinf(v * PI / 180.0f), 0);
|
||||||
|
glVertex3f(p.x(), p.y(), p.z());
|
||||||
|
}
|
||||||
|
auto end = t * size * Vec4(0, -cosf((float)upper_limit * PI / 180.0f), -sinf((float)upper_limit * PI / 180.0f), 0);
|
||||||
|
glVertex3f(end.x(), end.y(), end.z());
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
void AtomicRotationTransform::drawActualIndicator(float size)
|
||||||
|
{
|
||||||
|
//Calculate rotation matrix from x-axis to current axis
|
||||||
|
Vec3 rot_axis = cgv::math::cross(Vec3(1, 0, 0), axis);
|
||||||
|
float angle = acosf(axis.x() / axis.length());
|
||||||
|
Mat4 t;
|
||||||
|
if (angle == 0)
|
||||||
|
t.identity();
|
||||||
|
else
|
||||||
|
t = rotate(rot_axis, angle * 180.0f / 3.1415926f);
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glVertex3f(0, 0, 0);
|
||||||
|
auto p = t * size * Vec4(0, -cosf((float)value * PI / 180.0f), -sinf((float)value * PI / 180.0f), 0);
|
||||||
|
glVertex3f(p.x(), p.y(), p.z());
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
void AtomicRotationTransform::optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse)
|
void AtomicRotationTransform::optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,7 +57,10 @@ public:
|
||||||
virtual void optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse = false) = 0;
|
virtual void optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse = false) = 0;
|
||||||
virtual void optimize_value(const Vec3& local_vector, const Vec3& target) { optimize_value(local_vector, target, false); }
|
virtual void optimize_value(const Vec3& local_vector, const Vec3& target) { optimize_value(local_vector, target, false); }
|
||||||
|
|
||||||
|
//Draws an indicator that visualizes the transform, including its limits.
|
||||||
|
virtual void drawIndicator(float size) = 0;
|
||||||
|
//Draws an indicator that visualizes the current scalar parameter.
|
||||||
|
virtual void drawActualIndicator(float size) = 0;
|
||||||
|
|
||||||
std::string get_name() const;
|
std::string get_name() const;
|
||||||
|
|
||||||
|
@ -84,7 +87,8 @@ public:
|
||||||
virtual Mat4 calculate_matrix();
|
virtual Mat4 calculate_matrix();
|
||||||
virtual void optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse = false);
|
virtual void optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse = false);
|
||||||
|
|
||||||
|
virtual void drawIndicator(float size);
|
||||||
|
virtual void drawActualIndicator(float size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Vec3 axis;
|
Vec3 axis;
|
||||||
|
@ -115,7 +119,8 @@ public:
|
||||||
virtual Mat4 calculate_matrix();
|
virtual Mat4 calculate_matrix();
|
||||||
virtual void optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse = false);
|
virtual void optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse = false);
|
||||||
|
|
||||||
|
virtual void drawIndicator(float size) { };
|
||||||
|
virtual void drawActualIndicator(float size) { };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int dim;
|
int dim;
|
||||||
|
|
|
@ -9,29 +9,9 @@
|
||||||
|
|
||||||
#include "math_helper.h"
|
#include "math_helper.h"
|
||||||
|
|
||||||
std::string from_Vec3(Vec3 &v)
|
|
||||||
{
|
|
||||||
std::stringstream is;
|
|
||||||
|
|
||||||
is << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")";
|
|
||||||
|
|
||||||
return is.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
float calc_angle(Vec3 dir_vec, Vec3 axis)
|
|
||||||
{
|
|
||||||
float dot_result = dot(dir_vec, axis);
|
|
||||||
|
|
||||||
float length_v1 = length(dir_vec);
|
|
||||||
float length_v2 = length(axis);
|
|
||||||
|
|
||||||
return acos(dot_result / (length_v1 * length_v2));
|
|
||||||
}
|
|
||||||
|
|
||||||
Bone::Bone()
|
Bone::Bone()
|
||||||
: parent(nullptr), length(0.0f), direction_in_world_space(0.0, 0.0, 0.0), translationTransforms(0)
|
: parent(nullptr), length(0.0f), direction_in_world_space(0.0, 0.0, 0.0), translationTransforms(0)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
Bone::~Bone()
|
Bone::~Bone()
|
||||||
{
|
{
|
||||||
|
@ -49,46 +29,23 @@ Bone::~Bone()
|
||||||
void Bone::calculate_matrices()
|
void Bone::calculate_matrices()
|
||||||
{
|
{
|
||||||
orientationTransformGlobalToLocal.identity();
|
orientationTransformGlobalToLocal.identity();
|
||||||
std::for_each(orientation.begin(), orientation.end(), [&](AtomicTransform *t) {
|
std::for_each(orientation.begin(), orientation.end(), [&](AtomicTransform* t) {
|
||||||
//std::cout << name << " orientation " << t->get_name() << ": " << t->get_value() << std::endl;
|
|
||||||
|
|
||||||
orientationTransformGlobalToLocal = orientationTransformGlobalToLocal * t->calculate_matrix();
|
orientationTransformGlobalToLocal = orientationTransformGlobalToLocal * t->calculate_matrix();
|
||||||
});
|
});
|
||||||
|
|
||||||
orientationTransformLocalToGlobal = cgv::math::inv(orientationTransformGlobalToLocal);
|
orientationTransformLocalToGlobal = cgv::math::inv(orientationTransformGlobalToLocal);
|
||||||
|
|
||||||
//std::cout << name << " direction " << from_Vec3(direction_in_world_space) << std::endl;
|
Vec4 globalDirection = Vec4(direction_in_world_space.x() * length, direction_in_world_space.y() * length, direction_in_world_space.z() * length, 0);
|
||||||
//std::cout << name << " length " << length << std::endl;
|
Vec4 localDirection = orientationTransformLocalToGlobal * globalDirection;
|
||||||
|
translationTransformCurrentJointToNext = translate(localDirection.x(), localDirection.y(), localDirection.z());
|
||||||
/*Task 2.1: Implement matrix calculation */
|
if (parent != nullptr)
|
||||||
Vec3 vector = direction_in_world_space * length;
|
|
||||||
//translationTransformCurrentJointToNext = orientationTransformLocalToGlobal * translate(vector) * orientationTransformGlobalToLocal;
|
|
||||||
translationTransformCurrentJointToNext = translate(vector);
|
|
||||||
|
|
||||||
if (parent == nullptr)
|
|
||||||
{
|
{
|
||||||
orientationTransformPrevJointToCurrent.identity();
|
orientationTransformPrevJointToCurrent = parent->orientationTransformLocalToGlobal * orientationTransformGlobalToLocal;
|
||||||
|
translationTransformGlobalToLocal = parent->translationTransformGlobalToLocal * translate(parent->direction_in_world_space * parent->length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Vec3 prev_dir = parent->get_direction_in_world_space();
|
orientationTransformPrevJointToCurrent = orientationTransformGlobalToLocal;
|
||||||
Vec3 &curr_dir = direction_in_world_space;
|
translationTransformGlobalToLocal.identity();
|
||||||
|
|
||||||
if (prev_dir.x() == 0.0f && prev_dir.y() == 0.0f && prev_dir.z() == 0.0f)
|
|
||||||
{
|
|
||||||
orientationTransformPrevJointToCurrent.identity();
|
|
||||||
}
|
|
||||||
else if (prev_dir == curr_dir)
|
|
||||||
{
|
|
||||||
orientationTransformPrevJointToCurrent.identity();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float angle = calc_angle(curr_dir, prev_dir);
|
|
||||||
Vec3 axis = cross(curr_dir, prev_dir);
|
|
||||||
|
|
||||||
orientationTransformPrevJointToCurrent = rotate(axis, angle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Task 4.6: Implement matrix calculation */
|
/*Task 4.6: Implement matrix calculation */
|
||||||
|
@ -96,46 +53,24 @@ void Bone::calculate_matrices()
|
||||||
|
|
||||||
Mat4 Bone::calculate_transform_prev_to_current_with_dofs()
|
Mat4 Bone::calculate_transform_prev_to_current_with_dofs()
|
||||||
{
|
{
|
||||||
//Task 2.1: Implement matrix calculation
|
Mat4 t = calculate_transform_prev_to_current_without_dofs();
|
||||||
if (parent == NULL)
|
for (unsigned int i = 0; i < dofs.size(); ++i)
|
||||||
{
|
t = t * dofs[i]->calculate_matrix();
|
||||||
Mat4 t;
|
return t;
|
||||||
t.identity();
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mat4 dofs_matrix;
|
|
||||||
dofs_matrix.identity();
|
|
||||||
|
|
||||||
std::for_each(dofs.begin(), dofs.end(), [&](std::shared_ptr<AtomicTransform> &t) {
|
|
||||||
dofs_matrix = dofs_matrix * t->calculate_matrix();
|
|
||||||
});
|
|
||||||
|
|
||||||
return parent->get_translation_transform_current_joint_to_next() * orientationTransformPrevJointToCurrent * dofs_matrix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat4 Bone::calculate_transform_prev_to_current_without_dofs()
|
Mat4 Bone::calculate_transform_prev_to_current_without_dofs()
|
||||||
{
|
{
|
||||||
//Task 2.1: Implement matrix calculation
|
Mat4 t = orientationTransformPrevJointToCurrent;
|
||||||
return parent->get_translation_transform_current_joint_to_next() * orientationTransformPrevJointToCurrent;
|
if (parent != nullptr)
|
||||||
|
t = parent->translationTransformCurrentJointToNext * t;
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat4 Bone::get_total_orientation()
|
void Bone::add_dof(AtomicTransform* dof)
|
||||||
{
|
|
||||||
Mat4 parent_orientation;
|
|
||||||
|
|
||||||
if (parent != NULL)
|
|
||||||
parent_orientation = parent->get_total_orientation();
|
|
||||||
else
|
|
||||||
parent_orientation.identity();
|
|
||||||
|
|
||||||
return orientationTransformPrevJointToCurrent * parent_orientation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bone::add_dof(AtomicTransform *dof)
|
|
||||||
{
|
{
|
||||||
dof->set_index_in_amc(dofs.size());
|
dof->set_index_in_amc(dofs.size());
|
||||||
if (dynamic_cast<AtomicTranslationTransform *>(dof))
|
if (dynamic_cast<AtomicTranslationTransform*>(dof))
|
||||||
{
|
{
|
||||||
dofs.push_front(std::shared_ptr<AtomicTransform>(dof));
|
dofs.push_front(std::shared_ptr<AtomicTransform>(dof));
|
||||||
++translationTransforms;
|
++translationTransforms;
|
||||||
|
@ -144,40 +79,40 @@ void Bone::add_dof(AtomicTransform *dof)
|
||||||
dofs.insert(dofs.begin() + translationTransforms, std::shared_ptr<AtomicTransform>(dof));
|
dofs.insert(dofs.begin() + translationTransforms, std::shared_ptr<AtomicTransform>(dof));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bone::set_name(const std::string &name) { this->name = name; }
|
void Bone::set_name(const std::string& name) { this->name = name; }
|
||||||
const std::string &Bone::get_name() const { return name; }
|
const std::string& Bone::get_name() const { return name; }
|
||||||
|
|
||||||
void Bone::set_direction_in_world_space(const Vec3 &direction) { this->direction_in_world_space = direction; }
|
void Bone::set_direction_in_world_space(const Vec3& direction) { this->direction_in_world_space = direction; }
|
||||||
const Vec3 &Bone::get_direction_in_world_space() const { return direction_in_world_space; }
|
const Vec3& Bone::get_direction_in_world_space() const { return direction_in_world_space; }
|
||||||
|
|
||||||
void Bone::set_length(float l) { this->length = l; }
|
void Bone::set_length(float l) { this->length = l; }
|
||||||
float Bone::get_length() const { return length; }
|
float Bone::get_length() const { return length; }
|
||||||
|
|
||||||
void Bone::add_axis_rotation(AtomicTransform *transform) { orientation.push_front(transform); }
|
void Bone::add_axis_rotation(AtomicTransform* transform) { orientation.push_front(transform); }
|
||||||
void Bone::add_child(Bone *child)
|
void Bone::add_child(Bone* child)
|
||||||
{
|
{
|
||||||
child->set_parent(this);
|
child->set_parent(this);
|
||||||
children.push_back(child);
|
children.push_back(child);
|
||||||
}
|
}
|
||||||
Bone *Bone::child_at(int i) const { return children[i]; }
|
Bone* Bone::child_at(int i) const { return children[i]; }
|
||||||
int Bone::childCount() const { return children.size(); }
|
int Bone::childCount() const { return children.size(); }
|
||||||
|
|
||||||
void Bone::set_parent(Bone *parent)
|
void Bone::set_parent(Bone* parent)
|
||||||
{
|
{
|
||||||
this->parent = parent;
|
this->parent = parent;
|
||||||
}
|
}
|
||||||
Bone *Bone::get_parent() const { return parent; }
|
Bone* Bone::get_parent() const { return parent; }
|
||||||
|
|
||||||
int Bone::dof_count() const { return dofs.size(); }
|
int Bone::dof_count() const { return dofs.size(); }
|
||||||
std::shared_ptr<AtomicTransform> Bone::get_dof(int dofIndex) const { return dofs[dofIndex]; }
|
std::shared_ptr<AtomicTransform> Bone::get_dof(int dofIndex) const { return dofs[dofIndex]; }
|
||||||
|
|
||||||
const Mat4 &Bone::get_binding_pose_matrix() const
|
const Mat4& Bone::get_binding_pose_matrix() const
|
||||||
{
|
{
|
||||||
return transformLocalToGlobal;
|
return transformLocalToGlobal;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mat4 &Bone::get_translation_transform_current_joint_to_next() const { return translationTransformCurrentJointToNext; }
|
const Mat4& Bone::get_translation_transform_current_joint_to_next() const { return translationTransformCurrentJointToNext; }
|
||||||
const Mat4 &Bone::get_orientation_transform_prev_joint_to_current() const { return orientationTransformPrevJointToCurrent; }
|
const Mat4& Bone::get_orientation_transform_prev_joint_to_current() const { return orientationTransformPrevJointToCurrent; }
|
||||||
|
|
||||||
Vec4 Bone::get_bone_local_root_position() const { return Vec4(0, 0, 0, 1); }
|
Vec4 Bone::get_bone_local_root_position() const { return Vec4(0, 0, 0, 1); }
|
||||||
Vec4 Bone::get_bone_local_tip_position() const { return translationTransformCurrentJointToNext * Vec4(0, 0, 0, 1); }
|
Vec4 Bone::get_bone_local_tip_position() const { return translationTransformCurrentJointToNext * Vec4(0, 0, 0, 1); }
|
|
@ -12,176 +12,84 @@
|
||||||
#include <cgv/base/find_action.h>
|
#include <cgv/base/find_action.h>
|
||||||
|
|
||||||
#include "math_helper.h"
|
#include "math_helper.h"
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
using namespace cgv::utils;
|
using namespace cgv::utils;
|
||||||
|
|
||||||
cgv::render::shader_program Mesh::prog;
|
cgv::render::shader_program Mesh::prog;
|
||||||
|
|
||||||
// The constructor of this class
|
// The constructor of this class
|
||||||
SkeletonViewer::SkeletonViewer(DataStore *data)
|
SkeletonViewer::SkeletonViewer(DataStore* data)
|
||||||
: node("Skeleton Viewer"), data(data)
|
: node("Skeleton Viewer"), data(data)
|
||||||
|
, animation(nullptr), animationTime(0)
|
||||||
{
|
{
|
||||||
connect(data->skeleton_changed, this, &SkeletonViewer::skeleton_changed);
|
connect(data->skeleton_changed, this, &SkeletonViewer::skeleton_changed);
|
||||||
|
|
||||||
connect(get_animation_trigger().shoot, this, &SkeletonViewer::timer_event);
|
connect(get_animation_trigger().shoot, this, &SkeletonViewer::timer_event);
|
||||||
|
|
||||||
for (int i = 0; i < SKELETON_DEPTH; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
colors[i][j] = static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
frame = 0;
|
|
||||||
inc_frame = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double winkel_to_bogenmass(float v)
|
|
||||||
{
|
|
||||||
return (v * 2 * PI) / 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_dof(Bone *node, Vec4 start_point)
|
|
||||||
{
|
|
||||||
|
|
||||||
for (int i = 0; i < node->dof_count(); i++)
|
|
||||||
{
|
|
||||||
|
|
||||||
Vec3 point_joint = Vec3(start_point.x(), start_point.y(), start_point.z());
|
|
||||||
|
|
||||||
auto bonelength = node->get_length();
|
|
||||||
|
|
||||||
double lower_limit = node->get_dof(i)->get_lower_limit();
|
|
||||||
double upper_limit = node->get_dof(i)->get_upper_limit();
|
|
||||||
|
|
||||||
// lowerlimit
|
|
||||||
auto bog_lower_limit = winkel_to_bogenmass(lower_limit);
|
|
||||||
auto tan_lower_limit = std::tan(bog_lower_limit);
|
|
||||||
auto cos_lower_limit = std::cos(bog_lower_limit);
|
|
||||||
|
|
||||||
// upperlimit
|
|
||||||
auto bog_upper_limit = winkel_to_bogenmass(upper_limit);
|
|
||||||
auto tan_upper_limit = std::tan(bog_upper_limit);
|
|
||||||
auto cos_upper_limit = std::cos(bog_upper_limit);
|
|
||||||
|
|
||||||
auto pt_min = bonelength * cos_lower_limit;
|
|
||||||
auto pt_max = bonelength * cos_upper_limit;
|
|
||||||
|
|
||||||
glBegin(GL_TRIANGLE_STRIP);
|
|
||||||
|
|
||||||
if (node->get_dof(i)->get_name() == "X-Rotation")
|
|
||||||
{
|
|
||||||
|
|
||||||
// drawing x movement (local)
|
|
||||||
glColor4f(0, 128, 0, 128);
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y(), point_joint.z());
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y() - 5, point_joint.z() + pt_max);
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y() - 5, point_joint.z() - pt_min);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if(node->get_dof(i)->get_name() == "Y-Rotation") {
|
|
||||||
// drawing y movement (local)
|
|
||||||
glColor4f(0, 128, 0, 128);
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y(), point_joint.z());
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y()+pt_max, point_joint.z());
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y()-pt_min, point_joint.z());
|
|
||||||
std::cout « "X:" « point_joint.x() « " Y:" « point_joint.y()+pt_max « " Z:" « point_joint.z() « std::endl;
|
|
||||||
std::cout « pt_max « std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(node->get_dof(i)->get_name() == "Z-Rotation") {
|
|
||||||
// drawing z movement (local)
|
|
||||||
glColor4f(0, 128, 0, 128);
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y(), point_joint.z());
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y(), point_joint.z()+pt_max);
|
|
||||||
glVertex3f(point_joint.x(), point_joint.y(), point_joint.z()-pt_min);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
// drawing y movement (local)
|
|
||||||
glColor4f(128, 0, 0, 128);
|
|
||||||
glVertex3f(start_point.x(), start_point.y(), start_point.z());
|
|
||||||
glVertex3f(end_point.x(), end_point.y() - 5, end_point.z());
|
|
||||||
glVertex3f(end_point.x(), end_point.y() + 5, end_point.z());
|
|
||||||
|
|
||||||
// drawing z movement (local)
|
|
||||||
glColor4f(0, 0, 128, 128);
|
|
||||||
glVertex3f(start_point.x(), start_point.y(), start_point.z());
|
|
||||||
glVertex3f(end_point.x(), end_point.y(), end_point.z() - 5);
|
|
||||||
glVertex3f(end_point.x() + 5, end_point.y(), end_point.z() + 5);
|
|
||||||
*/
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//draws a part of a skeleton, represented by the given root node
|
//draws a part of a skeleton, represented by the given root node
|
||||||
void SkeletonViewer::draw_skeleton_subtree(Bone *node, const Mat4 &global_to_parent_local, context &c, int depth)
|
void SkeletonViewer::draw_skeleton_subtree(Bone* node, const Mat4& global_to_parent_local, context& c, int level, bool arrows, bool indicators)
|
||||||
{
|
{
|
||||||
//Task: Draw skeleton
|
auto global_to_current_local = global_to_parent_local * node->calculate_transform_prev_to_current_with_dofs();
|
||||||
if (frame < animations.size())
|
auto my_root_position = global_to_current_local * node->get_bone_local_root_position();
|
||||||
|
auto my_tip_position = global_to_current_local * node->get_bone_local_tip_position();
|
||||||
|
if (arrows)
|
||||||
{
|
{
|
||||||
auto ¤t_step = animations[frame];
|
const GLubyte colors[][3] =
|
||||||
auto it = current_step.find(node->get_name());
|
|
||||||
|
|
||||||
if (it != current_step.end())
|
|
||||||
{
|
{
|
||||||
std::vector<float> &values = it->second;
|
{ 27,158,119 },
|
||||||
|
{ 217,95,2 },
|
||||||
if (values.size() == node->dof_count())
|
{ 117,112,179 },
|
||||||
{
|
{ 231,41,138 },
|
||||||
for (int i = 0; i < values.size(); i++)
|
{ 102,166,30 },
|
||||||
{
|
{ 230,171,2 },
|
||||||
node->get_dof(i)->set_value(values[i]);
|
{ 166,118,29 },
|
||||||
}
|
};
|
||||||
}
|
glColor3ubv(colors[level % 7]);
|
||||||
}
|
c.tesselate_arrow(cgv::math::fvec<double, 3u>(my_root_position.x(), my_root_position.y(), my_root_position.z()),
|
||||||
|
cgv::math::fvec<double, 3u>(my_tip_position.x(), my_tip_position.y(), my_tip_position.z()), 0.1, 2.0, 0.5);
|
||||||
}
|
}
|
||||||
|
Mat4 dof_matrix = global_to_parent_local * node->calculate_transform_prev_to_current_without_dofs();
|
||||||
Mat4 local_transform = global_to_parent_local * node->calculate_transform_prev_to_current_with_dofs();
|
float indicatorSize = (data->get_skeleton()->getMax() - data->get_skeleton()->getMin()).length() * 0.05f;
|
||||||
|
//draw indicators for dofs
|
||||||
Vec4 zero = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
if (indicators)
|
||||||
|
|
||||||
Vec4 p1 = global_to_parent_local * zero;
|
|
||||||
Vec4 p2 = local_transform * zero;
|
|
||||||
|
|
||||||
Vec3 p1_v3 = Vec3(p1.x(), p1.y(), p1.z());
|
|
||||||
Vec3 p2_v3 = Vec3(p2.x(), p2.y(), p2.z());
|
|
||||||
|
|
||||||
glColor3f(colors[depth][0], colors[depth][1], colors[depth][2]);
|
|
||||||
c.tesselate_arrow(p1_v3, p2_v3);
|
|
||||||
|
|
||||||
draw_dof(node, p1);
|
|
||||||
|
|
||||||
depth++;
|
|
||||||
|
|
||||||
for (int i = 0; i < node->childCount(); i++)
|
|
||||||
{
|
{
|
||||||
draw_skeleton_subtree(node->child_at(i), local_transform, c, depth);
|
glDepthMask(false);
|
||||||
|
int i = 0;
|
||||||
|
for (int i = 0; i < node->dof_count(); ++i)
|
||||||
|
{
|
||||||
|
auto t = node->get_dof(i);
|
||||||
|
glPushMatrix();
|
||||||
|
glMultMatrixf(dof_matrix);
|
||||||
|
glColor4f(0, 1, 0, 0.2f);
|
||||||
|
t->drawIndicator(indicatorSize);
|
||||||
|
glColor4f(0.5f, 1, 0.5f, 1);
|
||||||
|
t->drawActualIndicator(indicatorSize);
|
||||||
|
glPopMatrix();
|
||||||
|
dof_matrix = dof_matrix * node->get_dof(i)->calculate_matrix();
|
||||||
|
}
|
||||||
|
glDepthMask(true);
|
||||||
|
}
|
||||||
|
int n = node->childCount();
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
auto child = node->child_at(i);
|
||||||
|
draw_skeleton_subtree(child, global_to_current_local, c, level + 1, arrows, indicators);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonViewer::timer_event(double, double dt)
|
void SkeletonViewer::timer_event(double, double dt)
|
||||||
{
|
{
|
||||||
/*Task: Implement animation */
|
if (animation && playing)
|
||||||
|
{
|
||||||
|
animationTime += dt;
|
||||||
|
int frame = (int)std::round(animationTime * 120.0) % animation->frame_count();
|
||||||
|
animation->apply_frame(frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonViewer::start_animation()
|
void SkeletonViewer::start_animation() { playing = true; }
|
||||||
{
|
void SkeletonViewer::stop_animation() { playing = false; }
|
||||||
frame = 0;
|
|
||||||
inc_frame = true;
|
|
||||||
post_redraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkeletonViewer::stop_animation()
|
|
||||||
{
|
|
||||||
inc_frame = false;
|
|
||||||
//Task: Implement animation
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkeletonViewer::skeleton_changed(std::shared_ptr<Skeleton> s)
|
void SkeletonViewer::skeleton_changed(std::shared_ptr<Skeleton> s)
|
||||||
{
|
{
|
||||||
|
@ -192,10 +100,9 @@ void SkeletonViewer::skeleton_changed(std::shared_ptr<Skeleton> s)
|
||||||
generate_tree_view_nodes();
|
generate_tree_view_nodes();
|
||||||
|
|
||||||
//Fit view to skeleton
|
//Fit view to skeleton
|
||||||
std::vector<cgv::render::view *> view_ptrs;
|
std::vector<cgv::render::view*> view_ptrs;
|
||||||
cgv::base::find_interface<cgv::render::view>(get_node(), view_ptrs);
|
cgv::base::find_interface<cgv::render::view>(get_node(), view_ptrs);
|
||||||
if (view_ptrs.empty())
|
if (view_ptrs.empty()) {
|
||||||
{
|
|
||||||
// If there is no view, we cannot update it
|
// If there is no view, we cannot update it
|
||||||
cgv::gui::message("could not find a view to adjust!!");
|
cgv::gui::message("could not find a view to adjust!!");
|
||||||
}
|
}
|
||||||
|
@ -213,7 +120,7 @@ void SkeletonViewer::skeleton_changed(std::shared_ptr<Skeleton> s)
|
||||||
post_redraw();
|
post_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonViewer::recursive_connect_signals(Bone *b)
|
void SkeletonViewer::recursive_connect_signals(Bone* b)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < b->dof_count(); ++i)
|
for (int i = 0; i < b->dof_count(); ++i)
|
||||||
connect(b->get_dof(i)->changed_signal, this, &SkeletonViewer::dof_changed);
|
connect(b->get_dof(i)->changed_signal, this, &SkeletonViewer::dof_changed);
|
||||||
|
@ -239,7 +146,7 @@ void SkeletonViewer::generate_tree_view_nodes()
|
||||||
generate_tree_view_nodes(tree_view, data->get_skeleton()->get_root());
|
generate_tree_view_nodes(tree_view, data->get_skeleton()->get_root());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonViewer::generate_tree_view_nodes(gui_group_ptr parent, Bone *bone)
|
void SkeletonViewer::generate_tree_view_nodes(gui_group_ptr parent, Bone* bone)
|
||||||
{
|
{
|
||||||
if (bone->childCount() == 0)
|
if (bone->childCount() == 0)
|
||||||
{
|
{
|
||||||
|
@ -259,7 +166,7 @@ void SkeletonViewer::generate_tree_view_nodes(gui_group_ptr parent, Bone *bone)
|
||||||
|
|
||||||
void SkeletonViewer::start_choose_base()
|
void SkeletonViewer::start_choose_base()
|
||||||
{
|
{
|
||||||
Bone *b = data->get_endeffector();
|
Bone* b = data->get_endeffector();
|
||||||
data->set_endeffector(nullptr);
|
data->set_endeffector(nullptr);
|
||||||
data->set_base(b);
|
data->set_base(b);
|
||||||
}
|
}
|
||||||
|
@ -270,7 +177,7 @@ void SkeletonViewer::tree_selection_changed(base_ptr p, bool select)
|
||||||
|
|
||||||
if (select)
|
if (select)
|
||||||
{
|
{
|
||||||
Bone *bone = gui_to_bone.at(p);
|
Bone* bone = gui_to_bone.at(p);
|
||||||
generate_bone_gui(bone);
|
generate_bone_gui(bone);
|
||||||
data->set_endeffector(bone);
|
data->set_endeffector(bone);
|
||||||
}
|
}
|
||||||
|
@ -346,58 +253,22 @@ void SkeletonViewer::load_animation()
|
||||||
std::string filename = cgv::gui::file_open_dialog("Open", "Animation File (*.amc):*.amc");
|
std::string filename = cgv::gui::file_open_dialog("Open", "Animation File (*.amc):*.amc");
|
||||||
if (!filename.empty())
|
if (!filename.empty())
|
||||||
{
|
{
|
||||||
animations.clear();
|
if (animation)
|
||||||
|
|
||||||
std::ifstream file(filename);
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
int current_index = -1;
|
|
||||||
|
|
||||||
while (std::getline(file, line))
|
|
||||||
{
|
{
|
||||||
if (line[0] == '#' || line[0] == ':')
|
delete animation;
|
||||||
{
|
animation = nullptr;
|
||||||
continue;
|
}
|
||||||
}
|
auto a = new Animation();
|
||||||
|
if (a->read_amc_file(filename, data->get_skeleton().get()))
|
||||||
int number = 0;
|
{
|
||||||
|
animationTime = 0;
|
||||||
std::istringstream sline(line);
|
animation = a;
|
||||||
sline >> number;
|
playing = true;
|
||||||
|
}
|
||||||
if (number != 0)
|
else
|
||||||
{
|
{
|
||||||
current_index = number - 1;
|
delete a;
|
||||||
|
cgv::gui::message("Could not load specified AMC file.");
|
||||||
//std::map<std::string, std::vector<AtomicTransform *>> tmp;
|
|
||||||
std::map<std::string, std::vector<float>> tmp;
|
|
||||||
animations.emplace_back(tmp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (current_index < 0)
|
|
||||||
abort();
|
|
||||||
|
|
||||||
std::string bone_name;
|
|
||||||
std::vector<float> values;
|
|
||||||
|
|
||||||
int first_blank = line.find_first_of(" ");
|
|
||||||
bone_name = line.substr(0, first_blank);
|
|
||||||
|
|
||||||
auto ¤t_map = animations[current_index];
|
|
||||||
|
|
||||||
std::string rest = line.substr(first_blank + 1, line.size());
|
|
||||||
std::stringstream sstream(rest);
|
|
||||||
float value;
|
|
||||||
|
|
||||||
while (sstream >> value)
|
|
||||||
{
|
|
||||||
values.push_back(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// test if values alone are enough
|
|
||||||
current_map[bone_name] = values;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,28 +292,28 @@ void SkeletonViewer::create_gui()
|
||||||
auto gui_group = dock_group->add_group("", "align_group", "", "f");
|
auto gui_group = dock_group->add_group("", "align_group", "", "f");
|
||||||
|
|
||||||
connect_copy(gui_group->add_button("Load ASF skeleton", "", "\n")->click,
|
connect_copy(gui_group->add_button("Load ASF skeleton", "", "\n")->click,
|
||||||
rebind(this, &SkeletonViewer::load_skeleton));
|
rebind(this, &SkeletonViewer::load_skeleton));
|
||||||
|
|
||||||
connect_copy(gui_group->add_button("Load Animation", "", "\n")->click,
|
connect_copy(gui_group->add_button("Load Animation", "", "\n")->click,
|
||||||
rebind(this, &SkeletonViewer::load_animation));
|
rebind(this, &SkeletonViewer::load_animation));
|
||||||
|
|
||||||
connect_copy(gui_group->add_button("Start Animation", "", "\n")->click,
|
connect_copy(gui_group->add_button("Start Animation", "", "\n")->click,
|
||||||
rebind(this, &SkeletonViewer::start_animation));
|
rebind(this, &SkeletonViewer::start_animation));
|
||||||
|
|
||||||
connect_copy(gui_group->add_button("Stop Animation", "", "\n")->click,
|
connect_copy(gui_group->add_button("Stop Animation", "", "\n")->click,
|
||||||
rebind(this, &SkeletonViewer::stop_animation));
|
rebind(this, &SkeletonViewer::stop_animation));
|
||||||
|
|
||||||
connect_copy(gui_group->add_button("Choose IK Base", "", "\n")->click,
|
connect_copy(gui_group->add_button("Choose IK Base", "", "\n")->click,
|
||||||
rebind(this, &SkeletonViewer::start_choose_base));
|
rebind(this, &SkeletonViewer::start_choose_base));
|
||||||
|
|
||||||
connect_copy(gui_group->add_button("Write Pinocchio skeleton", "", "\n")->click,
|
connect_copy(gui_group->add_button("Write Pinocchio skeleton", "", "\n")->click,
|
||||||
rebind(this, &SkeletonViewer::write_pinocchio));
|
rebind(this, &SkeletonViewer::write_pinocchio));
|
||||||
|
|
||||||
connect_copy(gui_group->add_button("Load Pinocchio skeleton", "", "\n")->click,
|
connect_copy(gui_group->add_button("Load Pinocchio skeleton", "", "\n")->click,
|
||||||
rebind(this, &SkeletonViewer::load_pinocchio));
|
rebind(this, &SkeletonViewer::load_pinocchio));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonViewer::generate_bone_gui(Bone *bone)
|
void SkeletonViewer::generate_bone_gui(Bone* bone)
|
||||||
{
|
{
|
||||||
// Add bone-specific gui elements to bone_group.
|
// Add bone-specific gui elements to bone_group.
|
||||||
// Use the layout "\n" to specify vertical alignment
|
// Use the layout "\n" to specify vertical alignment
|
||||||
|
@ -458,7 +329,7 @@ void SkeletonViewer::generate_bone_gui(Bone *bone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonViewer::draw(context &c)
|
void SkeletonViewer::draw(context& c)
|
||||||
{
|
{
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
|
@ -466,11 +337,16 @@ void SkeletonViewer::draw(context &c)
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||||
|
|
||||||
if (data->get_skeleton() != nullptr)
|
if (data->get_skeleton() != nullptr)
|
||||||
draw_skeleton_subtree(data->get_skeleton()->get_root(), data->get_skeleton()->get_origin(), c, 0);
|
{
|
||||||
|
glEnable(GL_LIGHTING);
|
||||||
if (inc_frame)
|
glEnable(GL_CULL_FACE);
|
||||||
frame++;
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
if (frame >= animations.size())
|
draw_skeleton_subtree(data->get_skeleton()->get_root(), data->get_skeleton()->get_origin(), c, 0, true, false);
|
||||||
frame = 0;
|
glDisable(GL_LIGHTING);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||||
|
draw_skeleton_subtree(data->get_skeleton()->get_root(), data->get_skeleton()->get_origin(), c, 0, false, true);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,33 +21,25 @@ using namespace cgv::math;
|
||||||
using namespace cgv::render;
|
using namespace cgv::render;
|
||||||
using namespace cgv::utils;
|
using namespace cgv::utils;
|
||||||
|
|
||||||
#define SKELETON_DEPTH 10
|
|
||||||
|
|
||||||
class SkeletonViewer : public node, public drawable, public provider
|
class SkeletonViewer : public node, public drawable, public provider
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
DataStore *data;
|
DataStore* data;
|
||||||
gui_group_ptr tree_view;
|
gui_group_ptr tree_view;
|
||||||
gui_group_ptr bone_group;
|
gui_group_ptr bone_group;
|
||||||
|
|
||||||
std::vector<std::map<std::string, std::vector<float>>> animations;
|
|
||||||
float colors[SKELETON_DEPTH][3];
|
|
||||||
|
|
||||||
// Maps gui elements in the tree view to a specific bone
|
// Maps gui elements in the tree view to a specific bone
|
||||||
std::map<base_ptr, Bone *> gui_to_bone;
|
std::map<base_ptr, Bone*> gui_to_bone;
|
||||||
|
|
||||||
bool inc_frame;
|
|
||||||
int frame;
|
|
||||||
|
|
||||||
// slot for the signal
|
// slot for the signal
|
||||||
void timer_event(double, double dt);
|
void timer_event(double, double dt);
|
||||||
void skeleton_changed(std::shared_ptr<Skeleton>);
|
void skeleton_changed(std::shared_ptr<Skeleton>);
|
||||||
|
|
||||||
void generate_tree_view_nodes();
|
void generate_tree_view_nodes();
|
||||||
void generate_tree_view_nodes(gui_group_ptr parent, Bone *bone);
|
void generate_tree_view_nodes(gui_group_ptr parent, Bone* bone);
|
||||||
|
|
||||||
void tree_selection_changed(base_ptr p, bool select);
|
void tree_selection_changed(base_ptr p, bool select);
|
||||||
void generate_bone_gui(Bone *bone);
|
void generate_bone_gui(Bone* bone);
|
||||||
|
|
||||||
void load_skeleton();
|
void load_skeleton();
|
||||||
void write_pinocchio();
|
void write_pinocchio();
|
||||||
|
@ -55,22 +47,27 @@ class SkeletonViewer : public node, public drawable, public provider
|
||||||
void load_animation();
|
void load_animation();
|
||||||
void start_choose_base();
|
void start_choose_base();
|
||||||
|
|
||||||
void draw_skeleton_subtree(Bone *node, const Mat4 &global_to_parent_local, context &c, int depth);
|
void draw_skeleton_subtree(Bone* node, const Mat4& global_to_parent_local, context& c, int level, bool arrows, bool indicators);
|
||||||
|
|
||||||
void dof_changed(double new_value);
|
void dof_changed(double new_value);
|
||||||
void recursive_connect_signals(Bone *b);
|
void recursive_connect_signals(Bone* b);
|
||||||
|
|
||||||
|
Animation* animation;
|
||||||
|
double animationTime;
|
||||||
|
bool playing;
|
||||||
|
|
||||||
void start_animation();
|
void start_animation();
|
||||||
void stop_animation();
|
void stop_animation();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// The constructor of this class
|
// The constructor of this class
|
||||||
SkeletonViewer(DataStore *);
|
SkeletonViewer(DataStore*);
|
||||||
|
|
||||||
// Create the gui elements
|
// Create the gui elements
|
||||||
void create_gui();
|
void create_gui();
|
||||||
// Draw the scene
|
// Draw the scene
|
||||||
void draw(context &c);
|
void draw(context& c);
|
||||||
|
|
||||||
std::string get_parent_type() const;
|
std::string get_parent_type() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,11 @@ using namespace cgv::base;
|
||||||
|
|
||||||
struct Initializer
|
struct Initializer
|
||||||
{
|
{
|
||||||
DataStore *data;
|
DataStore* data;
|
||||||
|
|
||||||
Initializer()
|
Initializer()
|
||||||
{
|
{
|
||||||
//register_object(base_ptr(new CGVDemo()), "");
|
|
||||||
|
|
||||||
data = new DataStore();
|
data = new DataStore();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue