# OpenGL 2D sprites in OpenGL using 3D coordinates

## Recommended Posts

FireNet    187
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);
glTranslatef(0,0,-2);

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

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++)
{

//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 on other sites
haegarr    7372
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 on other sites
FireNet    187
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 on other sites
lightbringer    1070
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 on other sites
Or you could try my approach written in the forum FAQ.

##### Share on other sites
FireNet    187
Quote:
 Original post by lightbringerAs 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 ProjectionWith 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 on other sites
Kwizatz    1392
Quote:
 Original post by FireNetBut 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 FireNetwhat 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 on other sites
Kalidor    1087
Quote:
 Original post by FireNetBut 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 on other sites
lightbringer    1070
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 on other sites
FireNet    187
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 on other sites
Trienco    2555
My guess? The very typical and usual mistake of doing

glOrtho(0, vPort[2], 0, vPort[3], -100, 100);
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 on other sites
FireNet    187
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 on other sites
Kalidor    1087
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 on other sites
FireNet    187
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:

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

Some info I found useful ;)
Quote:
 Source: MSDNglGetIntegerv(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.glViewportThe glViewport function sets the viewport.void glViewport( GLint x, GLint y, GLsizei width, GLsizei height);Parametersx, 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.

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 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.

## Create an account

Register a new account

• ### Similar Content

• I'm trying to get some legacy OpenGL code to run with a shader pipeline,
The legacy code uses glVertexPointer(), glColorPointer(), glNormalPointer() and glTexCoordPointer() to supply the vertex information.
I know that it should be using setVertexAttribPointer() etc to clearly define the layout but that is not an option right now since the legacy code can't be modified to that extent.
I've got a version 330 vertex shader to somewhat work:
#version 330 uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; layout(location = 0) in vec4 Vertex; layout(location = 2) in vec4 Normal; // Velocity layout(location = 3) in vec3 TexCoord; // TODO: is this the right layout location? out VertexData { vec4 color; vec3 velocity; float size; } VertexOut; void main(void) { vec4 p0 = Vertex; vec4 p1 = Vertex + vec4(Normal.x, Normal.y, Normal.z, 0.0f); vec3 velocity = (osg_ModelViewProjectionMatrix * p1 - osg_ModelViewProjectionMatrix * p0).xyz; VertexOut.velocity = velocity; VertexOut.size = TexCoord.y; gl_Position = osg_ModelViewMatrix * Vertex; } What works is the Vertex and Normal information that the legacy C++ OpenGL code seem to provide in layout location 0 and 2. This is fine.
What I'm not getting to work is the TexCoord information that is supplied by a glTexCoordPointer() call in C++.
Question:
What layout location is the old standard pipeline using for glTexCoordPointer()? Or is this undefined?

Side note: I'm trying to get an OpenSceneGraph 3.4.0 particle system to use custom vertex, geometry and fragment shaders for rendering the particles.

• Hi i am new to this forum  i wanted to ask for help from all of you i want to generate real time terrain using a 32 bit heightmap i am good at c++ and have started learning Opengl as i am very interested in making landscapes in opengl i have looked around the internet for help about this topic but i am not getting the hang of the concepts and what they are doing can some here suggests me some good resources for making terrain engine please for example like tutorials,books etc so that i can understand the whole concept of terrain generation.

• By KarimIO
Hey guys. I'm trying to get my application to work on my Nvidia GTX 970 desktop. It currently works on my Intel HD 3000 laptop, but on the desktop, every bind textures specifically from framebuffers, I get half a second of lag. This is done 4 times as I have three RGBA textures and one depth 32F buffer. I tried to use debugging software for the first time - RenderDoc only shows SwapBuffers() and no OGL calls, while Nvidia Nsight crashes upon execution, so neither are helpful. Without binding it runs regularly. This does not happen with non-framebuffer binds.
GLFramebuffer::GLFramebuffer(FramebufferCreateInfo createInfo) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); textures = new GLuint[createInfo.numColorTargets]; glGenTextures(createInfo.numColorTargets, textures); GLenum *DrawBuffers = new GLenum[createInfo.numColorTargets]; for (uint32_t i = 0; i < createInfo.numColorTargets; i++) { glBindTexture(GL_TEXTURE_2D, textures[i]); GLint internalFormat; GLenum format; TranslateFormats(createInfo.colorFormats[i], format, internalFormat); // returns GL_RGBA and GL_RGBA glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, createInfo.width, createInfo.height, 0, format, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); DrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, textures[i], 0); } if (createInfo.depthFormat != FORMAT_DEPTH_NONE) { GLenum depthFormat; switch (createInfo.depthFormat) { case FORMAT_DEPTH_16: depthFormat = GL_DEPTH_COMPONENT16; break; case FORMAT_DEPTH_24: depthFormat = GL_DEPTH_COMPONENT24; break; case FORMAT_DEPTH_32: depthFormat = GL_DEPTH_COMPONENT32; break; case FORMAT_DEPTH_24_STENCIL_8: depthFormat = GL_DEPTH24_STENCIL8; break; case FORMAT_DEPTH_32_STENCIL_8: depthFormat = GL_DEPTH32F_STENCIL8; break; } glGenTextures(1, &depthrenderbuffer); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, createInfo.width, createInfo.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthrenderbuffer, 0); } if (createInfo.numColorTargets > 0) glDrawBuffers(createInfo.numColorTargets, DrawBuffers); else glDrawBuffer(GL_NONE); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout << "Framebuffer Incomplete\n"; glBindFramebuffer(GL_FRAMEBUFFER, 0); width = createInfo.width; height = createInfo.height; } // ... // FBO Creation FramebufferCreateInfo gbufferCI; gbufferCI.colorFormats = gbufferCFs.data(); gbufferCI.depthFormat = FORMAT_DEPTH_32; gbufferCI.numColorTargets = gbufferCFs.size(); gbufferCI.width = engine.settings.resolutionX; gbufferCI.height = engine.settings.resolutionY; gbufferCI.renderPass = nullptr; gbuffer = graphicsWrapper->CreateFramebuffer(gbufferCI); // Bind glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); // Draw here... // Bind to textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[0]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textures[1]); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textures[2]); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); Here is an extract of my code. I can't think of anything else to include. I've really been butting my head into a wall trying to think of a reason but I can think of none and all my research yields nothing. Thanks in advance!

• Hi everyone, I've shared my 2D Game Engine source code. It's the result of 4 years working on it (and I still continue improving features ) and I want to share with the community. You can see some videos on youtube and some demo gifs on my twitter account.
This Engine has been developed as End-of-Degree Project and it is coded in Javascript, WebGL and GLSL. The engine is written from scratch.
This is not a professional engine but it's for learning purposes, so anyone can review the code an learn basis about graphics, physics or game engine architecture. Source code on this GitHub repository.
I'm available for a good conversation about Game Engine / Graphics Programming
• By C0dR
I would like to introduce the first version of my physically based camera rendering library, written in C++, called PhysiCam.
Physicam is an open source OpenGL C++ library, which provides physically based camera rendering and parameters. It is based on OpenGL and designed to be used as either static library or dynamic library and can be integrated in existing applications.

The following features are implemented:
Physically based sensor and focal length calculation Autoexposure Manual exposure Lense distortion Bloom (influenced by ISO, Shutter Speed, Sensor type etc.) Bokeh (influenced by Aperture, Sensor type and focal length) Tonemapping
You can find the repository at https://github.com/0x2A/physicam

I would be happy about feedback, suggestions or contributions.

• 10
• 10
• 18
• 9
• 9