## Pi3D

liz
Raspberry Pi Foundation Employee & Forum Moderator
Posts: 5212
Joined: Thu Jul 28, 2011 7:22 pm
Contact: Website

### Pi3D

http://www.raspberrypi.org/archives/1408

Tim Skillman and our old friend Peter de Rivaz have come up with a Python module which will let you muck around with 3d models, 2d sprites and more in Python on the Pi. Click the link above for more, and for a download.
Director of Communications, Raspberry Pi

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

couldn't post this in a comment on Tim's 'news' post so I will put it here. It's some tidying up of the cloud demonstration (still see-through background but nicer clouds)

Code: Select all

``````# Clouds 3D example using pi3d module
# ===================================
# Copyright (c) 2012 - Tim Skillman
#
# This example does not reflect the finished pi3d module in any way whatsoever!
# It merely aims to demonstrate a working concept in simplfying 3D programming on the Pi
#
# PLEASE INSTALL PIL imaging with:
#
#      \$ sudo apt-get install python-imaging
#
# before running this example
#
# This demo needs some sorting out - the alpha's are blending with desktop
# Solutions welcome!

import pi3d, random, time

z=0
x=0
speed=1
widex=40
widey = 10
cloudno = 50
cloud_depth = 60.0
zd = cloud_depth / cloudno

# Setup display and initialise pi3d
scnx = 800
scny = 600
display = pi3d.glDisplay()
display.create(100,100,scnx,scny)
display.setBackColour(0,0.7,1,1)

clouds = []

# Setup cloud positions and cloud image refs
z = 0.0
cxyz = []
for b in range (0, cloudno):
cxyz.append([random.random() * widex - widex*.5, -random.random() * widey, cloud_depth-z, int(random.random() * 4) + 1])
z = z + zd  #(z+random.random() * 100) % 1000

zc = 0

# Fetch key presses
mykeys = pi3d.key()

while True:

display.clear()

maxDepth = 0
maxDepthIndex = 0
# first go through the clouds to find index of furthest away
for i in range(len(cxyz)):
cxyz[i][2] = (cxyz[i][2] - speed) % cloud_depth
if (cxyz[i][2] > maxDepth):
maxDepth = cxyz[i][2]
maxDepthIndex = i

# paint the clouds from background to foreground
for i in range(maxDepthIndex, maxDepthIndex + cloudno):
c = cxyz[i%cloudno]
pi3d.sprite(clouds[c[3]], c[0], c[1], -c[2], 8, 5)

#Press ENTER to terminate
display.destroy()
break

display.swap_buffers()
time.sleep(0.01)
``````
Last edited by paddyg on Thu Jun 14, 2012 10:25 pm, edited 1 time in total.

liz
Raspberry Pi Foundation Employee & Forum Moderator
Posts: 5212
Joined: Thu Jul 28, 2011 7:22 pm
Contact: Website

### Re: Pi3D

Director of Communications, Raspberry Pi

tipam
Posts: 105
Joined: Fri Dec 30, 2011 1:32 pm

### Re: Pi3D

Raspberry Pi == small computer == big dreams

Gibble
Posts: 56
Joined: Wed May 09, 2012 9:52 am

### Re: Pi3D

Just want to say a big thanks for the work on this. I've been having a play .

Maybe worth a note in the Graphics programming forum section as well ?

Just for info, I've switched to using Shorts rather than Bytes on the 3d draw and created an eglshorts like eglbytes, as my object wasn't displaying right, and realised after some debugging that the indexes were overlapping to negative as I had too many. Not sure if its possible to adapt, depending on size of index or something ?

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

Following Tim's encouragement I have started the process of making an equivalent of the loadModule() At the moment I'm working on the basis of just one material and texture per object with fairly minimal functionality. Seems to parse the egg data ok, I will put full code up once I have joined it in to the Pi3D stuff.

Code: Select all

``````###
########################################################################
class vertex():
def __init__(self, coords_in, UVcoords_in, UVtangent_in, UVbinormal_in, normal_in):
self.coords = coords_in
self.UVcoords = UVcoords_in
self.UVtangent = UVtangent_in
self.UVbinormal = UVbinormal_in
self.normal = normal_in

########################################################################
class polygon():
def __init__(self, normal_in, rgba_in, vertexRef_in):
self.vertexRef = [] # variable number
for vRef in vertexRef_in:
self.vertexRef.append(vRef)
self.rgba = [] #should always be four
for rgbVal in rgba_in:
self.rgba.append(rgbVal)
self.normal = [] #should always be three
for nVal in normal_in:
self.normal.append(nVal)

########################################################################
def __init__(self):
self.coordinateSystem = "Y-up"
self.material = {}
self.textureFile = ""
self.texture = {}
self.vertexList = []
self.polygonList = []
``````
extracted from egg files like this

