-
-
Save mihow/4fb0735a11113ab8a56446cb634583cc to your computer and use it in GitHub Desktop.
3D cubes animation with PyODE and Vapory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Physics simulation with PyODE followed by a (basic) rendering with Vapory | |
See the result here: http://i.imgur.com/TdhxwGz.gifv | |
Zulko 2014 | |
This script is placed in the Public Domain (Licence Creative Commons 0) | |
""" | |
# =============== FIRST PART : SIMULATION WITH PyODE | |
import ode | |
lx, ly, lz, density = 1.0, 1.0, 1.0, 1.0 | |
world = ode.World() | |
world.setGravity( (0,-9.81,0) ) | |
world.setCFM(1E-6) | |
space = ode.Space() | |
contactgroup = ode.JointGroup() | |
geoms = [] | |
def near_callback(args, geom1, geom2): | |
"""Callback function for the collide() method below. | |
This function checks if the given geoms do collide and | |
creates contact joints if they do. | |
""" | |
contacts = ode.collide(geom1, geom2) | |
world,contactgroup = args | |
for c in contacts: | |
c.setBounce(0.01) | |
c.setMu(60000) | |
j = ode.ContactJoint(world, contactgroup, c) | |
j.attach(geom1.getBody(), geom2.getBody()) | |
def new_cube(xyz): | |
""" Creates a new PyODE cude at position (x,y,z) """ | |
body = ode.Body(world) | |
M = ode.Mass() | |
M.setBox(density, lx, ly, lz) | |
body.setMass(M) | |
body.shape = "box" | |
body.boxsize = (lx, ly, lz) | |
body.setPosition(xyz) | |
geom = ode.GeomBox(space, lengths=body.boxsize) | |
geom.setBody(body) | |
geoms.append(geom) # avoids that geom gets trashed | |
return body | |
# The objects of the scene: | |
floor = ode.GeomPlane(space, (0,1,0), 0) | |
cubes = [new_cube(xyz) for xyz in | |
[(0.5,3,0.5),(0.5,4,0),(0,5,0),(-0.5,6,0), | |
(-0.5,7,-0.5),(0,8,0.5)]] | |
# Start the simulation ! | |
t = 0.0 | |
dt = 0.005 | |
duration = 4.0 | |
trajectories = [] | |
while t<duration: | |
trajectories.append([(c.getPosition(), c.getRotation()) | |
for c in cubes]) | |
space.collide((world,contactgroup), near_callback) | |
world.step(dt) | |
contactgroup.empty() | |
t+=dt | |
# =============== SECOND PART : RENDERING WITH VAPORY | |
from moviepy.editor import VideoClip, ipython_display | |
from vapory import * | |
light = LightSource( [10,10,10], 'color', [3,3,3], | |
'parallel', 'point_at', [0, 0, 0]) | |
ground = Plane([0,1,0],0, Texture('Rosewood')) | |
def vapory_box(xyz, R): | |
""" Draws a box with at the given position and rotation""" | |
return Box([-lx/2, -ly/2, -lz/2], [lx/2, ly/2, lz/2], | |
Texture('T_Ruby_Glass'), Interior('ior',4), | |
'matrix', R+xyz) | |
def make_frame(t): | |
""" Returns the image of the scene rendered at time t """ | |
boxes = [vapory_box(position, rotation) | |
for (position, rotation) in trajectories[int(t/dt)]] | |
scene = Scene( Camera("location", [0,3,-4], "look_at", [0,0,0]), | |
[light, ground, Background("White")] + boxes, | |
included=["colors.inc", "textures.inc", "glass.inc"]) | |
return scene.render(height=300, width=400, antialiasing=0.0001) | |
clip = VideoClip(make_frame, duration=duration) | |
clip.write_videofile("pyODE.avi", codec='png', fps=20) # lossless format |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment