Pi3D


216 posts   Page 1 of 9   1, 2, 3, 4, 5 ... 9
by liz » Thu Jun 14, 2012 5:10 pm
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.
--
Head of Comms, Raspberry Pi Foundation
User avatar
Raspberry Pi Foundation Employee & Forum Moderator
Raspberry Pi Foundation Employee & Forum Moderator
Posts: 4076
Joined: Thu Jul 28, 2011 7:22 pm
by paddyg » Thu Jun 14, 2012 9:56 pm
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 = []
clouds.append(pi3d.load_textureAlpha("Textures/cloud2.png"))
clouds.append(pi3d.load_textureAlpha("Textures/cloud3.png"))
clouds.append(pi3d.load_textureAlpha("Textures/cloud4.png"))
clouds.append(pi3d.load_textureAlpha("Textures/cloud5.png"))
clouds.append(pi3d.load_textureAlpha("Textures/cloud6.png"))

# 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
    if mykeys.read() == 10:       
        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.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by liz » Thu Jun 14, 2012 10:18 pm
Thanks Paddy!
--
Head of Comms, Raspberry Pi Foundation
User avatar
Raspberry Pi Foundation Employee & Forum Moderator
Raspberry Pi Foundation Employee & Forum Moderator
Posts: 4076
Joined: Thu Jul 28, 2011 7:22 pm
by tipam » Thu Jun 14, 2012 11:09 pm
liz wrote:Thanks Paddy!

Thanks Paddy again!
Posts: 44
Joined: Fri Dec 30, 2011 1:32 pm
by Gibble » Fri Jun 15, 2012 12:05 pm
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: 56
Joined: Wed May 09, 2012 9:52 am
by paddyg » Fri Jun 15, 2012 4:57 pm
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)

########################################################################
class loadModel():
    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 } }
  }
}
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by paddyg » Sat Jun 16, 2012 5:17 pm
Sorted something out at last. Here's what seems to be a functioning version of loadModel().
http://www.eldwick.org.uk/files/loadmodel.zip
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.

Paddy

PS I will try it with some other eggs and post some video of the most impressive looking one!
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by paddyg » Sat Jun 16, 2012 7:28 pm
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
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by paddyg » Sun Jun 17, 2012 9:14 am
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.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by HiggleBottom » Sun Jun 17, 2012 10:34 am
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.

Please help :cry:
Posts: 21
Joined: Sun Apr 22, 2012 7:09 pm
by rurwin » Sun Jun 17, 2012 11:01 am
Have you done an rpi-update? IIUC that installs the libraries.
User avatar
Forum Moderator
Forum Moderator
Posts: 2903
Joined: Mon Jan 09, 2012 3:16 pm
by Gibble » Sun Jun 17, 2012 11:38 am
Just thinking, will the GL stuff work in a VM anyway ?
Posts: 56
Joined: Wed May 09, 2012 9:52 am
by rurwin » Sun Jun 17, 2012 1:17 pm
No, not unless it virtualises the videocore, which it can't. Good catch.
User avatar
Forum Moderator
Forum Moderator
Posts: 2903
Joined: Mon Jan 09, 2012 3:16 pm
by HiggleBottom » Sun Jun 17, 2012 1:43 pm
Ah. Thanks anyway!
Posts: 21
Joined: Sun Apr 22, 2012 7:09 pm
by paddyg » Tue Jun 19, 2012 9:27 pm
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:

http://www.eldwick.org.uk/files/moreloadmodel.zip
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by Gibble » Wed Jun 20, 2012 9:50 am
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: 56
Joined: Wed May 09, 2012 9:52 am
by paddyg » Wed Jun 20, 2012 11:30 am
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)
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by paddyg » Thu Jun 21, 2012 3:15 pm
paddyg wrote:I will upload the latest version here)

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.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by tipam » Sat Jun 23, 2012 5:00 pm
paddyg wrote:
paddyg wrote:I will upload the latest version here)

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!
Posts: 44
Joined: Fri Dec 30, 2011 1:32 pm
by tipam » Sat Jun 23, 2012 6:38 pm
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.

Image

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.
Image

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

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.
Posts: 44
Joined: Fri Dec 30, 2011 1:32 pm
by Gibble » Sat Jun 23, 2012 7:33 pm
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)
Posts: 56
Joined: Wed May 09, 2012 9:52 am
by dom » Sat Jun 23, 2012 7:38 pm
@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.
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 4011
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge
by tipam » Sat Jun 23, 2012 8:34 pm
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 ...

print "Loading ...",fileString
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!
Posts: 44
Joined: Fri Dec 30, 2011 1:32 pm
by paddyg » Sun Jun 24, 2012 9:57 pm
Not really sure how else to do it but most of the time seems to be taken with
Code: Select all
.tostring("raw",RGBs)
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire
by paddyg » Mon Jun 25, 2012 5:11 pm
paddyg wrote:.tostring("raw",RGBs)
actually it's the eglchars() method that takes all the time. I tried saving the images as 'raw' strings but it seemed to take the same time and this is why.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 836
Joined: Sat Jan 28, 2012 11:57 am
Location: Bingley, Yorkshire