Code: Select all

``````<CoordinateSystem> { Z-up }

<Comment> { "Egg laid by Chicken for Blender, version R91" }

<Material> Material {
<Scalar> diffr {0.800000011921}
<Scalar> diffg {0.800000011921}
<Scalar> diffb {0.800000011921}
<Scalar> specr {0.25}
<Scalar> specg {0.25}
<Scalar> specb {0.25}
<Scalar> shininess {12.5}
}
<Texture> burgee.jpg {
"./burgee.jpg"
<Scalar> saved-result { 1 }
<Scalar> envtype { MODULATE }
<Scalar> minfilter { LINEAR }
<Scalar> magfilter { LINEAR }
<Scalar> wrap { REPEAT }
}
<Group> Cube {
<VertexPool> Cube {
<Vertex> 0 {
0.017518222332 0.801870763302 -0.159120246768
<UV>  {
0.004181 0.094870
<Tangent> { -0.020093 0.987846 0.154130 }
<Binormal> { -0.999798 -0.019853 -0.003098 }
}
}
<Vertex> 1 {
0.0882814079523 -0.9045535326 -0.425367534161
<UV>  {
0.928280 0.082284
<Tangent> { -0.020093 0.987846 0.154130 }
<Binormal> { -0.999798 -0.019853 -0.003098 }
}
}
<Vertex> 2 {
-0.0882815122604 -0.904553413391 -0.425367534161
<UV>  {
0.927306 0.143919
<Tangent> { -0.020093 0.987846 0.154130 }
<Binormal> { -0.999798 -0.019853 -0.003098 }
}
}
<Vertex> 3 {
-0.0175182558596 0.801870763302 -0.159120246768
<UV>  {
0.003988 0.107100
<Tangent> { -0.020093 0.987846 0.154130 }
<Binormal> { -0.999798 -0.019852 -0.003098 }
}
}
etc etc...
<Vertex> 22 {
-0.0175182558596 0.801870763302 -0.159120246768
<UV>  {
0.005199 -0.001855
<Tangent> { 0.012571 0.560083 -0.828341 }
<Binormal> { 0.999921 -0.007044 0.010412 }
}
}
<Vertex> 23 {
0.00276914983988 0.586692810059 0.159120246768
<UV>  {
0.190125 0.006914
<Tangent> { 0.013705 0.752456 -0.658500 }
<Binormal> { 0.966977 -0.007679 0.011351 }
}
}
}
<Polygon> {
<TRef> { burgee.jpg }
<MRef> { Material }
<Normal> { 0.000000 0.154161 -0.988046
}
<VertexRef> { 0 1 2 3 <Ref> { Cube } }
}
<Polygon> {
<TRef> { burgee.jpg }
<MRef> { Material }
<Normal> { 0.000004 0.420068 0.907493
}
<VertexRef> { 4 5 6 7 <Ref> { Cube } }
}
etc etc..
<Polygon> {
<TRef> { burgee.jpg }
<MRef> { Material }
<Normal> { -0.000002 -0.996518 0.083378
}
<VertexRef> { 12 13 14 15 <Ref> { Cube } }
}
<Polygon> {
<TRef> { burgee.jpg }
<MRef> { Material }
<Normal> { -0.997540 0.037755 0.059068
}
<VertexRef> { 16 17 18 19 <Ref> { Cube } }
}
<Polygon> {
<TRef> { burgee.jpg }
<MRef> { Material }
<Normal> { 0.000003 0.828407 0.560127
}
<VertexRef> { 20 21 22 23 <Ref> { Cube } }
}
}``````

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

Sorted something out at last. Here's what seems to be a functioning version of loadModel().
It's a zip file including the modified pi3d, a test .py and a couple of egg files one with a jpeg UV and one with png. You can probably find other egg files or produce them from blender with the chicken add on. I haven't tried it with any others so there could well be issues. (Will be issues)

I have had to do quite a lot of tweaking with the pi3d file to get this to work and could well have broken something so it's worth looking it all over carefully. To summarise:
1. I do a fairly hacky extraction of the vertices and polygons along with the first material and first texture in the file, I don't build a list of textures and match groups to them (but this ought to be done I suppose). Also I get the Z-up from the file but don't do anything with it.
2. I produce arrays of floats (instead of bytes) for the vertices, normals and tex_coords. It only seemed to work before because everything was 1x1. The triangles array uses shorts
3. I had to change the texture_on to use floats so changed the other lists in pi3d for rectangle etc

There seem to be a few other things to think about, I don't do any checking for whether the front of the triangle can be seen. I kind of expected that to be handled by the chip but with the png model ther is some funny see through effect. It's very handy to be able to parent object so when you move a body, say, all the limbs move with it. This functionality probably should go into the class but maybe it should be part of the pi3d.

