Scripted Effect Workshop

http://web.netrevolution.com/gbeloin/elysiun/pw/pw_splash.png
There I am again, trying to involve your curiousity on some bit of chalenge and eye candy.
You python coders out there are invited to share your littles scripts to generate stuff on the fly, from animation to huge scene.

Ask questions, give ideas, exchange tips on this dark side of blender; python scripting.

When posting a script, put it in

 tags, try to provide a blend file, and maybe snapshots and/or a short video. How it work is always a good thing to ear about.
You can use free host such as http://www.imageshack.us/ for images
and http://putfile.com/ for video.

Have fun!

and what preytell is this script that you made that with ???

I will start This with a wave generator for object, used for the splash on top of this thread. I used an other script to generate all theses cubes also, cause there is a lot of cube involved in there, it’s a 50x50 grid.

Here is a Snapshot of the blend file

The script used to Generate the grid:

#Gabriel Beloin
#17/08/05
#Generate a matrix of cubes.

import Blender
from Blender.Object import *
from Blender import Scene

#Var:
name =		"Cube"
x_long =	50
y_long =	50
z =				0

ori = Get("Cube")
mesh = ori.getData()
sc = Scene.GetCurrent()
for y in range(y_long):
	for x in range(x_long):
		cur = New("Mesh",name)
		cur.link(mesh)
		cur.setLocation(x,y,z)
		sc.link(cur)

And the main script:

#Gabriel Beloin
#18/08/05
# script done for Framechange event purpose.

import Blender
from Blender.Object import *
import math
from math import sin,cos,tan,sqrt,pi

#Variable
name = "Cube" #The begining of the name of all object part of the matrix.
var = Get("var") #The empty used to control the solver. The location is used, so we can use the ipo to animate variables.
ra = var.loc[2] #range based on z location of empty "var" #how many waves... return 0 outbound.
he = var.loc[1] #height based on y location of empty "var" (is a multiple of 2u)
wi = var.loc[0] #width, based on x location of empty "var" (is a multiple of 2pi, a circle, which is 6.283185
spot = Get("wave") #Empty used to define the center of the wave, animate using ipo, the x,y is used.
oblist = Get()

def solve(x,y,range,height,width): #The solver... not too complex.
	a = sqrt(x**2+y**2)
	if (ra*2)*(width*(pi))<a:
		ans = 0
	else:
		ans = sin(a/width+width)*height+height
	return ans

def main(): #where action take place
	for ob in oblist:
		if ob.name[:len(name)] == name:
			z = solve(ob.loc[0]-spot.loc[0],ob.loc[1]-spot.loc[1],ra,he,wi)
			ob.setLocation(ob.loc[0],ob.loc[1],z)

main() #GO!

How it work:
When I have a grid to work on, I add this script as a scriptlink to the scene for a framechange event. At each framechange, The script run through all object and find the grid, Then it pass info to the solver, which will define if it’s in bound (if not return 0, flat to the ground) and then calculate a function to know the final value of z, which is the height of the wave at this precise moment. 2 other object are used, 2 empty. I use empties because I can animate them using ipo ans then use the result as variable in my script, so I can animate variable. This give me the chance to change to position of the center, the height and width or the wave.
The fact that the wave do a circle around the center, when it’s a simple sin function is due to the sqrt(x2+y2), the famous pytagor equation. By doing so I kind of delete the Z and just get a y=x environement. It’s like turning a rope around a central point, even if you turn, you still get a line. And then I apply the sin function on this line and get this effect. I “curve” the function as I want.

Here is a quick animation of the result.

An other little script. This is an easy one, almost same principe as the wave generator for object, but it’s a wave effect that get moved away, following a sphere :slight_smile:

Blend file

The script:

#This is a free of charge script, use it as you want.
#Gabriel Beloin
#Purpose: if linked to an objet named "Plane", 
#it will change the start of wave effect and will follow the object named Object
#14/05/04

import Blender
from Blender import *

myeff = Effect.Get("Plane2",0)

