Merge solution of task 3
This commit is contained in:
parent
d1c4a03f5e
commit
3d00ece41d
5 changed files with 207 additions and 311 deletions
BIN
04_Skinning.pdf
Normal file
BIN
04_Skinning.pdf
Normal file
Binary file not shown.
|
@ -16,14 +16,14 @@ void AtomicTransform::set_limits(double lower, double upper)
|
|||
this->value = 0;
|
||||
}
|
||||
|
||||
void AtomicTransform::set_value(const double &value, void *)
|
||||
void AtomicTransform::set_value(const double& value, void*)
|
||||
{
|
||||
this->value = value;
|
||||
changed_signal(value);
|
||||
}
|
||||
|
||||
std::string AtomicTransform::get_name() const { return title; }
|
||||
const double AtomicTransform::get_value(void *) const { return value; }
|
||||
const double AtomicTransform::get_value(void*) const { return value; }
|
||||
const double AtomicTransform::get_lower_limit() const { return lower_limit; }
|
||||
const double AtomicTransform::get_upper_limit() const { return upper_limit; }
|
||||
|
||||
|
@ -80,59 +80,41 @@ void AtomicRotationTransform::drawActualIndicator(float size)
|
|||
glEnd();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T clamp(T &v, T &c1, T &c2)
|
||||
void AtomicRotationTransform::optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse)
|
||||
{
|
||||
if (v < c1)
|
||||
return c1;
|
||||
//project vectors in the tangent plane of the axis and normalize
|
||||
Vec3 local_in_tangent_plane = local_vector - cgv::math::dot(local_vector, axis) * axis;
|
||||
auto length = local_in_tangent_plane.length();
|
||||
if (length < 0.01)
|
||||
return; //the local vector is mostly parallel to the axis; there is not much we can do
|
||||
local_in_tangent_plane.normalize();
|
||||
|
||||
if (v > c2)
|
||||
return c2;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
float angle(const Vec3 &v1, const Vec3 &v2)
|
||||
{
|
||||
return std::acos(dot(v1, v2) / (length(v1) * length(v2))) * 180.0f / PI;
|
||||
}
|
||||
|
||||
float optimize_angle(const Vec3 &v1, const Vec3 &v2)
|
||||
{
|
||||
Vec3 first_cross = cross(v1, v2);
|
||||
Vec3 second_cross = cross(v1, first_cross);
|
||||
|
||||
float plane_angle = angle(second_cross, v2);
|
||||
|
||||
if (plane_angle >= 90.0f)
|
||||
{
|
||||
return -angle(v1, v2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return angle(v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
void AtomicRotationTransform::optimize_value(const Vec3 &local_vector, const Vec3 &target, bool inverse)
|
||||
{
|
||||
/*Task: Implement parameter optimization*/
|
||||
|
||||
// optimize this that: target = this->calculate_matrix() * local_vector;
|
||||
|
||||
double result = 0.0;
|
||||
|
||||
Vec3 lp = local_vector - (dot(local_vector, axis) * axis);
|
||||
Vec3 tp = target - (dot(target, axis) * axis);
|
||||
|
||||
result = (double)angle(lp, tp);
|
||||
Vec3 target_in_tangent_plane = target - cgv::math::dot(target, axis) * axis;
|
||||
length = target_in_tangent_plane.length();
|
||||
if (length < 0.01)
|
||||
return; //the target vector is mostly parallel to the axis; there is not much we can do
|
||||
target_in_tangent_plane.normalize();
|
||||
|
||||
double optimal_value = atan2(
|
||||
cgv::math::dot(axis, cgv::math::cross(local_in_tangent_plane, target_in_tangent_plane)),
|
||||
cgv::math::dot(local_in_tangent_plane, target_in_tangent_plane)) * 180.0f / 3.1415926f;
|
||||
if (inverse)
|
||||
result = -result;
|
||||
|
||||
result = clamp(result, lower_limit, upper_limit);
|
||||
|
||||
set_value(result);
|
||||
optimal_value *= -1;
|
||||
if (optimal_value < lower_limit || optimal_value > upper_limit)
|
||||
{
|
||||
//check which limit is closer
|
||||
while (abs(upper_limit - optimal_value) > 180.0f)
|
||||
optimal_value += 360.0f * (optimal_value < upper_limit ? 1.0f : -1.0f);
|
||||
double distance_to_upper = abs(upper_limit - optimal_value);
|
||||
while (abs(lower_limit - optimal_value) > 180.0f)
|
||||
optimal_value += 360.0f * (optimal_value < lower_limit ? 1.0f : -1.0f);
|
||||
double distance_to_lower = abs(lower_limit - optimal_value);
|
||||
if (distance_to_lower < distance_to_upper)
|
||||
optimal_value = lower_limit;
|
||||
else
|
||||
optimal_value = upper_limit;
|
||||
}
|
||||
set_value(optimal_value);
|
||||
}
|
||||
|
||||
AtomicTranslationTransform::AtomicTranslationTransform(int dim)
|
||||
|
@ -150,6 +132,6 @@ Mat4 AtomicTranslationTransform::calculate_matrix()
|
|||
return result;
|
||||
}
|
||||
|
||||
void AtomicTranslationTransform::optimize_value(const Vec3 &local_vector, const Vec3 &target, bool inverse)
|
||||
void AtomicTranslationTransform::optimize_value(const Vec3& local_vector, const Vec3& target, bool inverse)
|
||||
{
|
||||
}
|
|
@ -12,199 +12,120 @@
|
|||
#include <cgv/math/inv.h>
|
||||
#include <cgv/math/mat.h>
|
||||
|
||||
Vec3 into_vec3(const Vec4 &v)
|
||||
{
|
||||
return Vec3(v.x(), v.y(), v.z());
|
||||
}
|
||||
|
||||
IKViewer::IKViewer(DataStore *data)
|
||||
IKViewer::IKViewer(DataStore* data)
|
||||
: node("IK Viewer"), data(data), modifying(false), target_position(0, 0, 0, 1), max_iterations(20)
|
||||
{
|
||||
connect(data->endeffector_changed, this, &IKViewer::endeffector_changed);
|
||||
connect(data->base_changed, this, &IKViewer::base_changed);
|
||||
}
|
||||
|
||||
void IKViewer::endeffector_changed(Bone *b)
|
||||
void IKViewer::endeffector_changed(Bone* b)
|
||||
{
|
||||
calculate_kinematic_chain(data->get_base(), data->get_endeffector());
|
||||
|
||||
post_redraw();
|
||||
}
|
||||
|
||||
void IKViewer::base_changed(Bone *b)
|
||||
void IKViewer::base_changed(Bone* b)
|
||||
{
|
||||
calculate_kinematic_chain(data->get_base(), data->get_endeffector());
|
||||
|
||||
post_redraw();
|
||||
}
|
||||
|
||||
int IKViewer::find_element(std::vector<Bone *> &v, Bone *element)
|
||||
void IKViewer::calculate_kinematic_chain(Bone* base, Bone* endeffector)
|
||||
{
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
{
|
||||
if (v[i] == element)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void IKViewer::calculate_kinematic_chain(Bone *base, Bone *endeffector)
|
||||
{
|
||||
/*Task 3.1: Calculate kinematic chain*/
|
||||
kinematic_chain.clear();
|
||||
|
||||
this->base = base;
|
||||
this->endeffector = endeffector;
|
||||
|
||||
if (!base)
|
||||
if (!base || !endeffector)
|
||||
return;
|
||||
|
||||
// gather all bones from base to root
|
||||
std::vector<Bone *> base_tree;
|
||||
|
||||
Bone *current_bone = base;
|
||||
|
||||
while (1)
|
||||
Bone *b;
|
||||
Mat4 transform_root_to_base;
|
||||
transform_root_to_base.identity();
|
||||
std::unordered_set<Bone*> base_path_to_root;
|
||||
if (base)
|
||||
{
|
||||
base_tree.emplace_back(current_bone);
|
||||
|
||||
// break if we reached base bone
|
||||
if (current_bone->get_parent() == nullptr)
|
||||
break;
|
||||
|
||||
// set next bone in hierarchy
|
||||
current_bone = current_bone->get_parent();
|
||||
}
|
||||
|
||||
// calculate base transformation
|
||||
std::list<std::shared_ptr<Transform>> base_chain;
|
||||
|
||||
for (Bone *bone : base_tree)
|
||||
{
|
||||
for (int i = bone->dof_count() - 1; i >= 0; i--)
|
||||
//traverse from base to root
|
||||
b = base;
|
||||
while (b)
|
||||
{
|
||||
base_chain.emplace_front(bone->get_dof(i));
|
||||
transform_root_to_base = b->get_translation_transform_current_joint_to_next() * transform_root_to_base;
|
||||
for (int i = b->dof_count() - 1; i >= 0; --i)
|
||||
transform_root_to_base = b->get_dof(i)->calculate_matrix() * transform_root_to_base;
|
||||
transform_root_to_base = b->get_orientation_transform_prev_joint_to_current() * transform_root_to_base;
|
||||
base_path_to_root.insert(b);
|
||||
b = b->get_parent();
|
||||
}
|
||||
|
||||
Transform *tmp = new StaticTransform(bone->calculate_transform_prev_to_current_without_dofs());
|
||||
std::shared_ptr<Transform> transform = std::shared_ptr<Transform>(tmp);
|
||||
base_chain.emplace_front(transform);
|
||||
current_base_matrix = data->get_skeleton()->get_origin() * transform_root_to_base;
|
||||
}
|
||||
|
||||
current_base_matrix.identity();
|
||||
|
||||
for (auto &transform : base_chain)
|
||||
{
|
||||
current_base_matrix = current_base_matrix * transform->calculate_matrix();
|
||||
}
|
||||
|
||||
current_base_matrix = current_base_matrix * base->get_translation_transform_current_joint_to_next();
|
||||
|
||||
if (!endeffector)
|
||||
if (!base || !endeffector)
|
||||
return;
|
||||
|
||||
// get list of bones in order of endeffector to base
|
||||
std::vector<Bone *> endeffector_tree;
|
||||
|
||||
// gather all bones from endeffector to root
|
||||
current_bone = endeffector;
|
||||
|
||||
while (1)
|
||||
{
|
||||
endeffector_tree.emplace_back(current_bone);
|
||||
|
||||
// break if we reached base bone
|
||||
if (current_bone->get_parent() == nullptr)
|
||||
break;
|
||||
|
||||
// set next bone in hierarchy
|
||||
current_bone = current_bone->get_parent();
|
||||
}
|
||||
|
||||
// add all transform from endeffector to common ancestor and to reverse base
|
||||
|
||||
// state == 0 means, iterating through endeffector_tree
|
||||
// state == 1 means, reverse iterating through base_tree
|
||||
int state = 0;
|
||||
|
||||
int endeffector_index = 0;
|
||||
int base_index = 0;
|
||||
|
||||
//TODO: check if common ancestor is visited twice
|
||||
|
||||
std::shared_ptr<Transform> static_trans = std::shared_ptr<Transform>(new StaticTransform(endeffector->get_translation_transform_current_joint_to_next()));
|
||||
kinematic_chain.emplace_front(static_trans);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (state == 0)
|
||||
{
|
||||
if (endeffector_index >= endeffector_tree.size())
|
||||
break;
|
||||
|
||||
Bone *bone = endeffector_tree[endeffector_index];
|
||||
|
||||
for (int i = bone->dof_count() - 1; i >= 0; i--)
|
||||
{
|
||||
kinematic_chain.emplace_front(bone->get_dof(i));
|
||||
}
|
||||
|
||||
Transform *tmp = new StaticTransform(bone->calculate_transform_prev_to_current_without_dofs());
|
||||
std::shared_ptr<Transform> transform = std::shared_ptr<Transform>(tmp);
|
||||
kinematic_chain.emplace_front(transform);
|
||||
|
||||
int index = find_element(base_tree, bone);
|
||||
if (index != -1)
|
||||
{
|
||||
base_index = index;
|
||||
state = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
endeffector_index++;
|
||||
}
|
||||
else if (state == 1)
|
||||
{
|
||||
if (base_index < 0)
|
||||
break;
|
||||
|
||||
Bone *bone = base_tree[base_index];
|
||||
|
||||
std::shared_ptr<Transform> inverse_static = std::shared_ptr<Transform>(new StaticTransform(inv(bone->calculate_transform_prev_to_current_without_dofs())));
|
||||
kinematic_chain.emplace_front(inverse_static);
|
||||
|
||||
for (int i = 0; i < bone->dof_count(); i++)
|
||||
{
|
||||
Transform *tmp = new InverseTransform(bone->get_dof(i));
|
||||
std::shared_ptr<Transform> inverse_dof = std::shared_ptr<Transform>(tmp);
|
||||
kinematic_chain.emplace_front(inverse_dof);
|
||||
}
|
||||
|
||||
base_index--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// can never happen, but when it does, we will know
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Transform> inverse_static = std::shared_ptr<Transform>(new StaticTransform(inv(base->get_translation_transform_current_joint_to_next())));
|
||||
kinematic_chain.emplace_front(inverse_static);
|
||||
|
||||
Mat4 t;
|
||||
current_endeffector_matrix.identity();
|
||||
kinematic_vector.clear();
|
||||
|
||||
for (auto &transform : kinematic_chain)
|
||||
kinematic_chain.clear();
|
||||
common_ancestor = nullptr;
|
||||
//traverse from endeffector to lowest common ancestor
|
||||
b = endeffector;
|
||||
while (b)
|
||||
{
|
||||
kinematic_vector.emplace_back(transform);
|
||||
current_endeffector_matrix = current_endeffector_matrix * transform->calculate_matrix();
|
||||
if (base_path_to_root.find(b) != base_path_to_root.end())
|
||||
{
|
||||
common_ancestor = b;
|
||||
break;
|
||||
}
|
||||
t = b->get_translation_transform_current_joint_to_next();
|
||||
kinematic_chain.push_front(std::make_shared<StaticTransform>(t));
|
||||
current_endeffector_matrix = t * current_endeffector_matrix;
|
||||
for (int current_dof_id = b->dof_count() - 1; current_dof_id >= 0; --current_dof_id)
|
||||
{
|
||||
auto dof = b->get_dof(current_dof_id);
|
||||
t = dof->calculate_matrix();
|
||||
kinematic_chain.push_front(dof);
|
||||
current_endeffector_matrix = t * current_endeffector_matrix;
|
||||
}
|
||||
t = b->get_orientation_transform_prev_joint_to_current();
|
||||
kinematic_chain.push_front(std::make_shared<StaticTransform>(t));
|
||||
current_endeffector_matrix = t * current_endeffector_matrix;
|
||||
b = b->get_parent();
|
||||
}
|
||||
|
||||
target_position = current_base_matrix * current_endeffector_matrix * Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
//traverse from base to lowest common ancestor
|
||||
std::deque<std::shared_ptr<Transform>> chain_base_to_ancestor;
|
||||
Mat4 matrix_base_to_ancestor; matrix_base_to_ancestor.identity();
|
||||
b = base;
|
||||
while (b)
|
||||
{
|
||||
if (b == common_ancestor)
|
||||
break;
|
||||
t = cgv::math::inv(b->get_translation_transform_current_joint_to_next());
|
||||
chain_base_to_ancestor.push_back(std::make_shared<StaticTransform>(t));
|
||||
matrix_base_to_ancestor = matrix_base_to_ancestor * t;
|
||||
for (int current_dof_id = b->dof_count() - 1; current_dof_id >= 0; --current_dof_id)
|
||||
{
|
||||
auto dof = b->get_dof(current_dof_id);
|
||||
t = cgv::math::inv(dof->calculate_matrix());
|
||||
chain_base_to_ancestor.push_back(std::make_shared<InverseTransform>(dof));
|
||||
matrix_base_to_ancestor = matrix_base_to_ancestor * t;
|
||||
}
|
||||
t = cgv::math::inv(b->get_orientation_transform_prev_joint_to_current());
|
||||
chain_base_to_ancestor.push_back(std::make_shared<StaticTransform>(t));
|
||||
matrix_base_to_ancestor = matrix_base_to_ancestor * t;
|
||||
b = b->get_parent();
|
||||
}
|
||||
current_endeffector_matrix = matrix_base_to_ancestor * current_endeffector_matrix;
|
||||
kinematic_chain.insert(kinematic_chain.begin(), chain_base_to_ancestor.begin(), chain_base_to_ancestor.end());
|
||||
//traverse from ancestor to root
|
||||
current_ancestor_matrix.identity();
|
||||
b = common_ancestor;
|
||||
while (b)
|
||||
{
|
||||
current_ancestor_matrix = b->get_translation_transform_current_joint_to_next() * current_ancestor_matrix;
|
||||
for (int i = b->dof_count() - 1; i >= 0; --i)
|
||||
current_ancestor_matrix = b->get_dof(i)->calculate_matrix() * current_ancestor_matrix;
|
||||
current_ancestor_matrix = b->get_orientation_transform_prev_joint_to_current() * current_ancestor_matrix;
|
||||
b = b->get_parent();
|
||||
}
|
||||
t = data->get_skeleton()->get_origin() * transform_root_to_base * current_endeffector_matrix;
|
||||
target_position.x() = t(0, 3);
|
||||
target_position.y() = t(1, 3);
|
||||
target_position.z() = t(2, 3);
|
||||
}
|
||||
|
||||
void IKViewer::optimize()
|
||||
|
@ -213,56 +134,51 @@ void IKViewer::optimize()
|
|||
data->dof_changed_by_ik = true;
|
||||
|
||||
auto skeleton_size = (data->get_skeleton()->getMax() - data->get_skeleton()->getMin());
|
||||
float distance_threshold = 0.0001f * std::max({skeleton_size.x(), skeleton_size.y(), skeleton_size.z()});
|
||||
float distance_threshold = 0.0001f * std::max({ skeleton_size.x(), skeleton_size.y(), skeleton_size.z() });
|
||||
|
||||
/*Task 3.3: Implement CCD */
|
||||
for (int i = 0; i < max_iterations; i++)
|
||||
//split the current matrix in:
|
||||
// before_dof -> dof -> after_dof
|
||||
|
||||
for (unsigned int iteration = 0; iteration < max_iterations; ++iteration)
|
||||
{
|
||||
int kc_size = kinematic_vector.size();
|
||||
|
||||
// reverse iterate through kinematic chain
|
||||
for (int j = kc_size - 1; j >= 0; j--)
|
||||
Mat4 after_dof;
|
||||
after_dof.identity();
|
||||
Mat4 before_dof = current_endeffector_matrix;
|
||||
Vec4 target_base_local = cgv::math::inv(current_base_matrix) * target_position;
|
||||
//start from the last bone
|
||||
for (auto it = kinematic_chain.rbegin(); it != kinematic_chain.rend(); ++it)
|
||||
{
|
||||
Mat4 before_dof = current_base_matrix;
|
||||
|
||||
for (int k = 0; k < j; k++)
|
||||
{
|
||||
before_dof = before_dof * kinematic_vector[k]->calculate_matrix();
|
||||
}
|
||||
|
||||
Mat4 after_dof;
|
||||
after_dof.identity();
|
||||
|
||||
int after_dof_index = j + 1;
|
||||
|
||||
for (int k = j + 1; k < kc_size; k++)
|
||||
{
|
||||
after_dof = after_dof * kinematic_vector[k]->calculate_matrix();
|
||||
}
|
||||
|
||||
// now we got 3 matrices
|
||||
// (1) before dof: base_matrix * kinematic_vector[0...j-1]
|
||||
// (2) dof: kinematic_vector[j]
|
||||
// (3) after_dof: kinematic_vector[j+1...kc_size-1]
|
||||
|
||||
auto v_local = after_dof * Vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
auto v_target = inv(before_dof) * target_position;
|
||||
|
||||
kinematic_vector[j]->optimize_value(into_vec3(v_local), into_vec3(v_target));
|
||||
auto t = *it;
|
||||
before_dof = before_dof * inv(t->calculate_matrix());
|
||||
Vec4 target_dof_local = inv(before_dof) * target_base_local;
|
||||
t->optimize_value(Vec3(after_dof(0, 3), after_dof(1, 3), after_dof(2, 3)), Vec3(target_dof_local));
|
||||
after_dof = t->calculate_matrix() * after_dof;
|
||||
}
|
||||
|
||||
current_endeffector_matrix.identity();
|
||||
|
||||
for (auto &transform : kinematic_chain)
|
||||
{
|
||||
current_endeffector_matrix = current_endeffector_matrix * transform->calculate_matrix();
|
||||
}
|
||||
|
||||
Vec4 current_endeffector_position = current_endeffector_matrix * endeffector->get_bone_local_tip_position();
|
||||
|
||||
if (distance_threshold >= length(current_endeffector_position - target_position))
|
||||
current_endeffector_matrix = before_dof * after_dof;
|
||||
float error = Vec3(current_endeffector_matrix(0, 3) - target_base_local.x(),
|
||||
current_endeffector_matrix(1, 3) - target_base_local.y(),
|
||||
current_endeffector_matrix(2, 3) - target_base_local.z()).length();
|
||||
if (error <= distance_threshold)
|
||||
break;
|
||||
}
|
||||
//update the origin
|
||||
//traverse from base to ancestor
|
||||
Mat4 transform_ancestor_to_base;
|
||||
transform_ancestor_to_base.identity();
|
||||
Bone* b = data->get_base();
|
||||
while (b)
|
||||
{
|
||||
if (b == common_ancestor)
|
||||
break;
|
||||
transform_ancestor_to_base = b->get_translation_transform_current_joint_to_next() * transform_ancestor_to_base;
|
||||
for (int i = b->dof_count() - 1; i >= 0; --i)
|
||||
transform_ancestor_to_base = b->get_dof(i)->calculate_matrix() * transform_ancestor_to_base;
|
||||
transform_ancestor_to_base = b->get_orientation_transform_prev_joint_to_current() * transform_ancestor_to_base;
|
||||
b = b->get_parent();
|
||||
}
|
||||
Mat4 origin_to_base = current_ancestor_matrix * transform_ancestor_to_base;
|
||||
Mat4 global_to_origin = current_base_matrix * cgv::math::inv(origin_to_base);
|
||||
data->get_skeleton()->set_origin(global_to_origin);
|
||||
|
||||
//used for correct GUI behavior
|
||||
data->dof_changed_by_ik = false;
|
||||
|
@ -294,7 +210,7 @@ void IKViewer::set_target_position_2d(int x, int y)
|
|||
int width = ctx->get_width();
|
||||
int height = ctx->get_height();
|
||||
|
||||
float proj_position[4] = {(2.0f * x) / width - 1.0f, (-2.0f * y) / height + 1.0f, z, 1.0f};
|
||||
float proj_position[4] = { (2.0f * x) / width - 1.0f, (-2.0f * y) / height + 1.0f, z, 1.0f };
|
||||
auto unprojected = inv_mvp * cgv::math::vec<float>(4, proj_position);
|
||||
unprojected *= 1.0f / unprojected.w();
|
||||
|
||||
|
@ -308,17 +224,15 @@ void IKViewer::set_target_position_2d(int x, int y)
|
|||
post_redraw();
|
||||
}
|
||||
|
||||
bool IKViewer::handle(event &e)
|
||||
{
|
||||
if (e.get_kind() == EID_MOUSE)
|
||||
{
|
||||
cgv::gui::mouse_event me = (cgv::gui::mouse_event &)e;
|
||||
|
||||
switch (me.get_action())
|
||||
{
|
||||
bool IKViewer::handle(event& e)
|
||||
{
|
||||
if (e.get_kind() == EID_MOUSE) {
|
||||
cgv::gui::mouse_event me = (cgv::gui::mouse_event&) e;
|
||||
|
||||
switch (me.get_action()) {
|
||||
case MA_PRESS:
|
||||
if (me.get_button() == MB_LEFT_BUTTON && me.get_modifiers() == EM_CTRL)
|
||||
{
|
||||
if (me.get_button() == MB_LEFT_BUTTON && me.get_modifiers() == EM_CTRL) {
|
||||
modifying = true;
|
||||
set_target_position_2d(me.get_x(), me.get_y());
|
||||
return true;
|
||||
|
@ -334,24 +248,23 @@ bool IKViewer::handle(event &e)
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void IKViewer::stream_help(std::ostream &os)
|
||||
void IKViewer::stream_help(std::ostream& os)
|
||||
{
|
||||
}
|
||||
|
||||
void IKViewer::draw(cgv::render::context &ctx)
|
||||
void IKViewer::draw(cgv::render::context& ctx)
|
||||
{
|
||||
if (!data->get_skeleton())
|
||||
return;
|
||||
|
||||
auto skeleton_size = (data->get_skeleton()->getMax() - data->get_skeleton()->getMin());
|
||||
float scale = 0.2f * std::max({skeleton_size.x(), skeleton_size.y(), skeleton_size.z()});
|
||||
float scale = 0.2f * std::max({ skeleton_size.x(), skeleton_size.y(), skeleton_size.z() });
|
||||
|
||||
glBegin(GL_LINES);
|
||||
|
||||
|
|
|
@ -25,42 +25,41 @@ using namespace cgv::utils;
|
|||
|
||||
class IKViewer : public node, public drawable, public provider, public event_handler
|
||||
{
|
||||
private:
|
||||
DataStore *data;
|
||||
private:
|
||||
DataStore* data;
|
||||
|
||||
void set_target_position_2d(int x, int y);
|
||||
|
||||
void endeffector_changed(Bone *);
|
||||
void base_changed(Bone *);
|
||||
void endeffector_changed(Bone*);
|
||||
void base_changed(Bone*);
|
||||
|
||||
int find_element(std::vector<Bone *> &v, Bone *element);
|
||||
void calculate_kinematic_chain(Bone *base, Bone *endeffector);
|
||||
void calculate_kinematic_chain(Bone* base, Bone* endeffector);
|
||||
|
||||
bool modifying; //Specifies if the user is currently modifying the IK target position
|
||||
|
||||
Vec4 target_position;
|
||||
Mat4 current_endeffector_matrix; //transform from base to endeffector
|
||||
Mat4 current_base_matrix; //transform from global origin to base
|
||||
Mat4 current_base_matrix; //transform from global origin to base
|
||||
|
||||
Bone *base;
|
||||
Bone *endeffector;
|
||||
Bone* common_ancestor; //lowest common ancestor of base and endeffector
|
||||
Mat4 current_ancestor_matrix; //transform from root to common_ancestor
|
||||
|
||||
unsigned int max_iterations;
|
||||
|
||||
std::list<std::shared_ptr<Transform>> kinematic_chain;
|
||||
std::vector<std::shared_ptr<Transform>> kinematic_vector;
|
||||
|
||||
void optimize();
|
||||
|
||||
public:
|
||||
public:
|
||||
// The constructor of this class
|
||||
IKViewer(DataStore *);
|
||||
IKViewer(DataStore*);
|
||||
|
||||
bool handle(cgv::gui::event &e);
|
||||
void stream_help(std::ostream &os);
|
||||
bool handle(cgv::gui::event& e);
|
||||
void stream_help(std::ostream& os);
|
||||
|
||||
// Create the gui elements
|
||||
void create_gui();
|
||||
// Draw the scene
|
||||
void draw(context &c);
|
||||
void draw(context& c);
|
||||
};
|
||||
|
||||
|
|
|
@ -16,10 +16,12 @@ using namespace cgv::base;
|
|||
|
||||
struct Initializer
|
||||
{
|
||||
DataStore *data;
|
||||
DataStore* data;
|
||||
|
||||
Initializer()
|
||||
{
|
||||
|
||||
|
||||
data = new DataStore();
|
||||
|
||||
register_object(base_ptr(new SkeletonViewer(data)), "");
|
||||
|
|
Loading…
Reference in a new issue