Dark Bit Factory & Gravity
PROGRAMMING => Freebasic => Topic started by: ninogenio on April 04, 2007
-
right im working on a game right now that has lots of objects on the map the problem is though that after about fifty 3d objects i start to get really bad slow down so i need some sort of way of not sending opengl my objects as soon as they have falling out side the veiwing rect i thought this would have been easy enough and went something like this.
x = objxpos * halfscrx
y = objypos * halfscry
if x+objwidth < screenx or x-objwidth>screenx blah blah
but i was forgetting about the projection ie the edges of the veiwing rect 10 units in might be 2 or 3 so i was wondering if there is a way to unproject an object to test it against the borders of the screen.
cheers.
-
Most people use bounding cubes or bounding spheres to do this. A bounding sphere is a sphere which just encloses the whole object. If the sphere lies outside the view then don't print any of the polygons in the object. What you then have to do is check the sphere against your view. If your viewing angle is 90degrees, then any point where the x or y is > z is outside the view.
So, if your object is at (x,y,z) and has radius r then it's offscreen if
z<r - the object is behind the camera
x-r<-z - the object is off to the left
x+r<z - the object is off to the right
y-r<-z - the object is off to the bottom
y+r<z - the object is off to the top
That works for viewing angles of 90deg only, but it can be fixed up to work with any angle.
Jim
-
cheers jim my game uses bounding boxes for collisions so ill just use those for boundary checking im currently using a 45 deg viewing angle and i am not sure how to work this in.
-
I bet you mean 45degrees is half the viewing angle. So 90 from left to right. You can do the same check I put above for each point on a bounding box, if you want to use that instead of spheres. If any point on the box is inside the view then you need to print the object.
This will all need some tweaking by the way.
Jim
-
sorry jim i dont quite understand i have a 45 fov if i translate my object -10 into the screen then a simple bounding check against the clipping planes isnt going to be possible as the distance to the clipping planes change dippending on the object z position.
i need some way of incorporating the view angles and the objects z pos into the bounding checks.
cheers
-
You compare x and y of the vertex with z of the same vertex.
Imagine a square-based pyramid with the apex point at 0,0,0 and the z axis running from the apex to the middle of the base. This is your view volume. Any (x,y,z) points inside that view volume have x and y coordinates less than their z coordinates. Any points outside it have x or y coordinates bigger than z. That's for 90degress. Set your fov to 90 to try it out.
So all you need to do for any point you want to check to see if it's in or out of the view, subtract away the camera position and compare the x and y with z. So
px,py,pz = point to check
cx,cy,cz = camera position
dx = px - cx
dy = py - cy
dz = py - cz
if (dx < -dz || dx > dz)
..outside
if (dy <-dz || dy > dz)
..outside
else
..inside
OpenGL doesn't provide any functions to retrieve the data after it's been through the modelview or the projection matrix. So you're going to have to implement a matching rotation function which does the same as the gl_modelview. You can grab the matrix code out of the pumpkin source if you like, and use glGetFloatv(GL_MODELVIEW_MATRIX) to retrieve the modelview matrix. You can apply that matrix to a point to put it in camera space and then you can use the test above.
Jim
-
ahh ok im with you now cheers jim.
-
i already have matrix math in the game my camera and object all have independent 4x4`s so does the matrix grabbing part go something like.
glloadidentity
rotatecameramatrix
translatecameramatrix
glloadmatrix(camera)
rotatemymatrix
gltranslatematrix
glmulmatrixd(object)
tempmatrix = glGetFloatv(GL_MODELVIEW_MATRIX)
does that look ok for that part.
now onto aplying a matrix onto a point is it the same as we do with our 2d engines something like this.
x = ( matrix(0,0) * x + matrix(0,1) * y + matrix(0,2) * z )
y = ( matrix(1,0) * x + matrix(1,1) * y + matrix(1,2) * z )
z = ( matrix(2,0) * x + matrix(2,1) * y + matrix(2,2) * z )
-
Since it's just a point, you only want the camera part of the matrix.
Jim
-
right ive tryed to get this going but i think ive messed up the applying of the matrix onto the x,y,z of the object but im not sure.
-
No, you're really close actually.
The first problem is with GenioTransposeM(), the last 3 lines need to be negged, ie.
object->matrix( m30 ) = -Tx
object->matrix( m31 ) = -Ty
object->matrix( m32 ) = -Tz
I hope that doesn't bugger up too much other stuff. If it does, we can fix it later somewhere else.
Then the transformation you want to achieve is this one.
Matrix(3,...) is the camera position from the model matrix. This is how I spotted the above problem. If you don't want to change the transpose function, change it to minuses here.
Anyway, you need to take care the camera position before the rotation
Tmp1X = Cube->Position->X + Matrix(3,0)
Tmp1Y = Cube->Position->Y + Matrix(3,1)
Tmp1Z = Cube->Position->Z + Matrix(3,2)
Tmp2X = ( Matrix(0,0) * Tmp1X + Matrix(0,1) * Tmp1Y + Matrix(0,2) * Tmp1Z )
Tmp2Y = ( Matrix(1,0) * Tmp1X + Matrix(1,1) * Tmp1Y + Matrix(1,2) * Tmp1Z )
Tmp2Z = ( Matrix(2,0) * Tmp1X + Matrix(2,1) * Tmp1Y + Matrix(2,2) * Tmp1Z )
Then finally
Xvec = Tmp2X
Yvec = Tmp2Y
Zvec = -Tmp2Z
Z is negated because in OpenGL z is negative into the distance. It pretty much works then.
Here's how I checked it
If ( Xin And Yin ) Then
DrawEntity( Cube )
OutputDebugString("In\n")
Else
OutputDebugString("Out\n")
EndIf
glDisable(GL_DEPTH_TEST)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glBegin(GL_POINTS)
glColor3f(1,0,0)
glVertex3f(Tmp2X, Tmp2Y, Tmp2Z)
glEnd()
glEnable(GL_DEPTH_TEST)
What this does is draw an untransformed red dot (no zbuffer) so that I can see whether our rotation is indeed correct. The red dot is always drawn over the centre of the square, so wahey!
I really encourage you (and everyone else) to learn to debug this way. Visualising your data like this makes it far easier to find out wtf is wrong with complicated code.
Jim
-
cool thanks jim!
negging the translation has only reversed my controlls around so it should be easy to fix.
i never thought about debugging that way but for sure ill be trying stuff like that from now. btw how do i see the output from outputdebugstring.
-
I use dbmon which is part of Visual Studio. For me, that's located here
C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin\winnt
If you don't have VS, you can download dbmon replacements from lots of places.
Jim
-
ive found a peculiar bug which i cant get fixed this works perfect if the object is inside camera space at start up but if i draw my object outside camera space i gant get it to appear even though my debug info says it should.
#include "GenioGl.Bi"
GenioGraphics( 800 , 600 , 32 , WINDOWED )
Type KeyTracker
Key As Ubyte ptr
Esckey as Uinteger
Up As uinteger
Down As Uinteger
KLeft As Uinteger
KRight As Uinteger
Z As Uinteger
End Type
Declare Sub MoveCamera ( Cam As GenioEntity PTR )
Declare Sub GenioCheckKeys ( Keys As KeyTracker )
Dim Shared Camera As GenioEntity PTR
Dim Shared Key As KeyTracker
Dim Shared Cube As GenioEntity PTR
Cube = cube_mesh()
scale_entity( Cube , 0.5 , 0.5 , 0.5 )
set_entity_position( Cube , 20 , 0 , -10 )
camera = SetUpCamera
Dim Shared As Integer GenioLeftX = 1 , GenioRightX = 1 , GenioUpY = 1 , GenioDownY = 1
do
Dim As Single TmpX , TmpY , TmpZ , Xvec , Yvec , Zvec
GenioRender( Camera )
GenioClear()
GenioCheckKeys( Key )
TmpX = ( Cube->Position->X - Camera->Matrix( m30 ) )
TmpY = ( Cube->Position->Y - Camera->Matrix( m31 ) )
TmpZ = ( Cube->Position->Z - Camera->Matrix( m32 ) )
Print TmpX
Print TmpY
Print TmpZ
Xvec = ( Camera->Matrix( m00 ) * TmpX + Camera->Matrix( m10 ) * TmpY + Camera->Matrix( m20 ) * TmpZ )
Yvec = ( Camera->Matrix( m01 ) * TmpX + Camera->Matrix( m11 ) * TmpY + Camera->Matrix( m21 ) * TmpZ )
Zvec = -( Camera->Matrix( m02 ) * TmpX + Camera->Matrix( m12 ) * TmpY + Camera->Matrix( m22 ) * TmpZ )
print xvec
print yvec
print zvec
If ( Xvec <= -Zvec ) Then
GenioLeftX = 0
Else
GenioLeftX = 1
EndIf
If ( Xvec >= Zvec ) Then
GenioRightX = 0
Else
GenioRightX = 1
EndIf
If ( Yvec <= -Zvec ) Then
GenioDownY = 0
Else
GenioDownY = 1
EndIf
If ( Yvec >= Zvec ) Then
GenioUpY = 0
Else
GenioUpY = 1
Endif
If ( GenioLeftX And GenioRightX And GenioUpY And GenioDownY ) Then
DrawEntity( Cube )
glColor3f(0,1,0)
Else
glColor3f(1,0,0)
EndIf
glDisable(GL_DEPTH_TEST)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glBegin(GL_POINTS)
glVertex3f( 0 , 0 , -2 )
glEnd()
glEnable(GL_DEPTH_TEST)
MoveCamera( Camera )
LOOP WHILE Key.esckey <> 1
DeleteCamera( Camera )
DestroyEntity( Cube )
SDL_Quit
SLEEP
sub GenioCheckKeys( Keys As KeyTracker )
SDL_PumpEvents
Keys.Key = SDL_GetKeyState(0)
Keys.Esckey = Peek( Keys.Key + SDLK_ESCAPE )
Keys.Up = peek( Keys.Key + SDLK_UP )
Keys.Down = peek( Keys.Key + SDLK_DOWN )
Keys.KLeft = peek( Keys.Key + SDLK_LEFT )
Keys.KRight = peek( Keys.Key + SDLK_RIGHT )
Keys.Z = peek( Keys.Key + SDLK_Z )
end sub
Sub MoveCamera( Cam As GenioEntity PTR )
If Key.KLeft Then
move_entity( Cam , -0.1 , 0 , 0 )
ElseIf Key.KRight Then
move_entity( Cam , 0.1 , 0 , 0 )
EndIf
If Key.Up Then
move_entity( Cam , 0 , 0.1 , 0 )
ElseIf Key.Down Then
move_entity( Cam , 0 , -0.1 , 0 )
EndIf
End Sub
<edit just went over this and in fact the only situation this works in is when my object is in the center of the veiw port when the object moves left or right by say 5 units the clipping planes move also>
-
Why have you changed it from using the matrix you get from
GLGETFLOATV( GL_MODELVIEW_MATRIX , @Matrix(0,0) )
to using the camera matrix? Or have you changed GenioGL to store it away?
Here's my entire While loop after I'd finished (total mess, I left your stuff in there and added my own, but you can pick out the bits you need)
do
Dim As Single Matrix( 0 To 3 , 0 To 3 )
Dim As Single TmpX , TmpY , TmpZ , Xvec , Yvec , Zvec
GenioRender( Camera )
GenioClear()
GenioCheckKeys( Key )
' GLGETFLOATV( GL_MODELVIEW_MATRIX , @Matrix(0,0) )
glGetFloatv(GL_MODELVIEW_MATRIX, @Matrix(0,0))
TmpX = ( Matrix(0,0) * Cube->Position->X + Matrix(0,1) * Cube->Position->Y + Matrix(0,2) * Cube->Position->Z )
TmpY = ( Matrix(1,0) * Cube->Position->X + Matrix(1,1) * Cube->Position->Y + Matrix(1,2) * Cube->Position->Z )
TmpZ = ( Matrix(2,0) * Cube->Position->X + Matrix(2,1) * Cube->Position->Y + Matrix(2,2) * Cube->Position->Z )
Xvec = TmpX - Camera->Position->X
Yvec = TmpY - Camera->Position->Y
Zvec = TmpZ - Camera->Position->Z
Dim as single Tmp1X,Tmp1Y,Tmp1Z,Tmp2X,Tmp2Y,Tmp2Z
Tmp1X = Cube->Position->X + Matrix(3,0)
Tmp1Y = Cube->Position->Y + Matrix(3,1)
Tmp1Z = Cube->Position->Z + Matrix(3,2)
Tmp2X = ( Matrix(0,0) * Tmp1X + Matrix(0,1) * Tmp1Y + Matrix(0,2) * Tmp1Z )
Tmp2Y = ( Matrix(1,0) * Tmp1X + Matrix(1,1) * Tmp1Y + Matrix(1,2) * Tmp1Z )
Tmp2Z = ( Matrix(2,0) * Tmp1X + Matrix(2,1) * Tmp1Y + Matrix(2,2) * Tmp1Z )
Xvec = Tmp2X
Yvec = Tmp2Y
Zvec = -Tmp2Z
If ( Xvec < -Zvec Or Xvec > Zvec ) Then
'Do Nothing
Xin = 0
Else
Xin = 1
EndIf
If ( Yvec < -Zvec Or Yvec > Zvec ) Then
'Do Nothing
Yin = 0
Else
Yin = 1
EndIf
If ( Xin And Yin ) Then
DrawEntity( Cube )
OutputDebugString("In"+Chr$(13)+Chr$(10))
Else
OutputDebugString("Out"+Chr$(13)+Chr$(10))
EndIf
glDisable(GL_DEPTH_TEST)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glBegin(GL_POINTS)
glColor3f(1,0,0)
glVertex3f(Tmp2X, Tmp2Y, Tmp2Z)
glEnd()
glEnable(GL_DEPTH_TEST)
MoveCamera( Camera )
LOOP WHILE Key.esckey <> 1
Jim
-
ahha so its object + matrix
Tmp1X = Cube->Position->X + Matrix(3,0)
Tmp1Y = Cube->Position->Y + Matrix(3,1)
Tmp1Z = Cube->Position->Z + Matrix(3,2)
this works properly for me.
i dont think i need to get gl to retrieve the model veiw matrix as its just retreving my transposed camera matrix that i just loaded. ive tested it and it still seems to work so im sure thats the case.
cheers jim.
-
In this case, it's object + matrix because the camera position in the camera matrix is -ve (you're adding on a -ve number).
ie.
a + -5 = a - 5
You're right, the camera matrix you generate will be just fine.
In general, if you want to rotate something around something else (like this point around the camera) you have to subtract away the origin of the rotation (the point you're rotating about - in this case the camera) from the position of the object you want to rotate. Then you can apply the rotation.
Jim
-
yeah i forgot i had negged the translation of the camera lol.
ive spent a good couple of hours trying to figure out where i had buggerd it up aswell!
thanks for the help jim and it really has made a diffrence in my game i recon ill get about 10x the amount of badguys into my level now.