#Time to get the adresse of the sphere:
obj = Object.Get("Sphere")
vloc = obj.getLocation()

#We use x and y(0 and 1 of the vector) because it's the planar cood., dont need to know height

myeff.setStartx(vloc[0])
myeff.setStarty(vloc[1])

And an anim to show off.

Last one for today, a surface generator using mathematical function of the kind y=x.
If you like to toy around with stuff you learned in high school, then this is for you.
For now this script take 2 function and cross them so you get a 3D surface out of it.
You need to write them in good python syntax or the script will crash!
The easy example, again, is the sin function. and crossing them can give you cool patern. (used sin(x) two time, with a width of 30)
http://web.netrevolution.com/gbeloin/elysiun/pw/surfgen/sin2.png

Or crossed roots “sqrt(x)*2”:
http://web.netrevolution.com/gbeloin/elysiun/pw/surfgen/sqrt2.png

Or tan(x):
http://web.netrevolution.com/gbeloin/elysiun/pw/surfgen/tan.png
Read doc about math module, there is some more idea to work on.

import Blender
from Blender.BGL import *
from Blender.Draw import *
from Blender.NMesh import *
from math import *

#default function string
eq_yx = Create("x")
eq_yz = Create("z")
#surface to genertae
width = Create(10)
height = Create(10)

#event
E_gen = 1
E_quit = 2

print "start",Blender.sys.time()

def draw():
	global eq_yx
	global eq_yz
	global width
	global height

	glClear(GL_COLOR_BUFFER_BIT)
	glRasterPos2d(1,150)
	Text("Surface generator")
	Button("Generate",1,10,10,80,20)
	Button("Quit",2,100,10,30,20)
	eq_yx = String("y=",0,10,100,180,15,eq_yx.val,200,"Equation y=x")
	eq_yz = String("y=",0,10,50,180,15,eq_yz.val,200,"Equation y=z")
	width = Number("width=",0,200,100,100,15,width.val,0,1000,"The width of the surface")
	height = Number("height=",0,200,50,100,15,height.val,0,1000,"The height of the surface")

def event(evt,val):
	if (evt == QKEY or evt == ESCKEY and not val):
		Exit()

def bevent(evt):
	if evt == 1:
		generate()
	elif evt == 2:
		Exit()

#generation step:
#1-generate vertex from coord
#2-generate face with vertex
#3-start a new line
def generate():
	global width
	global height
	vert_line = range(width.val)
	vert_old_line = range(width.val)
	mesh = New("surface")

	#This little zplus give the modification along the z axis.
	for z in range(height.val):
		zplus = func(eq_yz,z)

		#This create a line of vertice along x, variable on y
		for x in range(width.val):
			y = func(eq_yx,x)
			y = y + zplus
			vert_line[x] = Vert(x,y,z)
			mesh.verts.append(vert_line[x])
		if z > 0:  #if it's not the first line, start making face.
			for cur in range(width.val-1):
				mesh.faces.append(Face([vert_old_line[cur],vert_old_line[cur+1],vert_line[cur+1],vert_line[cur]]))
		#swap all vert for a new line
		for cur in range(width.val):
			vert_old_line[cur] = vert_line[cur]
	PutRaw(mesh,"surface",1)

def func(eq,x):
	z = x
	finaleq = "y="+eq.val
	exec(finaleq)
	return(y)
	
Register(draw,event,bevent)

hmm, could make huge khazad dum style chasms with that gabio :smiley:

the waver script is great!
reminds of that clip of some artist with a face animation, made from nails going up and down.

I think it’s the ‘Nine Inch Nails - Only’ clip. So, this script could do a similar effect? I haven’t tried it out yet, sorry. But indeed looks nice!

yeah, it was the 9 inch nails.
but i guess you need to script a lot more to be able to get such results

Yes. Scripts for effects is usually crafted for a precise purpose. They are short, not always user-friendy and used mostly in short animation, big serious project and often in studios where there are artists but also coders how develop stuff such as scripted effects.

