Sign in to follow this  
FireNet

OpenGL 2D sprites in OpenGL using 3D coordinates

Recommended Posts

I am trying to use 2D sprites with OpenGL. This is NOT about texture mapping quads, but rather about the best ways to position sprites using 3d coordinates. I want to use the Depth buffer for ordering the sprites.
static int zPos;

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();                                     
	glTranslatef(0,0,-2);
        
        if(KeyPress(VK_UP))++zPos;
        else if(KeyPress(VK_DOWN))--zPos;
        
        
        glBegin(GL_QUADS);
        glColor3f(1,0,1);
          glVertex3i(0, 1,-10);
          glVertex3i(0,-1,-10);
          glVertex3i(-1,-1,-10);
          glVertex3i(-1,1,-10);
         glEnd();
        
        
        for(int i=0;i<3;i++)
        {
        glBegin(GL_QUADS);
        
        //Red
        glColor3f(1,0,0);
          glVertex3f(1, 1,zPos);
        
        //Yellow
        glColor3f(1,1,0);
          glVertex3f(1,-1,zPos);
        
        //Green
        glColor3f(0,1,0);
          glVertex3f(-1,-1,zPos);
        
        //Blue
        glColor3f(0,0,1);
          glVertex3f(-1,1,zPos);
         glEnd();
         
         glTranslatef(2,0,0.1);
        }

This is the little bit of code I've been experimenting with. I was thinking of using the zPos variable as like to represent layers, so that sprites with a deeper depth will go beneath and vice-versa. The problem, which is quite obvious is that the higher up sprites will be a bit bigger.... Any ideas on what to do? Is there a better way to do this ?

Share this post


Link to post
Share on other sites
You may switch to an equivalent orthogonal projection. Only perspective projection does a scaling dependent on the depth of occurance. (Perhaps some artifacts may occur if mixing two projection modes in one rendering pass.)

Else, of course a bottom-up ordered rendering would do the job, neglecting the need of different z values, but I assume you would not do so since it means to deny using the z buffer...

Also, you may specify a glScale per sprite to pre-undo the scaling. The scale factor is to be determined from the z value, of course, and to be applied to x and y elements only.

[Edited by - haegarr on December 3, 2005 7:20:33 AM]

Share this post


Link to post
Share on other sites
Ah... I dint get anything :(

Can anybody point me to some source of a 2D game done in opengl ?

Or just even give me some pointers on how to go about doing 2D in opengl..

Share this post


Link to post
Share on other sites
As haegarr stated, you want to use orthographic projection mode. Basically, the viewing volume becomes a box (instead of a cut-off pyramid), so coordinates are mapped on the screen without being scaled. Check out the red book, chapter 3. Scroll down to about halfway down the page to get to the theory and some code.

Edit: of course, if you are after billboards instead of sprites, and want to mix 2d and 3d in one environment, it's a completely different story. But I think that was not your intention?

Share this post


Link to post
Share on other sites
Quote:
Original post by lightbringer
As haegarr stated, you want to use orthographic projection mode. Basically, the viewing volume becomes a box (instead of a cut-off pyramid), so coordinates are mapped on the screen without being scaled. Check out the red book, chapter 3. Scroll down to about halfway down the page to get to the theory and some code.

Edit: of course, if you are after billboards instead of sprites, and want to mix 2d and 3d in one environment, it's a completely different story. But I think that was not your intention?



I am not after billboards ;)

Quote:

Orthographic Projection
With an orthographic projection, the viewing volume is a rectangular parallelepiped, or more informally, a box (see Figure 3-13 ). Unlike perspective projection, the size of the viewing volume doesn't change from one end to the other, so distance from the camera doesn't affect how large an object appears. This type of projection is used for applications such as creating architectural blueprints and computer-aided design, where it's crucial to maintain the actual sizes of objects and angles between them as they're projected.

Is that what you were pointing me to ?

But once you call glOrtho() then only the glVertex2.... commands work right?

what would be the best near, far clipping values



[
I am not trying to mix 2d and 3d. Just a plain sprite based game :)
I would really love to see some source which showed 2d in opengl
]


P.S Thanks Dwarf with Axe for this Last post about 2D in OpenGL (so please stop!)

Share this post


Link to post
Share on other sites
Quote:
Original post by FireNet
But once you call glOrtho() then only the glVertex2.... commands work right?


Wrong, glVertex3 commands would also work, I think you can uze the Z Value as a, well, z buffer.

Quote:
Original post by FireNet
what would be the best near, far clipping values


I use

glOrtho(-0.375f,width,height,-0.375f, 0.0f, 1.0f);

where width and height are the width and height of the window/screen.

Quote:
Original post by FireNet
[
I am not trying to mix 2d and 3d. Just a plain sprite based game :)
I would really love to see some source which showed 2d in opengl
]


Here is my code for a 2D interface for my GUI library.

Share this post


Link to post
Share on other sites
Quote:
Original post by FireNet
But once you call glOrtho() then only the glVertex2.... commands work right?
No.

All glOrtho does is create an orthographic projection matrix and multiplies the matrix on the top of the current matrix mode's stack by it. It is usually used on the projection matrix after it has been set to the identity. So in the normal usage, the only thing that changes is the projection matrix; the rest of OpenGL still works exactly the same way.

Share this post


