Rotation and scaling problem

BlitzMax Forums/OpenGL Module/Rotation and scaling problem

jkrankie(Posted 2009) [#1]
Hi all,

I've been using OpenGL to write something simple that i can plug into my existing project to speed up drawing particles - i'm using minib3d's sprite stuff at the minute. Anyway, i've got a bit stuck with rotating and scaling things, rather than spinning and growing around the center of the image, its scaling and rotating from 0,0,0.

I expect that this is probably something that isn't too difficult to get working right, but i'm a bit new at OpenGL. Hopefully one of you clever types will be able to point me in the right direction with this...

further more, if i'm missing a trick here, and it's slower than it could be, could you let me know what i can do to make it faster.

here is the code:
Import sidesign.minib3d

graphics3d 640,480,32,7,60

cam=createcamera()
positionentity cam,0,0,-30

light=createlight()
positionentity light,0,0,-15

'load textures
pix=LoadPixmap("data/BCship.png")
tex=GLTexFromPixmap(pix)

list:TList=New TList
For Local i:Int=0 To 1000
	list.addlast New glsprite.Create(Rnd(-15,15),Rnd(-15,15))
Next

Local old_ms=MilliSecs()
Local renders
Local fps



While Not KeyHit(key_escape)
	
	renderworld
	renders:+1
	If MilliSecs()-old_ms>=1000
		old_ms=MilliSecs()
		fps=renders
		renders=0
	EndIf
	
	'addmore stuff to the list
	For Local n:Int=0 To 14
	list.addlast New glSprite.Create(Rnd(-15,15),Rnd(-15,15))
	Next
	
	'enable/disable stuff
	glenable(GL_COLOR_MATERIAL)
	glShadeModel(GL_SMOOTH);							
	glClearColor(0.0,0.0,0.0,0.0);					
	glClearDepth(1.0);								
	glDisable(GL_DEPTH_TEST);							
	glEnable(GL_BLEND);								
	glBlendFunc(GL_SRC_ALPHA,GL_ONE);					
	glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);	
	glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);								
	glEnable(GL_TEXTURE_2D);						
	glbindtexture(GL_TEXTURE_2D,tex)
	
	'update sprites
	For Local g:glsprite=EachIn list
		glpushmatrix()
		If g.update()=True Then list.remove g
		glpopmatrix()
	Next
	
	text 10,10,"FPS: "+String(fps)	
	text 10,20,"Sprites: "+String(list.count())
	
	Flip 
	
Wend


Type glsprite
	
	Field x:Float,y:Float
	Field angle:Float=0
	Field life:Float=1.0
	Field rot:Float=Rnd(-2,2)
	Field size:Float=Rnd(0.25,2.5)
	
	Function Create:glsprite(inx:Float,iny:Float)
		Local n:glsprite=New glsprite
		n.x=inx
		n.y=iny
		Return n
	EndFunction
	
	Method update:Int()
		angle:+rot
		life:-0.01
		glcolor4f(255,255,255,life)
		
		glrotatef(angle,0,0,1)
		glscalef(size,size,1)
		
		glbegin(GL_TRIANGLE_STRIP)
			
			glTexCoord2d(1,1)
			glvertex3f(x+0.5,y+0.5,0)
			
			glTexCoord2d(0,1)
			glvertex3f(x-0.5,y+0.5,0)
			
			glTexCoord2d(1,0)
			glvertex3f(x+0.5,y-0.5,0)
			
			glTexCoord2d(0,0)
			glvertex3f(x-0.5,y-0.5,0)
		
		glend()
		
		If life<=0 Then Return True	
		Return False
		
	EndMethod
	
End Type


Cheers
Charlie