Ok well here is an other one I did for Ecks:

#Gabriel Beloin (c) le 9 juin 2005

#This script will select all faces pointing up(z-axis)
#and assign a random material index taken in the index list of the object
#assigned via the  "links and material" in the edit button. You just need to  
#create as many index as you want without assigning them and the script will assign it randomly on all selected faces. 
#Fun hu?
#Usage:
#1- Unselect all faces in face mode (FKEY in object mode)
#2- Go in object mode, make sure the object is the only one selected.
#3- Create material index to this object without assigning it to any face.
#4- All index under mat_min (0 if mat_min is 1) will not be used, assuming you already used it for something else. like the default material if the selection fall for this face(normal is not pointing ok).
#4- Set the limits in the *var* section

import Blender
from Blender import NMesh, Draw, Object, Noise
#*************
#Variable
#*************
limite = .5 #between 0/1. if z is under .5, it' because the face is pointing under 45 deg
mat_min = 1 #The first material in index the script will start with, let out keep some material slot out of reach of the random assignement.

mesh = Object.GetSelected()[0].data
mat = mesh.materials #all index
nofm = len(mat) #num of index
faces = mesh.faces
work = [] #list of face defined as ok to assign material to

#*************
#Code
#*************

for I in faces:
	if I.no[2] > limite:
		I.flag |= NMesh.FaceFlags["SELECT"]
		work.append(I)
for I in work:
	I.mat=(int((nofm-mat_min)*Noise.random()/1)+mat_min)
NMesh.PutRaw(mesh,mesh.name)
Draw.PupMenu("Finit%t|ok")

here is a result:
http://web.netrevolution.com/gbeloin/elysiun/pw/mat_as/snapshot.png

Other more nice use of this is to assigne a material to only one side of a really complex mesh, like texturing a city for example. :wink:

I just wanted to say that it’s great too see this kind of stuff, well commented scripts with examples -> a tutorial. I’m only just beginning to learn blender scripting and I really appreciate you to put this stuff up, I hope others will as well.

That exactly what I want to acheive. These scripts are not complicated at all. But you can get stuff with them you couldn’t just doing it by hand. IMO all artist should be able to scratch some lines here and there to kind of level up the freedom you can have when blending. And by providing simple example it give everyone ideas on what you could do someday you are stuck(or bored).

Ok that one is a cool one: Rigid body for the gang.
I’ve been studying ODE, blODEd script, pyODE and did some tutorials in python & blender and came up with the following result.

You need pyODE and a full install of python.

A simple way to get rigidbody simulation.
Concept is simple the gasp. Reading the ODE manual give instant hint about a way to easily get rigid body simulation.
The first things to know:
a simulation engine have the following structure:


A typical simulation will proceed like this:

   1. Create a dynamics world.
   2. Create bodies in the dynamics world.
   3. Set the state (position etc) of all bodies.
   4. Create joints in the dynamics world.
   5. Attach the joints to the bodies.
   6. Set the parameters of all joints.
   7. Create a collision world and collision geometry objects, as necessary.
   8. Create a joint group to hold the contact joints.
   9. Loop:
         1. Apply forces to the bodies as necessary.
         2. Adjust the joint parameters as necessary.
         3. Call collision detection.
         4. Create a contact joint for every collision point, and put it in the contact joint group.
         5. Take a simulation step.
         6. Remove all joints in the contact joint group. 
  10. Destroy the dynamics and collision worlds. 

And here is the basic concept of ODE:
-You have a world, which define primary information such as gravity, error correction and in generale way contain all bodies and joins. object from different world cannot collide.
-Then in a world the is a space. a Space is there just to optimise simulation speed, it contain other bodies and make group of bodies that may probably not always need to be calculated together. object from multiple space can collide, but if they don’t. you have half less simulation to do.
-Then you create bodies. A body is a point in the world, containting position, scale, rotation information, the mass and the center of mass. a body could represent onlyan object in blender and not the data it containt.
-After you have bodies you create joints(or constraints), quoting the ODE manual:

In real life a joint is something like a hinge, that is used to connect two objects. In ODE a joint is very similar: It is a relationship that is enforced between two bodies so that they can only have certain positions and orientations relative to each other.
Think about a necklass. every little ball is connected to the next one in a way that it stay on your shoulder.
-After that you create geometries (or geoms) that define what a body look like and link the body to the geom. you can have a plane, cube, sphere, caped tube, and a geoms made of triangular face(like a mesh).
-Then when all parameter for contact is made, you enter the simulation loop, which will turn 24 time a seconde (or each frame if you want :slight_smile: ) Some system may turn 2 time by frame for better result. at each frame a snapshot of all bodies’s positions is taken and returned to the system (here blender). at each turn the collision routine look at all pair of bodies and if an overlapping of bodies is detected in a space, the pair of objects is sent to a collision callback, which then take a deep look at it and decide what to do with this pair of bodies, return the result(the move and rotation for the next step… blabla) as a joint (constraint) that will make them consider each other and stop them going further(the ball will change direction when it hit a wall). The joint just created was part of a joint group especially for collision. What it do is after each loop, this group is deleted, so next time it has to do it all over again, as the collision append only once(if not, the ball will stick to wall, lol).
Hope it make sens a bit.

Here is the result:
tutorial 2:
Click here to watch Join_demo0001_0120

# pyODE example 2: Connecting bodies with joints
import Blender
from Blender import BGL, Draw, Object, Ipo
from Blender.BGL import *
from Blender.Draw import *
import ode

# Create an Ipo Object
def makeipo(name):
   print "Creating new IPO "+name
   ipo = Ipo.New('Object', name)
   Locx = ipo.addCurve('LocX')
   Locy = ipo.addCurve('LocY')
   Locz = ipo.addCurve('LocZ')
   Rotx = ipo.addCurve('RotX')
   Roty = ipo.addCurve('RotY')
   Rotz = ipo.addCurve('RotZ')
   for c in [Locx,Locy,Locz,Rotx,Roty,Rotz]:
      c.setInterpolation('Linear')
      c.setExtrapolation('Constant')
   return ipo

# Bakes the Blender settings to the IPO
def bakeipo(ipo, frame, obj):
    Locx = ipo.getCurve('LocX')
    Locy = ipo.getCurve('LocY')
    Locz = ipo.getCurve('LocZ')
    Rotx = ipo.getCurve('RotX')
    Roty = ipo.getCurve('RotY')
    Rotz = ipo.getCurve('RotZ')

    Locx.addBezier((frame,obj.LocX))
    Locy.addBezier((frame,obj.LocY))
    Locz.addBezier((frame,obj.LocZ))
    Rotx.addBezier((frame,obj.RotX*5.729))
    Roty.addBezier((frame,obj.RotY*5.729))
    Rotz.addBezier((frame,obj.RotZ*5.729))

def set_rot(obj, R):
	m = obj.getMatrix()
	m[0][0] = R[0]
	m[1][0] = R[1]
	m[2][0] = R[2]
	m[0][1] = R[3]
	m[1][1] = R[4]
	m[2][1] = R[5]
	m[0][2] = R[6]
	m[1][2] = R[7]
	m[2][2] = R[8]
	obj.setMatrix(m)

# Create a world object
world = ode.World()
world.setGravity((0,0,-9.81))

# Create 3 bodies
body1 = ode.Body(world)
M = ode.Mass()
M.setSphere(2500, 0.05)
body1.setMass(M)
body1.setPosition((1,2,0))

body2 = ode.Body(world)
M = ode.Mass()
M.setSphere(2500, 0.05)
body2.setMass(M)
body2.setPosition((2,2,0))

body3 = ode.Body(world)
M = ode.Mass()
M.setSphere(2500, 0.05)
body3.setMass(M)
body3.setPosition((3,2,0))

# Connect body1 with the static environment
j1 = ode.BallJoint(world)
j1.attach(body1, ode.environment)
j1.setAnchor( (0,2,0) )

