Search code examples
openglspritescale

Drawing unscaled 2D symbols (sprites) using OpenGL and VBOs


Here's the basic situation: I have an OpenGL VBO that draws a 2D symbol (e.g., a polygon or a line strip, or whatever--essentially a simple sprite). I've defined the vertices around the origin (0, 0) and such that I will get the desired symbol size in screen pixels.

My current scene has been translated and scaled and ortho-projected to show a particular region of the model. I now want to draw the symbol such that it is centered at a specific model location but not scaled with the model (i.e., draws to the screen pixel size as defined in the VBO). I'd prefer to do this without having to programmatically re-fill the vertex buffer for the symbol (i.e., I'd like to use translation and/or scaling to draw the symbol in screen pixels but at the desired location--which is defined in "model" coordinates).

A simple example: A map using longitude and latitude is displayed and the user has panned and zoomed to a specific area of the world. The user clicks on a site of interest, and I want to show a "star" at that point. The star will pan with the map but remain the same size as the user zooms in or out. So at any point I know where (in longitude, latitude coordinates) to "center" the star and I have a VBO defined (in pixel coordinates) for a star of the desired size (centered around an origin).

So, what is the "best" way to render the "unscaled" symbol/sprite in this case?

I think I have an idea of where to go with this, but (1) I'm not sure if the approach is quite right and (2) It doesn't seem to work as I expect it to. Here's some pseudo-code for my general idea:

void DrawSymbol()
{
    ...
    [Not Shown: Determine the screen coordinates of the symbol's desired model location]

    gl.MatrixMode(GL_PROJECTION);
    gl.PushMatrix();    // Store the current projection
    gl.LoadIdentity();  // Set projection to identity (no projection)

    gl.MatrixMode(GL_MODELVIEW);
    gl.PushMastrix();   // Store the current model view (was scaled and translated)
    gl.LoadIdentity();  // Set model view matrix to identity (1-to-1 with screen coords)

    [Not Shown: Translate the model view so that the origin is at the desired screen coordinate found above]

    [Not Shown: Draw the VBO for the symbol] // should draw to raw screen pixels, right?

    gl.MatrixMode(GL_MODELVIEW);
    gl.PopMatrix();     // Set model view matrix to previous value -- should only effect any future renders, right?

    gl.MatrixMode(GL_PROJECTION);
    gl.PopMatrix();     // Set projection matrix to previous value -- again, should only effect any future renders, right?
    ...
}

I've tried this (actually, I tried it by directly rendered a simple LineStrip at the desired screen location rather than using a translated VBO--just for testing) and it didn't seem to work. Don't know why, though. Does the approach seem sound?

Suggestions?


Solution

    1. With your 3D projection set, project the 3D coordinate to screen coordinates.
    2. Now set up a ortho projection that maps 1:1 with screen pixels and use the window coordinates determined in 1. to draw the screen-space object.

    Now, whatever the zoom or perspective of the scene, the 2D object will remain at the same size and orientation.

    Hope this helps!