[Numpy-discussion] Physics Engine

Ian Mallett geometrian at gmail.com
Wed Apr 7 22:36:03 EDT 2010


Hi,

I'm working on various projects, I think it would be great to have a
built-in physics engine to my rendering library.  I would rather not rely on
a large dedicated Physics library (PyOGRE, PyODE, etc.).  I thought it might
be interesting to try to make a simple soft-body physics engine with NumPy.


To this end, over the past few hours, I've constructed this per-vertex
physics object class, which plugs directly into my rendering object's
class.  So far, it implements global forces, collision detection with a
horizontal plane, and length tensors:

class glLibCPUSoftPhysMesh:
    def __init__(self,object):
        self.object = object

        self.original_vertices = np.array(object.raw_vertices)
#object.raw_vertices is the unique list of vertices
        self.vertices = np.array(object.raw_vertices)
        self.vertex_indices = np.array(object.indexed_vertices[0])
#object.indexed_vertices[0] is a list of indices into object.raw_vertices

        self.vertex_speeds = np.zeros((self.vertices.shape[0],3))

        self.delta_pos = np.zeros((self.vertices.shape[0],3))

        v1s = self.original_vertices[self.vertex_indices[0::3]]
        v2s = self.original_vertices[self.vertex_indices[1::3]]
        v3s = self.original_vertices[self.vertex_indices[2::3]]
        self.target_lengths1 = np.sum((v1s-v2s)**2.0,axis=1)**0.5
        self.target_lengths2 = np.sum((v2s-v3s)**2.0,axis=1)**0.5
        self.target_lengths3 = np.sum((v3s-v1s)**2.0,axis=1)**0.5

        self.dampening = 0.999
    def add_force(self,force):
        self.vertex_speeds += np.array(force)
    def add_position(self,pos):
        self.delta_pos += np.array(pos)
    def move(self):
        #Length tensors
        v1s = self.vertices[self.vertex_indices[0::3]]
        v2s = self.vertices[self.vertex_indices[1::3]]
        v3s = self.vertices[self.vertex_indices[2::3]]
        side1 = v2s - v1s
        side2 = v3s - v2s
        side3 = v1s - v3s
        delta_side1 = np.transpose(
((np.sum(side1**2.0,axis=1)**0.5)-self.target_lengths1,)*3 ) * side1
        delta_side2 = np.transpose(
((np.sum(side2**2.0,axis=1)**0.5)-self.target_lengths2,)*3 ) * side2
        delta_side3 = np.transpose(
((np.sum(side3**2.0,axis=1)**0.5)-self.target_lengths3,)*3 ) * side3
        tensor = 0.01
        self.vertex_speeds[self.vertex_indices[0::3]] += tensor*delta_side1
        self.vertex_speeds[self.vertex_indices[1::3]] -= tensor*delta_side1
        self.vertex_speeds[self.vertex_indices[1::3]] += tensor*delta_side2
        self.vertex_speeds[self.vertex_indices[2::3]] -= tensor*delta_side2
        self.vertex_speeds[self.vertex_indices[2::3]] += tensor*delta_side3
        self.vertex_speeds[self.vertex_indices[0::3]] -= tensor*delta_side3

        self.delta_pos += self.vertex_speeds
        self.vertex_speeds *= self.dampening
        self.vertices += self.delta_pos
        self.delta_pos.fill(0.0)
    def collision_detect(self):
        indices = np.where(self.vertices[:,1]<0.0001)
        self.vertices[indices,1] = 0.0001
        self.vertex_speeds[indices] *= -0.1
    def get_data(self):
        return [self.vertices[self.vertex_indices].tolist()]

The code works fairly well for its complexity (and runs very quickly).  I
believe it also needs angle tensors, which would be more complicated.  There
are a few strange errors I can't account for (like the object very slowly
drifts, as it rests on the ground).

At the moment, I'm wondering whether a physics engine has already been done
with NumPy before, and if not, whether anyone has any interest in making
one.

Ian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20100407/65c5737a/attachment.html>


More information about the NumPy-Discussion mailing list