# Connect body2 with body1
j2 = ode.BallJoint(world)
j2.attach(body2, body1)
j2.setAnchor( (1,2,0) )

# Connect body3 with body1
j3 = ode.BallJoint(world)
j3.attach(body3, body2)
j3.setAnchor( (2,2,0) )

#Get Blender Object
obj1 = Object.Get("Cube")
obj2 = Object.Get("Cube.001")
obj3 = Object.Get("Cube.002")
ipo1 = makeipo("Cube")
ipo2 = makeipo("Cube.001")
ipo3 = makeipo("Cube.002")

# Simulation loop...

fps = 24
dt = 1.0/fps
frame = 1 #first frame

while frame < 150: #tot of frame to do

    # Draw the two bodies
    x1,y1,z1 = body1.getPosition()
    x2,y2,z2 = body2.getPosition()
    x3,y3,z3 = body3.getPosition()
    obj1.setLocation(x1,y1,z1)
    obj2.setLocation(x2,y2,z2)
    obj3.setLocation(x3,y3,z3)
    set_rot(obj1,body1.getRotation())
    set_rot(obj2,body2.getRotation())
    set_rot(obj3,body3.getRotation())
    bakeipo(ipo1,frame,obj1)
    bakeipo(ipo2,frame,obj2)
    bakeipo(ipo3,frame,obj3)
    # Next simulation step
    world.step(dt)
    Blender.Set("curframe",Blender.Get("curframe")+1)
    frame += 1

obj1.setIpo(ipo1)
obj2.setIpo(ipo2)
obj3.setIpo(ipo3)

print "done!"

Tutorial 3:
Click here to watch Collision_demo0001_0600

# pyODE example 3: Collision detection
import Blender
from Blender import Ipo, Scene, Mathutils, Window
from Blender.Object import *
from Blender.Mathutils import *
import ode

# create_box
def create_box(world, space, density, lx, ly, lz):
    """Create a box body and its corresponding geom."""
    global objlist
    # Create body
    body = ode.Body(world)
    M = ode.Mass()
    M.setBox(density, lx, ly, lz)
    body.setMass(M)

    # Set parameters for drawing the body
    body.shape = "box"
    body.boxsize = (lx, ly, lz)
    zpos = Rand(10,15)
    xpos = Rand(-2,2)
    ypos = Rand(-2,2)
    body.setPosition((xpos,ypos,zpos))

    # Create a box geom for collision detection
    geom = ode.GeomBox(space, lengths=body.boxsize)
    geom.setBody(body)

    # Create Blender object
    obj = New("Mesh","box")
    obj.link(Get("box").getData())
    obj.setLocation(xpos,ypos,zpos)
    objlist.append(obj)
    ipo = makeipo("box_move")
    ipolist.append(ipo)
    obj.setIpo(ipo)
    sc = Scene.getCurrent()
    sc.link(obj)
    return body

# drop_object
def drop_object():
    """Drop an object into the scene."""
    
    global bodies, counter, objcount
    
    body = create_box(world, space, 3000, 1.0,0.5,0.5)
    bodies.append(body)
    counter=0
    objcount+=1
    
# Collision callback
def near_callback(args, geom1, geom2):
    """Callback function for the collide() method.

    This function checks if the given geoms do collide and
    creates contact joints if they do.
    """

    # Check if the objects do collide
    contacts = ode.collide(geom1, geom2)
    # Create contact joints
    world,contactgroup = args
    for c in contacts:
        c.setBounce(0.1)
        c.setMu(5000)
        j = ode.ContactJoint(world, contactgroup, c)
        j.attach(geom1.getBody(), geom2.getBody())

