Skip to content

Commit 84acde6

Browse files
committed
Trajectoties now support spline based interpolation.
1 parent 984ae25 commit 84acde6

File tree

4 files changed

+151
-104
lines changed

4 files changed

+151
-104
lines changed

CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8)
33
project(mesh-deform)
44

55
if (WIN32)
6-
add_definitions("-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS")
6+
add_definitions("-D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_ITERATOR_DEBUG_LEVEL=0")
77
else()
88
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
99
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
@@ -56,4 +56,13 @@ if (OPENSCENEGRAPH_FOUND)
5656
${OSG_COMMON_FILES}
5757
)
5858
target_link_libraries(deform_bar deform ${DEFORM_LINK_TARGETS} ${OPENSCENEGRAPH_LIBRARIES})
59+
60+
if (SOPHUS_FOUND)
61+
add_executable(deform_trajectory
62+
examples/deform_trajectory.cpp
63+
${OSG_COMMON_FILES}
64+
)
65+
target_link_libraries(deform_trajectory deform ${DEFORM_LINK_TARGETS} ${OPENSCENEGRAPH_LIBRARIES})
66+
endif ()
67+
5968
endif()

examples/deform_trajectory.cpp

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
This file is part of mesh-deform.
3+
4+
Copyright(C) 2016 Christoph Heindl
5+
All rights reserved.
6+
7+
This software may be modified and distributed under the terms
8+
of the BSD license.See the LICENSE file for details.
9+
10+
This examples shows the deformation of a sphere like object. In this particular
11+
case a single vertex is pinned to its initial location and a harmonic motion
12+
is applied to the vertex on the opposite side of the sphere. All other vertices
13+
are unconstrained.
14+
*/
15+
16+
#define _USE_MATH_DEFINES
17+
18+
#include <deform/arap.h>
19+
#include <deform/openmesh_adapter.h>
20+
#include <deform/trajectory.h>
21+
22+
#include "osg_viewer.h"
23+
#include "example_config.h"
24+
25+
#include <Eigen/Geometry>
26+
27+
#include <string>
28+
#include <iostream>
29+
30+
31+
const std::vector<int> handles = { 8,9,10,11,15,18,19,20,21,35,38,39,40,41,51,54,55,56,57,74,75,76,77,78,79,103,104,107,108,109,110,111,112,113,114,116,123,126,127,128,129,135,136,141,142,144,145,146,147,148,149,150,151,162,163,179,182,183,184,185,195,198,199,200,201,203,205,218,219,220,221,222,223,261,262,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,315,316,324,325,342,343,351,352,357,358,360,361,362,363,364,365,366,367,378,379 };
32+
33+
34+
const std::vector<int> anchors = {0,1,2,3,4,5,6,7,12,26,27,28,29,30,33,34,46,47,48,92,93,94,95,96,97,98,99,100,101,102,105,106,115,117,118,119,120,137,152,155,158,164,165,166,167,168,169,170,171,172,173,174,177,178,190,191,192,193,194,196,197,202,204,211,226,229,232,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,269,271,275,277,278,280,284,286,287,289,293,295,332,334,338,340,380,381,382,383,384,385 };
35+
36+
37+
typedef OpenMesh::TriMesh_ArrayKernelT<> Mesh;
38+
typedef deform::OpenMeshAdapter<> Adapter;
39+
typedef deform::AsRigidAsPossibleDeformation<Adapter, double> ARAP;
40+
typedef deform::TrajectorySE3<float> Trajectory;
41+
42+
43+
void applyTransformationToHandles(const Eigen::Affine3f &delta, Mesh &mesh, ARAP &arap) {
44+
for (auto h : handles) {
45+
Mesh::VertexHandle vh = mesh.vertex_handle(h);
46+
Eigen::Vector3f v = delta * deform::convert::toEigen(mesh.point(vh));
47+
arap.setConstraint(vh.idx(), v);
48+
}
49+
}
50+
51+
52+
int main(int argc, char **argv) {
53+
54+
std::string pathToSource = std::string(DEFORM_ETC_DIR) + std::string("/bar.obj");
55+
56+
Mesh mesh;
57+
if (!OpenMesh::IO::read_mesh(mesh, pathToSource)) {
58+
std::cerr << "Failed to read mesh" << std::endl;
59+
return -1;
60+
}
61+
62+
Adapter ma(mesh);
63+
ARAP arap(ma);
64+
65+
// Set anchors.
66+
for (auto a : anchors) {
67+
Mesh::VertexHandle va = mesh.vertex_handle(a);
68+
arap.setConstraint(va.idx(), deform::convert::toEigen(mesh.point(va)));
69+
}
70+
71+
// Setup trajectory
72+
Trajectory trajectory;
73+
trajectory.addKeyPose(Trajectory::Transform::Identity());
74+
trajectory.addKeyPose(Trajectory::Transform::Identity() * Eigen::Translation3f(1.f,0.f,0.f));
75+
trajectory.addKeyPose(Trajectory::Transform::Identity() * Eigen::Translation3f(2.f, 0.f, 0.f));
76+
trajectory.addKeyPose(Trajectory::Transform::Identity() * Eigen::AngleAxisf((float)M_PI / 2.f, Eigen::Vector3f::UnitZ()) * Eigen::AngleAxisf((float)M_PI / 4.f, Eigen::Vector3f::UnitX()) * Eigen::Translation3f(2.f, 0.f, 0.f));
77+
78+
79+
80+
81+
Eigen::Affine3f prev = trajectory(0.f);
82+
83+
// Create an OSG viewer to visualize incremental deformation.
84+
double duration = 10.f;
85+
86+
deform::example::OSGViewer viewer(mesh, anchors, handles);
87+
viewer.onFrame([&](Mesh &mesh, double time) {
88+
89+
90+
double t = time / duration;
91+
if (t > 1.f)
92+
return false;
93+
94+
Trajectory::Transform transform = trajectory((float)t);
95+
applyTransformationToHandles(transform * prev.inverse(Eigen::Isometry), mesh, arap);
96+
prev = transform;
97+
98+
arap.deform(10);
99+
100+
return true;
101+
});
102+
viewer.run();
103+
104+
return 0;
105+
106+
}