Feedback and improvements welcome.

PS I will try it with some other eggs and post some video of the most impressive looking one!

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

As mentioned above I did a quick blender random blob which actually ended up with several thousand vertices and polygons then made it float around with 15 of the burgees zooming out of the screen. It's still got the background going transparent bug but Tim says he has fixed that.
http://youtu.be/8FVvahS8btE
sorry about the useless movie resolution and mumbled explanation

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

paddyg wrote: You can probably find other egg files or produce them from blender with the chicken add on. I haven't tried it with any others so there could well be issues. (Will be issues)
I have added a couple more egg files to the zip. The panda-model doesn't work, probably because of the various assumptions about file structure. I have started the process of improving the extraction system so it
a) makes a list of textures and materials
b) splits first on <Group> and <VertexPool> so it can apply the different textures appropriately.

HiggleBottom
Posts: 21
Joined: Sun Apr 22, 2012 7:09 pm

### Re: Pi3D

I get this error when running the Bouncing Balls demo on a Debian Squeeze VM:
OSError: libbcm_host.so: cannot open shared object file: No such file or directory.

rurwin
Forum Moderator
Posts: 4257
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

### Re: Pi3D

Have you done an rpi-update? IIUC that installs the libraries.

Gibble
Posts: 56
Joined: Wed May 09, 2012 9:52 am

### Re: Pi3D

Just thinking, will the GL stuff work in a VM anyway ?

rurwin
Forum Moderator
Posts: 4257
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

### Re: Pi3D

No, not unless it virtualises the videocore, which it can't. Good catch.

HiggleBottom
Posts: 21
Joined: Sun Apr 22, 2012 7:09 pm

### Re: Pi3D

Ah. Thanks anyway!

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

video here http://youtu.be/gqx9WZop2Js

I've re-worked the loadModule class so that it copes with <Group> and <VertexPool> and assigns materials as well as textures. As it stands all it does with materials is allocate the diffr,diffg,diffb to the colours in the couple of lines commented out under the cube code. i.e. no shading or properties

In the video I have tried printing the same four objects (decagon, sphere, leaf, stem) numbers of times to save on uploading. Uploading takes a longer time now because I am searching through large parts of the file to get matching { }. It works quite well though my matrix rotation is wrong which caused the bizarre effect (compounded by a roty where a rotx should have been in transform() [check out: Tim])

I'm not sure what's the best way to go with the loadModule. I can probably speed it up by not bothering with the Group or VertexPool if there are no more than one material or texture. Some, more complicated models, have relationships built in to allow animation etc but this is a bit complicated and probably slow to do with python. Could make it into a c module

More bits to play with:

Gibble
Posts: 56
Joined: Wed May 09, 2012 9:52 am

### Re: Pi3D

Nice work. Following all of this with interest. Just getting my head around modelling a bit more, then will have a further play with pi3d and the work you chaps have done.

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

yet more http://youtu.be/Z1pysY_qbEQ

I have tried to offload the calculation of the pip locations to the graphics functions. It seems more jerky as if it's actually taking longer but at least it puts things in the right place! I will upload the latest version here. Still need to figure out the rotation of objects relative to other objects (as in parent - child object tree arrangements)

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