# Create an Ipo Object
def makeipo(name):
   print "Creating new IPO "+name
   ipo = Ipo.New('Object', name)
   Locx = ipo.addCurve('LocX')
   Locy = ipo.addCurve('LocY')
   Locz = ipo.addCurve('LocZ')
   Rotx = ipo.addCurve('RotX')
   Roty = ipo.addCurve('RotY')
   Rotz = ipo.addCurve('RotZ')
   for c in [Locx,Locy,Locz,Rotx,Roty,Rotz]:
      c.setInterpolation('Linear')
      c.setExtrapolation('Constant')
   return ipo

# Bakes the Blender settings to the IPO
def bakeipo(ipo, frame, obj):
    Locx = ipo.getCurve('LocX')
    Locy = ipo.getCurve('LocY')
    Locz = ipo.getCurve('LocZ')
    Rotx = ipo.getCurve('RotX')
    Roty = ipo.getCurve('RotY')
    Rotz = ipo.getCurve('RotZ')

    Locx.addBezier((frame,obj.LocX))
    Locy.addBezier((frame,obj.LocY))
    Locz.addBezier((frame,obj.LocZ))
    Rotx.addBezier((frame,obj.RotX*5.729))
    Roty.addBezier((frame,obj.RotY*5.729))
    Rotz.addBezier((frame,obj.RotZ*5.729))

def draw_body(body,obj,ipo):
    global frame
    x,y,z = body.getPosition()
    obj.setLocation(x,y,z)
    set_rot(obj,body.getRotation())
    bakeipo(ipo,frame,obj)
    
def set_rot(obj, R):
	m = obj.getMatrix()
	m[0][0] = R[0]
	m[1][0] = R[1]
	m[2][0] = R[2]
	m[0][1] = R[3]
	m[1][1] = R[4]
	m[2][1] = R[5]
	m[0][2] = R[6]
	m[1][2] = R[7]
	m[2][2] = R[8]
	obj.setMatrix(m)  

######################################################################

# Create a world object
world = ode.World()
world.setGravity( (0,0,-9.81) )
world.setERP(0.8)
world.setCFM(1E-5)

# Create a space object
space = ode.Space()

# Create a plane geom which prevent the objects from falling forever
floor = ode.GeomPlane(space, (0,0,1), 0)

# A list with ODE bodies
bodies = []
objlist = []
ipolist = []

# A joint group for the contact joints that are generated whenever
# two bodies collide
contactgroup = ode.JointGroup()

# Some variables used inside the simulation loop
fps = 24
dt = 1.0/fps
state = 0
counter = 0
objcount = 0
frame = 0.0
totframe = 700

while frame < totframe:
    counter+=1
    frame += 1
    Window.DrawProgressBar(frame/totframe,"Simulation...")
    Blender.Set("curframe",frame)
    if counter==5:
        drop_object()
    # Draw the scene
    for b in range(len(bodies)):
        draw_body(bodies[b],objlist[b],ipolist[b])

    # Simulate
    n = 2

    for i in range(n):
        # Detect collisions and create contact joints
        space.collide((world,contactgroup), near_callback)
        # Simulation step
        world.step(dt/n)
        # Remove all contact joints
        contactgroup.empty()
Window.DrawProgressBar(1,"Done")

A personnal test using lego:
Click here to watch playblast_legowall2
Click here to watch Render_legowall0001_0200

import Blender
from Blender import BGL, Draw, Object, Ipo, Scene, Window
from Blender.BGL import *
from Blender.Draw import *
import ode

# Create an Ipo Object
def makeipo(name):
   print "Creating new IPO "+name
   ipo = Ipo.New('Object', name)
   Locx = ipo.addCurve('LocX')
   Locy = ipo.addCurve('LocY')
   Locz = ipo.addCurve('LocZ')
   Rotx = ipo.addCurve('RotX')
   Roty = ipo.addCurve('RotY')
   Rotz = ipo.addCurve('RotZ')
   for c in [Locx,Locy,Locz,Rotx,Roty,Rotz]:
      c.setInterpolation('Linear')
      c.setExtrapolation('Constant')
   return ipo