inc/deform/trajectory.h

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <Eigen/Dense>
1515
#include <Eigen/Geometry>
1616
#include <Eigen/StdVector>
17+
#include <unsupported/Eigen/Splines>
1718

1819
#ifdef _WIN32
1920
#pragma warning (push)
@@ -49,81 +50,37 @@ namespace deform {
4950
/**
5051
Construct empty trajectory
5152
*/
52-
TrajectorySE3(Scalar timeStep)
53-
:_timeStep(timeStep)
54-
{
55-
_C <<
56-
6, 0, 0, 0,
57-
5, 3, -3, 1,
58-
1, 3, 3, -2,
59-
0, 0, 0, 1;
60-
_C *= Scalar(1) / 6;
61-
}
62-
63-
void addKeyframe(const Transform &transform) {
64-
_keyframes.push_back(transform);
65-
const size_t n = _keyframes.size();
66-
67-
if (n > 1) {
68-
Transform delta = _keyframes[n - 2].inverse(Eigen::Isometry) * _keyframes[n - 1];
69-
70-
SE3Group g(delta.matrix());
71-
_omega.push_back(g.log());
53+
TrajectorySE3()
54+
:_dirty(false)
55+
{}
7256

73-
if (n == 2) {
74-
_omega[0] = g.inverse().log();
75-
}
76-
} else {
77-
_omega.push_back(SE3Group::Tangent::Zero()); // Will be fixed when second keyframe is given.
78-
}
57+
void addKeyPose(const Transform &transform) {
58+
_transforms.push_back(transform);
59+
_dirty = true;
7960
}
8061

81-
Transform operator()(Scalar time) const {
82-
83-
const Scalar t0(0);
84-
const Scalar s = (time - t0) / _timeStep;
85-
86-
const int i = static_cast<int>(std::floor(s));
87-
eigen_assert(i >= 0);
62+
Transform operator()(Scalar time) {
63+
if (_dirty) {
64+
Eigen::Matrix<Scalar, 6, Eigen::Dynamic> points(6, _transforms.size());
65+
for (size_t i = 0; i < _transforms.size(); ++i) {
66+
points.col(i) = SE3Group(_transforms[i].matrix()).log();
67+
}
68+
_spline = Eigen::SplineFitting<SplineType>::Interpolate(points, 3);
69+
_dirty = false;
70+
}
8871

89-
const Scalar u = s - Scalar(i);
90-
const Eigen::Matrix<Scalar, 4, 1> b = _C * Eigen::Matrix<Scalar, 4, 1>(Scalar(1), u, u*u, u*u*u);
91-
92-
Transform trans = previousTransform(i);
93-
94-
Transform prod = Transform::Identity();
95-
for (int j = 1; j < 4; ++j) {
96-
typename SE3Group::Tangent o = omega(i + j);
97-
prod = prod * SE3Group::exp(b(j) * o).affine3();
98-
}
99-
100-
return trans * prod;
72+
SE3Group::Tangent tangent = _spline(time);
73+
return SE3Group::exp(tangent).affine3();
10174
}
10275

10376
private:
77+
typedef Eigen::Spline<Scalar, 6, 3> SplineType;
78+
typedef std::vector<Transform, Eigen::aligned_allocator<Transform> > TransformVector;
79+
80+
bool _dirty;
81+
SplineType _spline;
10482

105-
typename SE3Group::Tangent omega(int idx) const {
106-
if ((size_t)idx < _omega.size()) {
107-
return _omega[idx];
108-
} else {
109-
// Extrapolate
110-
return _omega.back();
111-
}
112-
}
113-
114-
Transform previousTransform(int idx) const {
115-
if (idx == 0) {
116-
// Extrapolate
117-
return SE3Group::exp(_omega[0]).affine3() * _keyframes[0];
118-
} else {
119-
return _keyframes[idx - 1];
120-
}
121-
}
122-
123-
Scalar _timeStep;
124-
std::vector<Transform, Eigen::aligned_allocator<Transform> > _keyframes;
125-
std::vector<typename SE3Group::Tangent, Eigen::aligned_allocator<typename SE3Group::Tangent> > _omega;
126-
Eigen::Matrix<Scalar, 4, 4> _C;
83+
TransformVector _transforms;
12784
};
12885
}
12986

tests/test_trajectory.cpp

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,47 +19,22 @@ TEST_CASE("trajectory")
1919
typedef deform::TrajectorySE3<float> Trajectory;
2020

2121

22-
Trajectory path(1.f);
22+
Trajectory path;
2323

2424
// time 0
25-
Trajectory::Transform trans = Trajectory::Transform::Identity();
26-
path.addKeyframe(trans);
25+
Trajectory::Transform pose0 = Trajectory::Transform::Identity();
26+
path.addKeyPose(pose0);
2727

28-
// time 1
29-
trans *= Eigen::Translation3f(0, 0, 1);
30-
path.addKeyframe(trans);
28+
Trajectory::Transform pose1 = Eigen::Translation3f(0, 0, 1) * pose0;
29+
path.addKeyPose(pose1);
3130

32-
// time 2
33-
trans *= Eigen::Translation3f(0, 0, 1);
34-
path.addKeyframe(trans);
31+
Trajectory::Transform pose2 = Eigen::Translation3f(0, 0, 1) * Eigen::AngleAxisf((float)M_PI / 4.f, Eigen::Vector3f::UnitX()) * pose1;
32+
path.addKeyPose(pose2);
3533

36-
// time 3
37-
trans *= Eigen::Translation3f(0, 0, 1);
38-
path.addKeyframe(trans);
34+
Trajectory::Transform pose3 = Eigen::Translation3f(0, 0, 1) * pose2;
35+
path.addKeyPose(pose3);
3936

40-
// time 4
41-
trans = trans * Eigen::Translation3f(0, 0, 1) * Eigen::AngleAxisf(M_PI / 4, Eigen::Vector3f::UnitX());
42-
std::cout << "Expected transform" << std::endl << trans.matrix() << std::endl;
43-
path.addKeyframe(trans);
44-
45-
// time 5
46-
trans *= Eigen::Translation3f(0, 0, 1);
47-
path.addKeyframe(trans);
48-
49-
// time 6
50-
trans *= Eigen::Translation3f(0, 0, 1);
51-
path.addKeyframe(trans);
52-
53-
// time 7
54-
trans *= Eigen::Translation3f(0, 0, 1);
55-
path.addKeyframe(trans);
56-
57-
// time 8
58-
trans *= Eigen::Translation3f(0, 0, 1);
59-
path.addKeyframe(trans);
60-
61-
62-
std::cout << "Transform is" << std::endl;
63-
std::cout << path(4.f).matrix() << std::endl;
37+
REQUIRE(path(0.f).matrix().isApprox(pose0.matrix(), 1e-3f));
38+
REQUIRE(path(1.f).matrix().isApprox(pose3.matrix(), 1e-3f));
6439
}
6540

0 commit comments

Comments
 (0)