Skip to content

Commit 030479c

Browse files
authored
Merge pull request #15 from rdeits/animation
support animations with vis.set_animation()
2 parents d1b444d + 1f5abb9 commit 030479c

File tree

9 files changed

+534
-8
lines changed

9 files changed

+534
-8
lines changed

animation_demo.ipynb

+268
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# MeshCat Animations\n",
8+
"\n",
9+
"MeshCat.jl also provides an animation interface, built on top of the [three.js animation system](https://threejs.org/docs/#manual/introduction/Animation-system). While it is possible to construct animation clips and tracks manually, just as you would in Three.js, it's generally easier to use the MeshCat `Animation` type.\n",
10+
"\n",
11+
"Let's show off building a simple animation. We first have to create our scene: "
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": 1,
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"import meshcat\n",
21+
"from meshcat.geometry import Box"
22+
]
23+
},
24+
{
25+
"cell_type": "code",
26+
"execution_count": 2,
27+
"metadata": {},
28+
"outputs": [
29+
{
30+
"name": "stdout",
31+
"output_type": "stream",
32+
"text": [
33+
"You can open the visualizer by visiting the following URL:\n",
34+
"http://127.0.0.1:7000/static/\n"
35+
]
36+
}
37+
],
38+
"source": [
39+
"vis = meshcat.Visualizer()"
40+
]
41+
},
42+
{
43+
"cell_type": "code",
44+
"execution_count": 3,
45+
"metadata": {},
46+
"outputs": [],
47+
"source": [
48+
"## To open the visualizer in a new browser tab, do: \n",
49+
"# vis.open()\n",
50+
"\n",
51+
"## To open the visualizer inside this jupyter notebook, do: \n",
52+
"# vis.jupyter_cell()"
53+
]
54+
},
55+
{
56+
"cell_type": "code",
57+
"execution_count": 4,
58+
"metadata": {},
59+
"outputs": [],
60+
"source": [
61+
"vis[\"box1\"].set_object(Box([0.1, 0.2, 0.3]))"
62+
]
63+
},
64+
{
65+
"cell_type": "markdown",
66+
"metadata": {},
67+
"source": [
68+
"### Building an Animation\n",
69+
"\n",
70+
"We construct an animation by first creating a blank `Animation()` object. We can then use the `at_frame` method to set properties or transforms of the animation at specific frames of the animation. Three.js will automatically interpolate between whatever values we provide. \n",
71+
"\n",
72+
"For example, let's animate moving the box from [0, 0, 0] to [0, 1, 0]: "
73+
]
74+
},
75+
{
76+
"cell_type": "code",
77+
"execution_count": 5,
78+
"metadata": {},
79+
"outputs": [],
80+
"source": [
81+
"from meshcat.animation import Animation\n",
82+
"import meshcat.transformations as tf"
83+
]
84+
},
85+
{
86+
"cell_type": "code",
87+
"execution_count": 6,
88+
"metadata": {},
89+
"outputs": [],
90+
"source": [
91+
"anim = Animation()\n",
92+
"\n",
93+
"with anim.at_frame(vis, 0) as frame:\n",
94+
" # `frame` behaves like a Visualizer, in that we can\n",
95+
" # call `set_transform` and `set_property` on it, but\n",
96+
" # it just stores information inside the animation\n",
97+
" # rather than changing the current visualization\n",
98+
" frame[\"box1\"].set_transform(tf.translation_matrix([0, 0, 0]))\n",
99+
"with anim.at_frame(vis, 30) as frame:\n",
100+
" frame[\"box1\"].set_transform(tf.translation_matrix([0, 1, 0]))\n",
101+
" \n",
102+
"# `set_animation` actually sends the animation to the\n",
103+
"# viewer. By default, the viewer will play the animation\n",
104+
"# right away. To avoid that, you can also pass `play=false`. \n",
105+
"vis.set_animation(anim)"
106+
]
107+
},
108+
{
109+
"cell_type": "markdown",
110+
"metadata": {},
111+
"source": [
112+
"You should see the box slide 1 meter to the right in the viewer. If you missed the animation, you can run it again from the viewer. Click \"Open Controls\", find the \"Animations\" section, and click \"play\". "
113+
]
114+
},
115+
{
116+
"cell_type": "markdown",
117+
"metadata": {},
118+
"source": [
119+
"### Animating the Camera\n",
120+
"\n",
121+
"The camera is just another object in the MeshCat scene. To set its transform, we just need to index into the visualizer with the right path (note the leading `/`):"
122+
]
123+
},
124+
{
125+
"cell_type": "code",
126+
"execution_count": 7,
127+
"metadata": {},
128+
"outputs": [],
129+
"source": [
130+
"vis[\"/Cameras/default\"].set_transform(tf.translation_matrix([0, 0, 1]))"
131+
]
132+
},
133+
{
134+
"cell_type": "markdown",
135+
"metadata": {},
136+
"source": [
137+
"To animate the camera, we just have to do that same kind of `settransform!` to individual frames in an animation: "
138+
]
139+
},
140+
{
141+
"cell_type": "code",
142+
"execution_count": 8,
143+
"metadata": {},
144+
"outputs": [],
145+
"source": [
146+
"anim = Animation()\n",
147+
"\n",
148+
"with anim.at_frame(vis, 0) as frame:\n",
149+
" frame[\"/Cameras/default\"].set_transform(tf.translation_matrix([0, 0, 0]))\n",
150+
"with anim.at_frame(vis, 30) as frame:\n",
151+
" frame[\"/Cameras/default\"].set_transform(tf.translation_matrix([0, 0, 1]))\n",
152+
"\n",
153+
"# we can repeat the animation playback with the \n",
154+
"# repetitions argument:\n",
155+
"vis.set_animation(anim, repetitions=2)"
156+
]
157+
},
158+
{
159+
"cell_type": "markdown",
160+
"metadata": {},
161+
"source": [
162+
"We can also animate object properties. For example, let's animate the camera's `zoom` property to smoothly zoom out and then back in. Note that to do this, we have to access a deeper path in the visualizer to get to the actual camera object. For more information, see: https://github.com/rdeits/meshcat#camera-control"
163+
]
164+
},
165+
{
166+
"cell_type": "code",
167+
"execution_count": 11,
168+
"metadata": {},
169+
"outputs": [],
170+
"source": [
171+
"anim = Animation()\n",
172+
"\n",
173+
"camera_path = \"/Cameras/default/rotated/<object>\"\n",
174+
"\n",
175+
"with anim.at_frame(vis, 0) as frame:\n",
176+
" frame[camera_path].set_property(\"zoom\", \"number\", 1)\n",
177+
"with anim.at_frame(vis, 30) as frame:\n",
178+
" frame[camera_path].set_property(\"zoom\", \"number\", 0.5)\n",
179+
"with anim.at_frame(vis, 60) as frame:\n",
180+
" frame[camera_path].set_property(\"zoom\", \"number\", 1)\n",
181+
" \n",
182+
"# While we're animating the camera zoom, we can also animate any other\n",
183+
"# properties we want. Let's simultaneously translate the box during \n",
184+
"# the same animation:\n",
185+
"with anim.at_frame(vis, 0) as frame:\n",
186+
" frame[\"box1\"].set_transform(tf.translation_matrix([0, -1, 0]))\n",
187+
"with anim.at_frame(vis, 60) as frame:\n",
188+
" frame[\"box1\"].set_transform(tf.translation_matrix([0, 1, 0]))\n",
189+
"\n",
190+
"vis.set_animation(anim)"
191+
]
192+
},
193+
{
194+
"cell_type": "markdown",
195+
"metadata": {},
196+
"source": [
197+
"### Recording an Animation\n",
198+
"\n",
199+
"To record an animation at a smooth, fixed frame rate, click on \"Open Controls\" in the viewer, and then go to \"Animations\" -> \"default\" -> \"Recording\" -> \"record\". This will play the entire animation, recording every frame and then let you download the resulting frames to your computer. \n",
200+
"\n",
201+
"To record activity in the MeshCat window that isn't a MeshCat animation, we suggest using a screen-capture tool like Quicktime for macOS or RecordMyDesktop for Linux. "
202+
]
203+
},
204+
{
205+
"cell_type": "markdown",
206+
"metadata": {},
207+
"source": [
208+
"### Converting the Animation into a Video\n",
209+
"\n",
210+
"Currently, meshcat can only save an animation as a `.tar` file consisting of a list of `.png` images, one for each frame. To convert that into a video, you will need to install the `ffmpeg` program, and then you can run: "
211+
]
212+
},
213+
{
214+
"cell_type": "code",
215+
"execution_count": 1,
216+
"metadata": {},
217+
"outputs": [],
218+
"source": [
219+
"from meshcat.animation import convert_frames_to_video"
220+
]
221+
},
222+
{
223+
"cell_type": "code",
224+
"execution_count": 3,
225+
"metadata": {},
226+
"outputs": [
227+
{
228+
"name": "stdout",
229+
"output_type": "stream",
230+
"text": [
231+
"Saved output as /home/rdeits/locomotion/explorations/meshcat-distro/meshcat-python/output.mp4\n"
232+
]
233+
}
234+
],
235+
"source": [
236+
"convert_frames_to_video(\"/home/rdeits/Downloads/meshcat_1528401494656.tar\", overwrite=True)"
237+
]
238+
},
239+
{
240+
"cell_type": "code",
241+
"execution_count": null,
242+
"metadata": {},
243+
"outputs": [],
244+
"source": []
245+
}
246+
],
247+
"metadata": {
248+
"kernelspec": {
249+
"display_name": "meshcat-python",
250+
"language": "python",
251+
"name": "meshcat-python"
252+
},
253+
"language_info": {
254+
"codemirror_mode": {
255+
"name": "ipython",
256+
"version": 3
257+
},
258+
"file_extension": ".py",
259+
"mimetype": "text/x-python",
260+
"name": "python",
261+
"nbconvert_exporter": "python",
262+
"pygments_lexer": "ipython3",
263+
"version": "3.5.2"
264+
}
265+
},
266+
"nbformat": 4,
267+
"nbformat_minor": 2
268+
}

src/meshcat/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from . import visualizer
66
from . import servers
77
from . import transformations
8+
from . import animation
89
from .visualizer import Visualizer
910

1011

0 commit comments

Comments
 (0)