# Bakes the Blender settings to the IPO
def bakeipo(ipo, frame, obj):
    Locx = ipo.getCurve('LocX')
    Locy = ipo.getCurve('LocY')
    Locz = ipo.getCurve('LocZ')
    Rotx = ipo.getCurve('RotX')
    Roty = ipo.getCurve('RotY')
    Rotz = ipo.getCurve('RotZ')

    Locx.addBezier((frame,obj.LocX))
    Locy.addBezier((frame,obj.LocY))
    Locz.addBezier((frame,obj.LocZ))
    Rotx.addBezier((frame,obj.RotX*5.729))
    Roty.addBezier((frame,obj.RotY*5.729))
    Rotz.addBezier((frame,obj.RotZ*5.729))

def set_rot(obj, R):
	m = obj.getMatrix()
	m[0][0] = R[0]
	m[1][0] = R[1]
	m[2][0] = R[2]
	m[0][1] = R[3]
	m[1][1] = R[4]
	m[2][1] = R[5]
	m[0][2] = R[6]
	m[1][2] = R[7]
	m[2][2] = R[8]
	obj.setMatrix(m)

def draw_body(body,obj,ipo):
    global frame
    x,y,z = body.getPosition()
    obj.setLocation(x,y,z)
    set_rot(obj,body.getRotation())
    bakeipo(ipo,frame,obj)

# Collision callback
def near_callback(args, geom1, geom2):
	"""Callback function for the collide() method.
	This function checks if the given geoms do collide and
	creates contact joints if they do.
	"""
	# Check if the objects do collide
	contacts = ode.collide(geom1, geom2)
	# Create contact joints
	world,contactgroup = args
	for c in contacts:
		c.setBounce(.5)
		c.setMu(7000)
		j = ode.ContactJoint(world, contactgroup, c)
		j.attach(geom1.getBody(), geom2.getBody())

# Create a world object
world = ode.World()
world.setGravity((0,0,-9.81))
world.setERP(0.2) #error correction
world.setCFM(1E-10) #softness of collision

# Create a wall
lbody = []
lobj = []
lipo = []
contactgroup = ode.JointGroup()
# Create a space object
space = ode.Space()
# Create a plane geom which prevent the objects from falling forever
floor = ode.GeomPlane(space, (0,0,1), 0)
ori = Object.Get("Lego") #lego is 3,1,1 long as x,y,z)
mesh = ori.getData()
sc = Scene.GetCurrent()
a = 1.5
for z in range(20):
	for x in range(5):
		cur = Object.New("Mesh","wall")
		cur.link(mesh)
		cur.setLocation(x*3+a,1,z+.5)
		sc.link(cur)
		lobj.append(cur)
	if a == 1.5:
		a = 3
	else:
		a = 1.5

for obj in lobj:		
	body = ode.Body(world)
	M = ode.Mass()
	M.setBox(5000,3,1,1)
	body.setMass(M)
	body.setPosition(obj.getLocation())
	geom = ode.GeomBox(space,(3,1,1))
	geom.setBody(body)
	ipo = makeipo(obj.name)
	obj.setIpo(ipo)
	lipo.append(ipo)
	lbody.append(body)
	body.disable() #wait for the cue
	
bball = ode.Body(world)
obj2 = Object.Get("Ball")
M = ode.Mass()
M.setSphere(700,5)
bball.setMass(M)
bball.setPosition(obj2.getLocation())
geom2 = ode.GeomSphere(space,5)
geom2.setBody(bball)
bball.setLinearVel((0,20,0)) #give some speed.

lobj.append(obj2)
lbody.append(bball)
ipo = makeipo(obj2.name)
lipo.append(ipo)
obj2.setIpo(ipo)

# Simulation loop...

fps = 24
dt = 1.0/fps
frame = 1 #first frame
totframe = 300
while frame < totframe: #tot of frame to do
	Window.DrawProgressBar(frame/totframe,"Simulation...")
	Blender.Set("curframe",frame)
	for i in range(2):
		space.collide((world,contactgroup), near_callback) #colision
		for b in range(len(lbody)):
			draw_body(lbody[b],lobj[b],lipo[b])
		world.quickStep(dt) #shift time
		contactgroup.empty() #empty mem
	Blender.Set("curframe",Blender.Get("curframe")+1)
	frame += 1