http://www.eldwick.org.uk/files/evenmoreloadmodel.zip has the latest version (again incremental to Tim's stuff and previous zips of mine, see above)
I have added a light (tried a camera but couldn't get it to do anything) which goes on and off each time you press enter (quits program after 10).

What I would really like is for the material colours to remain when the lights go on (probably not putting the properties in the right place) and to render it with smoothing on. The normals are set on the vertices as per smoothing (in blender) but don't seem to have any effect in pi3d (again need to set something probably). The light does seem to work with UV textures loaded from files though, for some reason, with a light added but off there is a bizarre (but quite attractive) chequered pattern as if half the normals are in the wrong direction which might be due to the way I create triangles. I'm doing things by trial and error and occasional wading through openGLES 2 documentation I can find on line but quite hard to match things up with what's in the program. Actually it's probably more efficient to leave that to Tim & co who started pi3d. I did change the on() off() and lighton attributes to be a bit more logical.

tipam
Posts: 105
Joined: Fri Dec 30, 2011 1:32 pm

### Re: Pi3D

http://www.eldwick.org.uk/files/evenmoreloadmodel.zip has the latest version (again incremental to Tim's stuff and previous zips of mine, see above)
I have added a light (tried a camera but couldn't get it to do anything) which goes on and off each time you press enter (quits program after 10).

What I would really like is for the material colours to remain when the lights go on (probably not putting the properties in the right place) and to render it with smoothing on. The normals are set on the vertices as per smoothing (in blender) but don't seem to have any effect in pi3d (again need to set something probably). The light does seem to work with UV textures loaded from files though, for some reason, with a light added but off there is a bizarre (but quite attractive) chequered pattern as if half the normals are in the wrong direction which might be due to the way I create triangles. I'm doing things by trial and error and occasional wading through openGLES 2 documentation I can find on line but quite hard to match things up with what's in the program. Actually it's probably more efficient to leave that to Tim & co who started pi3d. I did change the on() off() and lighton attributes to be a bit more logical.
I will be working on the lights - I must admit I got the same problem with a cuboid!! I'll do an update quite soon as I've included a ton of stuff and I'm trying to standardise the interfaces. I've added some docs to the Wiki on Github - they describe some of what's coming in the next update. Great work Paddy!
Raspberry Pi == small computer == big dreams

tipam
Posts: 105
Joined: Fri Dec 30, 2011 1:32 pm

### Re: Pi3D

Thought I would add a few pics here of Pi3D progress ...

1. Lots of pre-built shapes; sphere, cone, cylinder, truncated-cone, torus, spiral, extrude, tube, cuboid, lathe (create a vase, jet engine, proper wheels and whatever you like!) I'll probably include a few other objects such as a building with a roof and some other useful stuff. All of these shapes are fully textured.

2. Landscape generator from greyscale image (SRTM images will be fun!) ... also incorporated a walkabout function which calculates the intersection point on the map - this means smooth walkabouts and accurately placed objects. I'll also include a 'tilt' vector so cars (or whatever) will climb over terrain correctly.

3. Collective merging of shapes (renders a single vertex buffer in one call - nice and fast!)

Plus there's a screenshot facility (as you can see) and hierarchical transforms (which OpenGL ES dropped and I've reintroduced). 2D rendering is also easy to setup simply by calling 'display.create2D' and then render a bunch of sprites.

Hopefully, next week I'll have a stable/more complete version of pi3d with more examples! ... I'll try and incorporate your egg loader as well Paddy!!

BTW - there are some docs on the tipam/pi3d github wiki that will take shape over the next few weeks.

I'll let you know when the next version is up on this forum.

Tim S.
Raspberry Pi == small computer == big dreams

Gibble
Posts: 56
Joined: Wed May 09, 2012 9:52 am

### Re: Pi3D

Great work chaps, can't wait.

I've been having a play, and managed to get a basic obj file imported and displaying (only basic bit, no materials or groups etc, and no vertex optimisations), translating with pi3d. I'm new to python, so my code is really duff (could probably be reduced half the size), but happy to let anyone else have it if it gets them started to make a better one.

I found one strange thing today I'm trying to isolate, if I run my program on my own Pi, the program uses up 35% CPU. I ftp'ed the files over to another Pi elsewhere to show it, and it takes up 70% cpu. One difference is the first one is the original Debian distro, the higher cpu one is the latest Deb beta. I suspect its something else entirely and user error from me somewhere, but so far the files look identical.

If any one can think of something else that could affect performance on the Pi's relating to OpenGLES (as thats pretty much all I'm doing atm), I'd be very interested. (Not overclocked)

dom
Raspberry Pi Engineer & Forum Moderator
Posts: 5572
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge

### Re: Pi3D

@Gibble
Lots of things it could be.
First update the firmware (with rpi-update) on the Squeeze image, and see if performance changes.
If not then its possibly something installed. Try a clean Squeeze and a clean Wheezy image to find out.
If neither of those idnehtifies it then maybe something different in changes in Debian. E.g. A newer version of Python.

tipam
Posts: 105
Joined: Fri Dec 30, 2011 1:32 pm

### Re: Pi3D

If anyone would like to find solutions for the following - it would help me speed up devs a bit!

1) Grab 'window' context so that keys and mouse events are directed to Pi3D only
2) A better solution to key press events than curses! ... I get a lot of keyboard buffer lag and annoying feedback in the Python terminal.
3) A faster way of loading textures - PIL is great but (probably the way I've done it) very slow! I'm using the following code ...

im = Image.open(fileString)
iy = im.size[0]
ix = im.size[1]
...
... (code for ^2 conversions)
...
image = eglchars(im.convert(RGBs).tostring("raw",RGBs))
tex=eglint()
opengles.glGenTextures(1,ctypes.byref(tex))
opengles.glBindTexture(GL_TEXTURE_2D,tex)
opengles.glTexImage2D(GL_TEXTURE_2D,0,RGBv,ix,iy,0,RGBv,GL_UNSIGNED_BYTE, ctypes.byref(image))

To be honest I'm not a Python expert so I warmly welcome any coding/speed improvements!!

Thanks again!
Raspberry Pi == small computer == big dreams

Posts: 2561
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

### Re: Pi3D

Not really sure how else to do it but most of the time seems to be taken with

Code: Select all

``.tostring("raw",RGBs)``