Link to post
Share on other sites
As the others already stated, you still get to use the Z buffer with orthographic projection. The only thing that changes is how objects appear on the screen. If I understood your initial complaint, you didn't want them to scale with distance, and glOrtho() achieves that while keeping the "3D-ness" intact ^_^.

Share this post


Link to post
Share on other sites


void OGL_2D()
{
int vPort[4];

glGetIntegerv(GL_VIEWPORT, vPort);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

glOrtho(0, vPort[2], 0, vPort[3], -100, 100);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
}


void Render()
{
static float zPos = 0;

if(KeyPress(VK_ESCAPE))FlagQuit();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

if(KeyPress(VK_UP))++zPos;
else if(KeyPress(VK_DOWN))--zPos;


glBegin(GL_QUADS);
glColor3f(1,0,1);
glVertex3i(0, 1,-10);
glVertex3i(0,-1,-10);
glVertex3i(-1,-1,-10);
glVertex3i(-1,1,-10);
glEnd();


for(int i=0;i<3;i++)
{
glBegin(GL_QUADS);

//Red
glColor3f(1,0,0);
glVertex3f(1, 1,zPos);

//Yellow
glColor3f(1,1,0);
glVertex3f(1,-1,zPos);

//Green
glColor3f(0,1,0);
glVertex3f(-1,-1,zPos);

//Blue
glColor3f(0,0,1);
glVertex3f(-1,1,zPos);
glEnd();

glTranslatef(2,0,0.1);
}
}



This is my source atm and I get nothing on the screen. The set OGL_2D() was copied from Last post about 2D in OpenGL (so please stop!).

So what am I doing wrong here?

Share this post


Link to post
Share on other sites
My guess? The very typical and usual mistake of doing

glOrtho(0, vPort[2], 0, vPort[3], -100, 100);
instead of
glOrtho(0, vPort[2], vPort[3], 0, -100, 100);

hence everything is flipped upside down, hence an inverted winding order on your primitives and hence they are all backface culled (can you tell I like chicken?).

Also, if your viewport is ranging from 0-x then using negative coordinates doesn't make a lot of sense (unless you WANT them to be outside, of course). If you want the origin to be in the middle your glOrtho call should use +-vPort[x]/2

Share this post


Link to post
Share on other sites
I tried it :( and I still cant see anything


InitScene()
{
glShadeModel(GL_SMOOTH); // Enable smooth shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black background
glClearDepth(1.0f); // Depth buffer setup
glEnable(GL_DEPTH_TEST); // Enables depth testing
glDepthFunc(GL_LEQUAL); // The type of depth testing to do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really nice perspective calculations

return true;
}



My initialization code.... glClearDepth(1.0f) this causing the trouble?

If so what value should be passed to the function?


(Btw, the render function allows one to alter the z coordinates of 3 quads. So one can move them up and down along the z axis. This is just saying what the code is trying to do)

Share this post


Link to post
Share on other sites
You are using the viewport dimensions, probably the window size, for your orthographic projection. That makes each pixel on screen 1 unit2, making the quads you are rendering just a few pixels each. You are also drawing around the origin, which is in the lower left corner of the screen, so the parts of the quads with negative coordinates won't be on screen and you will only be rendering a pixel or two in the corner.

Share this post


Link to post
Share on other sites
Yee haaaaa,

I got something on my screen :).


void OGL_2D()
{
int vPort[4];

glGetIntegerv(GL_VIEWPORT, vPort);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

glOrtho(0, vPort[2], vPort[3], 0, -100, 100);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
}


void Render()
{
static float zPos = 0;

if(KeyPress(VK_ESCAPE))FlagQuit();

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(200,200,0);

if(KeyPress(VK_UP))++zPos;
else if(KeyPress(VK_DOWN))--zPos;


glBegin(GL_QUADS);
glColor3f(1,0,1);
glVertex3i(0, 1,-10);
glVertex3i(0,-1,-10);
glVertex3i(-1,-1,-10);
glVertex3i(-1,1,-10);
glEnd();


for(int i=0;i<3;i++)
{
glBegin(GL_QUADS);

//Red
glColor3f(100,0,0);
glVertex3f(100, 100,zPos);

//Yellow
glColor3f(100,100,0);
glVertex3f(100,-100,zPos);

//Green
glColor3f(0,1,0);
glVertex3f(-100,-100,zPos);

//Blue
glColor3f(0,0,1);
glVertex3f(-100,100,zPos);
glEnd();

glTranslatef(200,0,10);
}
}




Output:
Image Hosted by ImageShack.us

The origin (0,0) is the top left of the screen.

Some info I found useful ;)
Quote:

Source: MSDN

glGetIntegerv(GL_VIEWPORT, ...)
GL_VIEWPORT The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height.



glViewport

The glViewport function sets the viewport.

void glViewport(
GLint x,
GLint y,
GLsizei width,
GLsizei height
);

Parameters

x, y
The lower-left corner of the viewport rectangle, in pixels. The default is (0,0).
width, height
The width and height, respectively, of the viewport. When an OpenGL context is first attached to a window, width and height are set to the dimensions of that window.



Other Links:
Last post about 2D in OpenGL (so please stop!).
OpenGL Red Book
OpenGL FAQ
cprogramming.com: Projections in OpenGL
Hope someone with the same problem find these links as useful as I did



Thanks a lot all of you. You've been a great help.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
look at glRasterPos, it's not intuitive how to use it in perspective though.
Better is to switch to orthographic projection like people said.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this