ode.CloseODE()
Window.DrawProgressBar(1,"Done!")

Here is the .blend. You just need to switch screen with ctrl-left or right. And then start the script with alt-p to generate the goodies.

(edit) added stuff

Gabio, great!

I haven’t looked too much at bloded. I am a programmer, and your examples and code made ode very clear to me. What is the advantage or disadvantage of doing ode in blender for animations your way as opposed to bloded? Thanks again.

rob

There is no advantage at all. It’s (almost) the same code. I just use a different library, pyODE, which is maintained. blODEd hasn’t been updated for a while. Originally blODEd was an other python library giving you access to the ODE lib. It was designed with blender API in mind. The last update isn’t so different from pyODE actually, just some difference in the output of info. ie: Rotation is given as a vector in blODEd and as a 4x4 matrix in pyODE.
Until Blender get a real rigidbody engine integrated as the softbody one, this is imho the best way you can get anim from blender. Game engine baker can’t deliver yet want you can do by scripting it.
I plan on adding a GUI for it once in I have free time…

Hi Gabio, first a big Thanks for the samples and the explications , this maybe is out of subject but I try to use trimesh on your samples but I can not make it work. I base my self on bloded code. It seam that it construct the trimesh but I’m not sure why it fail. I try to flip the face order but nothing (hoping that the problem was a orientation for faces but NO), can you please help me on solving this?

This is what I have

class Objeto:
    def __init__(self,blendObj,densidad):
        self.blendObj=blendObj
        self.nom=blendObj.name
        self.body=ode.Body(world)
        bound=self.blendObj.getBoundBox()
        loc=self.blendObj.getLocation()
        data = ode.TriMeshData()
        verts = []
        faces = []
        for i in range(0,len(self.blendObj.data.verts)):
            verts.append((self.blendObj.data.verts[i].co[0],self.blendObj.data.verts[i].co[1],self.blendObj.data.verts[i].co[2]))        
        for i in range(0,len(self.blendObj.data.faces)):
            faces.append((self.blendObj.data.faces[i].v[1].index,self.blendObj.data.faces[i].v[0].index,self.blendObj.data.faces[i].v[2].index))
        data.build(verts, faces)
        x,y,z = self.blendObj.getSize()
        mass = ((x+y+z)/3)*densidad
        x = x *2
        y = y *2
        z = z *2
        M=ode.Mass()
        M.setBox(mass, x,y,z)
        M.mass = mass
        self.body.setMass(M)
        self.body.setPosition((loc[0],loc[1],loc[2]))                
        get_rot(self.body,self.blendObj.getMatrix())
        self.geom = ode.GeomTriMesh(data,space)
        self.geom.clearTCCache()
        #self.geom = ode.GeomBox(space,(x,y,z))
        print self.geom.getTriangle(0)
        print self.geom.getTriangle(1)
        print self.geom.getTriangle(2)
        self.geom.setBody(self.body)
        self.ipo=makeipo(self.nom)

If I use the GeomBox I dont have problem.

Thank you

Sure it will not bug with geombox, it’s the simplest of the geom after floor :wink:
If you tell me why it fail or what is the error msg it could help.

I got it to work out of the box replicating it from the blODEd wrapper in the Asdroide script.
However it take a lot of time to convert a trimesh from Blender to ODE. Here it take 30 secondes to convert 1 mesh of 500 verts, (suzanne).

hope it help.

THANKS for the fast replay!! :smiley:

Well the problem is that when I put the trimesh it did not reconice the floor and I was not sure that the trimesh was workin but I put a box geom in the botom and problem solve. Now I’m try to fix some object to the enviroment with a fixjoint but is doing some wird results. any sujestion?

Un Saludos

this respond my quiestion :-?

http://ode.org/ode-latest-userguide.html#sec_7_0_0

Un Saludo