Sprites Slower than Meshes?

Blitz3D Forums/Blitz3D Programming/Sprites Slower than Meshes?

NewtSoup(Posted 2010) [#1]
I saw a "Game of Life" program on here and thought I'd have a go at making one myself just as a quick refresher in B3D.

I made this first version using an array of Spheres to represent the cells and I used camerapick to select paint them. The controls are:

Arrow Keys to move the camera.
Mouse wheel to "zoom" (it's actually just moving the camera away from the grid)
Left and Right Mouse buttons to "paint" a cell, yellow is "Alive" and blue is "Dead".

Spacebar sets the sim going.

I found the limit is about a 120x120 grid and it's eating up a ton of memory at that. So I thought it would be a good idea to use sprites instead, fewer triangles means faster draw times right?

Apparently not so, with spheres the program is fairly responsive, eats about 40% of my CPU when running an F-Pentamino and about 128mb of mem with the 60x60 grid.

If I change the CreateSphere() to a CreateSprite() the memory usage drops to around 26mb and the process time goes down too to about 35% and yet the whole program becomes really really unresponsive requiring a 3 second hold on a key/mouse button to get anything to change. The sprite view mode is set to 2 but that only puts the sprite in "free" mode.

Anyone got a clue what's going on?

Here's the code in it's sphere form - if you want to test it with sprites just change the createSphere() to createSprite() - that's all you need to do.

Thanks in advance :)




NewtSoup(Posted 2010) [#2]
Well ok, I just found a thread along the same lines. So sprites have been utterly borked in B3D since version>1.64.

Nice :(

I have an idea though:

Perhaps a DIY sprite might work -

createMesh
createSurface
Add Vertices
Add Triangles

*edit*

Yes that works but the memory usage is twice that of actual sprites and of course I'd have to write my own versions of all the sprite handling functions. It's slightly speedier than spheres.

Function CreateSprite2()
	m=CreateMesh()
	s=CreateSurface(m)
	v0=AddVertex (s,-1,-1,0)
	v1=AddVertex (s,-1,1,0)
	v2=AddVertex (s,1,1,0)
	v3=AddVertex (s,1,-1,0)
	t0=AddTriangle(s,v0,v1,v2)
	t1=AddTriangle(s,v0,v2,v3)
	Return m
End Function


using CreateSphere(2) and rotating it by 45 degrees gives me almost the same rendering speed and looks nicer than the plain squares. and only uses 3 mb more for 60 size grid


Nate the Great(Posted 2010) [#3]
or you could use create cube? ;)


Stevie G(Posted 2010) [#4]
Use instancing Luke.

e.g. create one quad / sphere as a tempate at the start of your program, hide it, then use copyentity for all further instances.


Vorderman(Posted 2010) [#5]
I was finding that using just 4 sprites was bring my game to a standstill. Shame as they were really useful. I've still got a few sprites in the game that need to be removed seeing as their performance is now so low.


Ross C(Posted 2010) [#6]
I've heard people saying they are even slower, since a recent update?


NewtSoup(Posted 2010) [#7]
I don't know. It's been a while since I did any blitz stuff couple of years or more to be honest. I've never really used spites before and the reason behind trying here was to judge the performance difference.

I've mainly used blitz for mathematical modelling in the past and made do with primitives because I didn't need anything more complicated.

My projects in my final year of uni were 3D and 2D Behavioural programs using subsumption architecture and a program to demonstrate a 3D rendering written using only 2D line and pixel functions (I didn't feel like doing it all from first principles using only writepixelfast )


Rroff(Posted 2010) [#8]
You'd use a single surface and add all the sprites to that... that way you can get 10s of thousands being rendered with very little slowdown.


SLotman(Posted 2010) [#9]
Could be your drivers. Several people have been reporting problems with sprites/dx7 and newest nvidia drivers. Replacing them with meshes works way better.

Now, looking at your code, you're doing something wrong:

grid(x,y,MESH)=CreateSphere()
SpriteViewMode grid(x,y,mesh),2

SpriteViewMode only works on sprites! it should be

grid(x,y,MESH)=CreateSprite()

You can also reduce memory on CreateSphere, using something like CreateSphere(2) - so it will have much less segments than a normal sphere.


MadJack(Posted 2010) [#10]
Spritecandy'd probably clear that right up...


Vorderman(Posted 2010) [#11]
I've got an ATI card in my machine and the sprites are very very slow, so I think there's more to it than just NVidia's drivers.


NewtSoup(Posted 2010) [#12]
SLotman - you're quite right there, I'd just forgotten to comment that bit out when I uncommented the createsphere()

Rroff - I did just that with my home brew sprite function createSprite2() (I've since added in the vertex normals and UV coords so it will texture properly too) and I've also used createsphere(2) for the very reasons you state.

Function CreateSprite2()
	m=CreateMesh()
	s=CreateSurface(m)
	v0=AddVertex (s,-1,-1,0,0,1)
	v1=AddVertex (s,-1,1,0,0,0)
	v2=AddVertex (s,1,1,0,1,0)
	v3=AddVertex (s,1,-1,0,1,1)
	VertexNormal (s,0,0,0,1)
	VertexNormal (s,1,0,0,1)
	VertexNormal (s,2,0,0,1)
	VertexNormal (s,3,0,0,1)
	
	t0=AddTriangle(s,v0,v1,v2)
	t1=AddTriangle(s,v0,v2,v3)
	Return m
End Function


This works quite well, memory saving is as I mentioned a little better than createSphere(2) But I also prefer the look of createSphere(2).

And agreed Vorderman it can't really be a driver issue because many many games run perfectly well with sprites on my machine - Darwinia for instance.

Perhaps Mark will fix sprites in the next patch :) they'd be very handy for UI elements in 3D mode.

Thanks for the replies all.


Uber Jase(Posted 2010) [#13]
I can find the link at the moment but Toms hardware did a 2D benchmark test and found that even an old 3DFX card was faster at 2D than a modern card. ATI are fixing the issue in the next couple of months (they made a hotfix driver that TH tested and the results were a lot better). So it may not be blitz's fault.


Rroff(Posted 2010) [#14]
I'm a little confused - but it seems your adding each new quad to a new mesh?

What I'm talking about is creating one mesh, surface and adding each sprite quad to that (so directx batches the polygons for much faster rendering).


I'm in the middle of coding my own (somewhat experimental) sprite routines atm so will share what I come up with.


NewtSoup(Posted 2010) [#15]
Rroff - ah yes, I am indeed using a new mesh for each quad. This is because I'm using blitz's entity pick:

Each "sprite" is positioned relative to it's location in the array so the first sprite in the array (0,0) is located at (0,0) in world space then the sprite at (1,0) is located at (1,0) and so on - that way when I do a

cameraPick(camera, mouseX(), mouseY())

the entityX() and entityY() of the picked mesh tell me which cell in the array I have just picked.

I believe if it were one mesh and surface I'd have to devise another method of picking the cells.

I will have a good think on what you're doing too though.


Ross C(Posted 2010) [#16]
Well, you could use the picked triangle command. That way you can compare this against your particles in a single surface, and have the speed of a single surface particle system too.


Rroff(Posted 2010) [#17]
As above pick the triangle in the single mesh and get the vertex coords.


NewtSoup(Posted 2010) [#18]
I've come up with a speedy compromise

I use copyentity in initgrid to make initialisation faster
I set the alpha of each quad to 0 so it's invisible but pickable
I create another mesh behind the grid
I texture that mesh with a texture the same size as the grid
Then I color that grid in with writepixelfast using the picked mesh to get the correct pixel in the texture.

So now I'm only rendering 2 triangles but they have a dynamic texture - procedural texture I guess.

Runs acceptably @512x512 but struggles @1024x1024 (taking up 1.5gb ram in the process) which is better than struggling at 120 as before.

The cell counter doesn't work properly
Space starts/stops simulation
Arrow Keys navigate up down left right
left and right mouse buttons colour the cells alive/dead respectively
S puts the simulation in step mode so you can watch it frame by frame one keypress at a time.
C clears the grid if the simulation is paused.



Tips on how to make the texture pixels non blurred when zoomed in would be good now :(


Ross C(Posted 2010) [#19]
surely using the single surface method is the quickest way to do this?


NewtSoup(Posted 2010) [#20]
If I use purely a single surface I have to use pickedTriangle() which means I have to work out which quad it belongs to - entirely possible I admit BUT having got the right quad how do I color it independently of the other quads on the surface? As far as I can tell I can only have one color or texture per surface (in Blitz at least).

The way I'm doing it here means the quads used for picking have an alpha of 0 so they are not rendered. The proof can be seen by setting the alpha to 0.5 in initgrid() which makes the program run at about 0.25 fps - thus I know I am only rendering a single surface with 2 triangles on it.

For picking I can also use meshes with no triangles, it still counts as model and can thefore have an entityRadius for picking. However when I tried this the difference in memory use and speed was nothing.

Unless you mean a single surface for picking which is not visible and another surface for drawing on?


Rroff(Posted 2010) [#21]
If you want more than one effect on a spite use say a 512x512 texture split into 4 areas of 256x256, set the UV to that area - bingo :D


Warner(Posted 2010) [#22]
Yes, you can set the UV's for the picked triangle or use VertexColor.
For picking I can also use meshes with no triangles, it still counts as model and can thefore have an entityRadius for picking.
Shouldn't make too much of a speed difference, but you could better use a Pivot instead.


NewtSoup(Posted 2010) [#23]
Rroff - That's not quite what I'm after - I'm writing to a 512x512 texture where each pixel represents a cell in the cellular automaton. That texture is then mapped onto a 2 triangle surface to speed up rendering time compared to my first version.

I suspect what Ross thinks he means by using a single surface is different to what I think he means - I think he means make a single surface of the required grid size, pick that surface, get the picked triangle then work out which quad said triangle belongs to. But if that's what he means then in my case I'm back to rendering 512x512x2 = 524,288 triangles instead of just 2. Plus I can't work out how I'd color each quad to represent alive and or dead cells when they're on the same surface.

The problems with my current implementation are that it only likes grid sizes that are a power of two and when I'm zoomed in the pixels bleed over into each other. Blitz appears to be doing some smoothing that I don't want it to do.


NewtSoup(Posted 2010) [#24]
Warner please show me how to color triangles independently :)

and can't use a pivot for picking, if you try blitz tells you it's not a model.


GIB3D(Posted 2010) [#25]
I use a pivot for picking all the time but don't expect to use Mesh commands on one.


NewtSoup(Posted 2010) [#26]
I know why it told me off - I was using pickmode 2 and then tried pivots. Yeah there might be a memory saving with pivots


Warner(Posted 2010) [#27]
Here is how to color triangles using VertexColor:

And here with UV texturing:



NewtSoup(Posted 2010) [#28]
Thanks warner -

I should have figured that out - I can have multiple vertices sharing the same location in world space belonging to completely independent triangles, quads or whatever I like.

So in my program I won't need to unweld my mesh, just create each quad on the same surface, so the first quad will be

{ (0,0),(1,0),(1,1),(0,1)}

And the second will be

{(1,0),(1,1),(2,1),(2,0)}

And then I can set the vertex colors at the same time.

The only thing left to do then would be to sort out the picking

Much helpful thanks :)