ImaginaryHuman(Posted 2009) [#2]
If you are going to use glRotatef() for your rotation, then to get it to rotate around the center of the sprite you will have to precede it with glTranslatef(spritewidth/2,spriteheight/2,0) (or maybe those are supposed to be minuses).

There are some things you're doing with are slow and no faster than blitz is currently doing.

Pushing and popping the modelview matrix for every sprite?

Starting a glBegin and glEnd for every separate sprite?

A separate texture for each sprite? or are you using only one sprite for the entire particle system?

I don't know why you're pushing and popping the matrix for every sprite, not exactly necessary, is that a substitute for glLoadIdentity()? faster?

Lots of the calls to gl commands that you're doing inside your main loop can be outside the loop.

beginning and ending the geometry is not needed for every separate sprite, you can do it once at the beginning, update all sprites, then end it.

Why not use vertex arrays? They're supported in GL 1.1 with no extensions needed and can be twice as fast - only thing is you have to pass pre-rotated/translated/scaled vertex coordinates so you can't use glRotate etc.
However, supposedly using glRotate/scale/translate can be slower than calculating it yourself with simple adds and stuff cus each of those operations requires an entire matrix to be multiplied.


jkrankie(Posted 2009) [#3]
Maybe i should have been more clear/specific. I need most of those GL calls in the main loop because MiniB3D (which i'm using for the bulk of the drawing) sets it's own GL stuff. Also, i haven't put in functionality for each object having its own texture - am i right in thinking that i should make a simple check to see if the next texture is the same as the last and only call GLbindtexture if it is different?

I'm using push and pop because Loadidentity causes it not to work. i imagine that MiniB3d is using loadidentity in some way.

Also, if it's quicker to just change the vertex coordinates as opposed to using glrotatef/glscalef i'll do that. Scaling should be easy enough, but how would i calculate the rotated coordinates quickly? i could use sin and cos, but i guess that would add overhead... maybe this is more of a maths question than OpenGL?

Finally, how do i get away with using less GLbegin and GL end calls then? surely if i'm drawing a triangle strip then adding more vertices would make the triangle strip bigger?

thanks for taking the time to answer :)

Cheers
Charlie


ImaginaryHuman(Posted 2009) [#4]
No you should put everything on one texture if possible.

Yes the triangle strip would keep on going, by why are you using a triangle strip for particles which can be rendered using quads?


jkrankie(Posted 2009) [#5]
Ok, i'll switch to quads.

So i'd have one texture containing all the different textures i intend to use? how would i do that?

Cheers
Charlie


Brucey(Posted 2009) [#6]
Single Surface rendering :-)

Sounds like a good topic for a tutorial in the up-coming BlitzMax coder mag...

As for your question regarding lots of begin/ends, I believe that it is possible to use some kind of array, which you can pass into OpenGL as a batch. (yeah, I know that's totally vague, but I saw some code somewhere which used one)


jkrankie(Posted 2009) [#7]
Ok, i switched to quads and got rid of the glrotate and glscale commands, i also managed to get rid of quite a few of those GL calls in the main loop. Also, i tried using sin and cos to calculate the positions of the vertices when rotated and it seems to have little to no effect on performance. the big hit comes from using glBindTexture to swap textures. I'm using this to minimise calls:

If currenttexture<>tex
	glbindtexture(GL_TEXTURE_2D,tex)
EndIf


i'm also only using glbegin(quads) and glend when the texture is being changed.

At present, the code is currently rendering 3000 textured quads at 60fps and 4000 at >55fps, and there are two different textures being used. This is *probably* fast enough. Maybe...

If i wanted to use one big texture with all of the different images i want to use as particles, would i just have to change the texcoords to show a different part of the texture? or is it more complex than that?

Cheers
Charlie


jkrankie(Posted 2009) [#8]
@Brucey, i think you mean vertex arrays which would probably be ideal, i have absolutel no idea how to use them though!

Cheers
Charlie


jkrankie(Posted 2009) [#9]
Actually, it's faster than i though! i programmed this on my old G5 imac, but it runs even quicker on my win laptop with intel gfx chip! bonkers!

Cheers
Charlie


jkrankie(Posted 2009) [#10]
Single surface sprites are *really* quick!



fps goes down to about 45ish with 15000 sprites, but that's more than i'll ever need anyway!

Thanks for all the pointers guys. you're all super :)

Cheers
Charlie


Brucey(Posted 2009) [#11]
Single surface, eh? Who'd have thought it ;-)


Arowx(Posted 2009) [#12]
Cool, OK you've got me!

Please can you drop me a link or example code of 'single surface' and I'll start putting together an 'Advanced tutorial' for the first issue of BlitzMax Coder ;0)

Regards

Merx


jkrankie(Posted 2009) [#13]
I'll try to neaten up my code in the morning and post it on here. chances are though it won't be super useful as-is though, so you might need to make it more generic for your tutorial.

Cheers
Charlie


ImaginaryHuman(Posted 2009) [#14]
Yes you just need to use different texture coords for each quad, from a single texture, so that you can keep the same texture in use as long as possible.

You should check out vertex arrays, and the glDrawArrays() command which is the fastest. I believe I posted some code which does it in another thread in this opengl forum.

Actually, here:
http://www.blitzbasic.com/Community/posts.php?topic=84902
in a thread which you created ;D


jkrankie(Posted 2009) [#15]
Hi all, i've posted the code for what i've done so far here:
http://www.blitzbasic.com/Community/posts.php?topic=85639

I've got a slightly odd bug, which i describe to the best of my abilities in that post. basically on occasion it looks like drawing white quads instead of textured ones, although it may be some kind of blending issue?

Cheers
Charlie