Speed difference between ImageSprite and using an atlas like SpriteMulti demo?

33 views
Skip to first unread message

Chris T.

unread,
Nov 8, 2016, 11:07:41 AM11/8/16
to pi3d
Hello,

I got a Raspberry Pi 3 recently and reinstalled Pi3D, wow! What a difference in speed and exciting developments in the library, very nice work. 

I was wondering if there's any difference speed wise between using a system like in the SpriteMulti demo, with an image atlas vs creating ImageSprite objects for displaying 30-40 images on screen at the same time. Last time I used Pi3D I think there wasn't an ImageSprite function and the SpriteMulti demo was just created, but I might be wrong. 

I was also wondering what would be the best way to do the following: I'm planning on having a high definition image as static background and several characters animating on screen on top of this background, no scrolling. Maybe using ImageSprite for everything is the best approach? What about several planes?

Thank you very much,
Chris


Paddy

unread,
Nov 8, 2016, 3:52:46 PM11/8/16
to pi3d
Chris, ImageSprite is certainly simpler and I think the Pi3 could display 30-40 images at a good frame rate. However the uv_pointsprite shader system as used in SpriteMulti can render larger numbers of sprites much faster. If you want to animate your sprites in an image atlas kind of way (facing left, right, walking left, right etc) then the SpriteMulti arrangement may be better. If they're just moving around then ImageSprite may be better.

The ImageSprite class has existed from early days - it's really just a wrapper for creating a Sprite and a Texture more easily. If you want to use the same Texture on multiple Sprites then you should create the Texture instance before and pass that to ImageSprite.__init__() rather than the file string for the image.

Chris T.

unread,
Nov 11, 2016, 9:29:24 AM11/11/16
to pi3d
Thank you for your reply Paddy. I'm currently running 50 ImageSprites at 60fps on my Raspberry Pi 3!

Now, I'm doing some texture animation tests. I'm naively loading +30 textures and setting the textures over a sprite in a loop seems to work quite well. ~60fps with 35 frames next to 25 moving ImageSprites. However, I understand that this is a quite expensive operation, specially if one wants to add more animating sprites later on.

SpriteMulti seems like a nice solution, as you suggested, but I was wondering if you could provide some example or tips regarding the texture animation answer in the FAQ:

This became much more feasible after v1.4 and more so after v2.1 The Texture class now accepts a numpy array (size (H,W,N) where N is 3 for RGB or 4 for RGBA), remember C arrays are row,col,pixel)

I don't quite understand how can one place a set of textures on a numpy array :(  Would this be a better / faster way than just using an image atlas ala SpriteMulti?

Thanks,
Chris

Paddy

unread,
Nov 11, 2016, 1:09:36 PM11/11/16
to pi3d
Chris, The advantage of the SpriteMulti method is that there is only one Shape requiring transformation and projection matrix multiplicaiton. It can have thousands of vertices each one with a different image, or part of an image mapped to a 'point' on each one (gl_PointSize can be as big as you want, even filling the whole screen). However the Raspberry Pi 3 can do this kind of thing pretty fast - the numpy module seems significantly faster, maybe it's utilising the extra processors. So if you can render 50 ImageSprites at 60fps, and that's enough to do what you want, I would stick with that (20fps is pretty much perfect animation on the RPi, much smoother than 60fps on this i5 laptop). To animate the texture mapping the best way is to alter the uniform variables passed to the shader from the Buffer umult, vmult, u_off, v_off to render a different part of a texture atlas image. This takes virtually no processing effort compared with reloading a new texture even from a preloaded numpy array, which is quite slow.

I will make a very simple animated texture example to show you how to use the u_off, v_off values.

Purely for interest if you had 16 128x128 images in a directory called im00.png, im01.png ... im32.png, im33.png then you could generate a numpy texture atlas something like this:

img = np.zeros((512,512,4),dtype=np.uint8)
for i in range(4):
 
for j in range(4):
    img
[i*128:(i+1)*128, j*128:(j+1)*128] = np.array(Image.open('im{}{}.png'.format(i,j)))
# then
tex
= pi3d.Texture(img)
# or quicker for a pre-existing texture
tex
.update_ndarray(img)

Paddy

unread,
Nov 11, 2016, 1:48:54 PM11/11/16
to pi3d
Hope this is clear. #1 cutest kitten on youtube!
cat_atlas.jpg
tmp.py

Chris T.

unread,
Nov 11, 2016, 2:13:18 PM11/11/16
to pi3d
Paddy, as always you have been a huge help. Thank you very much, this works perfectly.

I'm sorry if I'm taking a big chunk of your time but this part went right over my head:
The advantage of the SpriteMulti method is that there is only one Shape requiring transformation and projection matrix multiplicaiton. It can have thousands of vertices each one with a different image, or part of an image mapped to a 'point' on each one (gl_PointSize can be as big as you want, even filling the whole screen)

 So, in the SpriteMulti demo all the sprites are actually over one Shape? Are the vertices the sprites? I guess I have some reading to do, do you have any noob friendly resources for understading this terms?

Thanks!

Chris T.

unread,
Nov 11, 2016, 2:17:56 PM11/11/16
to pi3d
Last question: how do you calculate which values for umult and vmult to use?

Paddy

unread,
Nov 11, 2016, 3:26:21 PM11/11/16
to pi3d
Chris, no problem. Yes each sprite is a single vertex of one Shape. When OpenGL renders the information provided to the GPU it can interpret the values in different ways: GL_TRIANGLES, GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN

there are probably better explanations but you could look at http://paddywwoof.github.io/pi3d_book/_build/html/Lines.html

umult and vmult are scaling values applied to the texture coordinates when looking up pixel values using the Texture2D function. As there are 8 x 8 sub images then the scaling values are 0.125 and the offset increases by this same amount.

Chris T.

unread,
Nov 17, 2016, 7:31:32 AM11/17/16
to pi3d
Hi Paddy, thanks again. With your suggestions and code I've been stressing the Rpi3 using several sprites with animated textures. This uses only 20% of one cpu!

Cheers!

Paddy

unread,
Nov 17, 2016, 9:33:52 AM11/17/16
to pi3d
They look very impressive!
Reply all
Reply to author
Forward
0 new messages