Mixing 3D and 2D in Blitz
BlitzMax Forums/OpenGL Module/Mixing 3D and 2D in Blitz
| ||
Suppose I wanted to make a street fighter type game where most of the graphics are 2d sprites, but I wanted a real 3d floor/ceiling. Is there a way to mix an OpenGL perspective projection and then go back to the regular Blitz one? Anyone done this yet? |
| ||
I'm not exactly sure on the internals of Max2D but I always thought that the 2d stuff is always drawn at a fixed Z coordinate, like 1.0 or something, for `normal size`. Maybe there already is a perspective projection in place, you just don't notice it because you don't move things in Z or rotate around the X and Y axes? If not it should be simple to set up - initialize the matrix with the projection matrix and draw the floor stuff then set it back and draw the `2D` stuff? I'm thinking that technically you wouldn't even need to switch back and forth between perspective and some other mode, given that 2d stuff is just quads that face the camera with a fixed Z position? |
| ||
Which is what I imagined to be the case, but I could not get it to work. OTOH, I am a complete GLnewbie. |
| ||
Seems likely it's orthographic, not perspective, or there'd probably be some distortion towards the edges. |
| ||
Hmmm, I tried replacing the bglCreateContext() with a call to Graphics(), and I got both my 3D and 2D showing. It ran really slowly, and the 2D wasn't positioned correctly, but its a start. Its maybe worth playing about with this to find out exactly how and where the 2D is being drawn. |
| ||
I've got it kind of working now, but hopefully it'll be enough for someone else to get it working properly :D Before calling bglCreateContext(), call Graphics(). This will allow both the 2D and 3D to displayed, without the slowdown. You also need to make sure GL_CULL_FACE is not enabled. I haven't looked into how to switch this off yet, so I just haven't enabled it in the first place. However, a better method would be to enable it before drawing the 3D, then disable it before drawing the 2D. Before drawing your 3d each frame, you will have to reset the camera as you will be changing it to get the 2D positioned correctly. This should be something like: glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45.0, Float(800)/Float(600), 0.1, 100.0) glMatrixMode(GL_MODELVIEW) After drawing the 3D, set the camera and model translation as follows: glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45, (Float(slx)/Float(sly))*1.045, 600.0, 700.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(-397,284,-686.5) glRotatef(180,1.0,0.0,0.0) The reason for rotating the object 190 round the x-axis is so that the origin is at top-left of screen instead of bottom-left. I've modified the GLTutorial to add 2D to it as follows: Strict 'Import "defines.bmx" Global slx = 800 ' Screen (or window) Width Global sly = 600 ' Screen (or window) Height Global depth = 32 ' 16-Bit, or 32-Bit Local isDebug:Byte = False ?Debug isDebug = True ? If isDebug Graphics(slx,sly,0) bglCreateContext(slx,sly,depth,0,BGL_BACKBUFFER|BGL_DEPTHBUFFER) Else Graphics(slx,sly,depth,60) bglCreateContext(slx,sly,depth,0,BGL_BACKBUFFER|BGL_DEPTHBUFFER|BGL_FULLSCREEN) EndIf Global moveabout:float=-5.0 Global direction:float=0 Global anglex:Float=0 Global angley:Float=0 Global up:tImage Type tCamera Field rotx:Float Field roty:Float Field rotz:Float Field tranx:Float Field trany:Float Field tranz:Float End Type Global cam:tCamera=New tCamera Type tObject Field rotx:Float Field roty:Float Field rotz:Float Field tranx:Float Field trany:Float Field tranz:Float Field scalex:Float Field scaley:Float Field scalez:Float Field offsetx:Float Field offsety:Float Field offsetz:Float End Type Global obj:tObject[5] For Local i = 0 To 4 obj[i] = New tObject Next Init() While Not KeyDown(KEY_ESCAPE) ' Clear the buffers glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) Tick() Render() ' Render to the backbuffer bglSwapBuffers ' Instead of Flip 'Flip Wend End Function Init() cam.tranz=-12 cam.rotx=20 cam.trany=-1 glClearColor(0.0, 0.0, 0.0, 0.0) glClearDepth(1.0) 'glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LEQUAL) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45.0, Float(slx)/Float(sly), 0.1, 100.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() up = LoadImage("../res/gfx/up.png") EndFunction Function Render() glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45.0, Float(slx)/Float(sly), 0.1, 100.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(cam.tranx,cam.trany,cam.tranz) glRotatef(cam.rotx,1.0,0.0,0.0) glRotatef(cam.roty,0.0,1.0,0.0) glRotatef(cam.rotz,0.0,0.0,1.0) 'glTranslatef(0,0,-15.0) 'glRotatef(anglex,1.0,0.0,0.0) 'glRotatef(angley,0.0,1.0,0.0) ' ** Tank Body glPushMatrix() glTranslatef(obj[0].tranx+obj[0].offsetx, obj[0].trany+obj[0].offsety, obj[0].tranz+obj[0].offsetz) glRotatef(obj[0].rotx, 1.0, 0, 0) glRotatef(obj[0].roty, 0, 1.0, 0) glRotatef(obj[0].rotz, 0, 0, 1.0) glBegin(GL_QUADS) glColor3f(0.3,0.8,0.2) ' Back Face glVertex3f(4.0, 1.0, -2.0) glVertex3f(3.0, -1.0, -2.0) glVertex3f(-3.0, -1.0, -2.0) glVertex3f(-4.0, 1.0, -2.0) glColor3f(0.3,0.8,0.2) ' Front Face glVertex3f(-4.0, 1.0, 2.0) glVertex3f(-3.0, -1.0, 2.0) glVertex3f(3.0, -1.0, 2.0) glVertex3f(4.0, 1.0, 2.0) glColor3f(0.3, 0.9,0.3) ' Left Face glVertex3f(-4.0, 1.0, -2.0) glVertex3f(-3.0, -1.0, -2.0) glVertex3f(-3.0, -1.0, 2.0) glVertex3f(-4.0, 1.0, 2.0) glColor3f(0.3, 0.9,0.3) ' Right Face glVertex3f(4.0, 1.0, 2.0) glVertex3f(3.0, -1.0, 2.0) glVertex3f(3.0, -1.0, -2.0) glVertex3f(4.0, 1.0, -2.0) glColor3f(0.3, 1.0,0.2) ' Top Face glVertex3f(-4.0, 1.0, -2.0) glVertex3f(-4.0, 1.0, 2.0) glVertex3f(4.0, 1.0, 2.0) glVertex3f(4.0, 1.0, -2.0) glColor3f(0.3, 1.0,0.2) ' Bottom Face glVertex3f(-3.0, -1.0, 2.0) glVertex3f(-3.0, -1.0, -2.0) glVertex3f(3.0, -1.0, -2.0) glVertex3f(3.0, -1.0, 2.0) glEnd() glPopMatrix() ' Turret Section glPushMatrix() glTranslatef(obj[1].tranx+obj[1].offsetx, obj[1].trany+obj[1].offsety, obj[1].tranz+obj[1].offsetz) glRotatef(obj[1].rotx, 1.0, 0, 0) glRotatef(obj[1].roty, 0, 1.0, 0) glRotatef(obj[1].rotz, 0, 0, 1.0) glBegin(GL_QUADS) glColor3f(0.3,0.8,0.2) ' Back Face glVertex3f(-4.0, 1.0, -2.0) glVertex3f(-2.5, 2.0, -1.5) glVertex3f(0.5, 2.0, -1.5) glVertex3f(2.5, 1.0, -2.0) glColor3f(0.3,0.8,0.2) ' Front Face glVertex3f(2.5, 1.0, 2.0) glVertex3f(0.5, 2.0, 1.5) glVertex3f(-2.5, 2.0, 1.5) glVertex3f(-4.0, 1.0, 2.0) glColor3f(0.3, 0.9,0.3) ' Left Face glVertex3f(-4.0, 1.0, 2.0) glVertex3f(-2.5, 2.0, 1.5) glVertex3f(-2.5, 2.0, -1.5) glVertex3f(-4.0, 1.0, -2.0) glColor3f(0.3, 0.9,0.3) ' right Face glVertex3f(0.5, 2.0, 1.5) glVertex3f(2.5, 1.0, 2.0) glVertex3f(2.5, 1.0, -2.0) glVertex3f(0.5, 2.0, -1.5) glColor3f(0.3, 1.0,0.1) ' top Face glVertex3f(0.5, 2.0, -1.5) glVertex3f(-2.5, 2.0, -1.5) glVertex3f(-2.5, 2.0, 1.5) glVertex3f(0.5, 2.0, 1.5) glEnd() glPopMatrix() ' Gun glPushMatrix() glTranslatef(obj[2].tranx+obj[2].offsetx, obj[2].trany+obj[2].offsety, obj[2].tranz+obj[2].offsetz) glRotatef(obj[1].rotx, 1.0, 0, 0) glRotatef(obj[1].roty, 0, 1.0, 0) glRotatef(obj[1].rotz, 0, 0, 1.0) glBegin(GL_QUADS) glColor3f(0.3,0.8,0.2) ' Back Face glVertex3f(0.0, 1.2, -0.5) glVertex3f(0.0, 1.7, -0.5) glVertex3f(4.0, 1.7, -0.5) glVertex3f(4.5, 1.2, -0.5) glColor3f(0.3,0.8,0.2) ' Front Face glVertex3f(4.5, 1.2, 0.5) glVertex3f(4.0, 1.7, 0.5) glVertex3f(0.0, 1.7, 0.5) glVertex3f(0.0, 1.2, 0.5) glColor3f(0.3,0.7,0.3) ' Top Face glVertex3f(4.0, 1.7, 0.5) glVertex3f(4.0, 1.7, -0.5) glVertex3f(0.0, 1.7, -0.5) glVertex3f(0.0, 1.7, 0.5) glColor3f(0.3,0.7,0.2) ' Bottom Face glVertex3f(0.0, 1.2, 0.5) glVertex3f(0.0, 1.2, -0.5) glVertex3f(4.5, 1.2, -0.5) glVertex3f(4.5, 1.2, 0.5) glEnd() glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45, (Float(slx)/Float(sly))*1.045, 600.0, 700.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(-397,284,-686.5) glRotatef(180,1.0,0.0,0.0) SetColor(255,255,255) DrawRect(0,0,slx/2,sly/2) EndFunction Function Tick() obj[0].roty:+0.01 If obj[0].roty>360 obj[0].roty:-360.0 EndIf obj[1].roty:+0.03 If obj[1].roty>360 obj[1].roty:-360.0 EndIf anglex:+0.01 If (anglex>360) anglex=0.0 EndIf angley:+0.02 If (angley>360) angley=0.0 EndIf EndFunction As you can see, this method is completely messy, and there are several problems with it, but hopefully someone else can improve this until we find a better way. NOTE: I've only tested this in windowed mode of 800*600, so it might be even worse in other modes :P |
| ||
You will suffer 'Gimbal Lock' problems with that camera rotation code. Use Google for explanations of it. A good way to avoid Gimbal Lock is using Quaternions. Tell me if you need the code for it, since I've got it working here. |
| ||
The camera rotation code is part of PaulJG's OpenGL Tuorial http://www.blitzbasic.com/Community/posts.php?topic=42662 so blame him :P Thanks for that tutorial PaulJG btw. Yeah, I know to use quaternians for rotation, especially if rotating around all 3 axis and you want to interpolate between frames. This was the only 3D code I had done in max, so just used that to test with the 2D stuff. I don't really care about how good/bad the 3D code is atm - it's not even mine :D. I just want a decent method of using 2D on 3D, and I know this isn't it, but thought it might help someone else come up with a decent method if they used this as a basis. |