OpenGL Point Sprites

Member
Posts: 215
Joined: 2008.06
Post: #1
Been poking around, trying to create a particle system and I stumbled across Point Sprites in OGL. Found this site which had some nice information: http://www.informit.com/articles/article...9&seqNum=7

Messed with it for a while and found that it refuses to use the textures I provide it. What I've gathered from this article is Point Sprites are a very easy and efficient way to render billboarded textures with lower bus traffic. So this follows that I thought these point sprites would render an entire texture for me without the need for extra vertices. Is this correct?

The sample image they provide on that page shows a scene with particles of varying sizes and textures. However, the code I will provide only renders a single pixel, no matter the size of the texture, and sometimes does not even take information from the texture, showing only a white dot. What's going on here?

Code:
//GLfloat sizes[2];
    //glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, sizes);
    
    BBSTexture* t = [BBSTexture loadTextureFromImageNamed:@"Artificial2.png"];
    
    
    glPushMatrix();
    
    /**
    glEnable([t type]);
    glBindTexture([t type], [t data]);
    glTexEnvi([t type], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexEnvi([t type], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    glBegin(GL_QUADS);
    {
        glTexCoord2f(0.0f, [t height]);
        glVertex2f(-1.0f, -1.0f);
        
        glTexCoord2f([t width], [t height]);
        glVertex2f(1.0f, -1.0f);
        
        glTexCoord2f([t width], 0.0f);
        glVertex2f(1.0f, 1.0f);
        
        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(-1.0f, 1.0f);
    }
    glEnd();
     **/
    
    glBindTexture([t type], [t data]);
    glEnable(GL_POINT_SPRITE);
    glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
    
    glBegin(GL_POINTS);
    //for (Particle* p in particles)
    //{
        //glVertex3f([p x], [p y], [p z]);
        glVertex3f(1.0f, 1.0f, 0.0f);
    //}
    glEnd();
    glPopMatrix();

The "Artificial2.png" is a 32x32 image. The glGetFloatv tells me that the number of pixels I am limited to is between 1 and 64, so this image should work.

So the biggest factor is probably the fact that the loaded textures have a type of GL_TEXTURE_RECTANGLE_EXT, but I've also tried it with GL_TEXTURE_2D and it still doesn't work. Help please. Thanks!

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #2
You never set the point size, or the point attenuation. So the point will rasterize with a 1 px diameter by default.

Also, you're passing invalid values to glTexEnv.
Quote this message in a reply
Member
Posts: 215
Joined: 2008.06
Post: #3
arekkusu Wrote:You never set the point size, or the point attenuation. So the point will rasterize with a 1 px diameter by default.

Also, you're passing invalid values to glTexEnv.

Thanks! Changed my code to the below. It now draws 32x32 squares, but it still does not have the textures. What am I missing now? Thanks.

Code:
    glPushMatrix();
    
    //GLuint tex = 45468113;
    
    glEnable(GL_POINT_SPRITE_ARB);
    float quadratic[] =  { 1.0f, 0.0f, 0.01f };
    glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic );
    glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 60.0f );
    
    glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 1.0f );
    glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, 64.0f );
    glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
    
    glPointSize(32.0f);
    
    glBegin(GL_POINTS);
    
    glColor3f(0.0f, 1.0f, 1.0f);
    for (Particle* p in particles)
    {
        glBindTexture([[p currentTexture] type], [[p currentTexture] data]);
        glVertex3f([p x], [p y], [p z]);
    }
    glEnd();
    glPopMatrix();

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Quote this message in a reply
Member
Posts: 45
Joined: 2008.04
Post: #4
you can't call glBindTexture() within a glBegin(..)-glEnd() block. Typically you would group the particles by texture and then render them in batches.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #5
I've added a How to Debug section to the OpenGL FAQ thread.

In this case, the first tip about checking for errors is the one you need to start using.
Quote this message in a reply
Member
Posts: 215
Joined: 2008.06
Post: #6
arekkusu Wrote:I've added a How to Debug section to the OpenGL FAQ thread.

In this case, the first tip about checking for errors is the one you need to start using.

Alright, following your advice on how to debug my application, I've found something somewhat unexpected:

glPushMatrix()
Error: GL_STACK_OVERFLOW

What does this mean, what does this effect, and how can I prevent it from happening? Despite having OpenGL Profiler and other tools working now (thanks arkkusu!) I'm still struggling to get Point Sprites working. It's not giving me errors for any other call other than glPushMatrix().

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #7
What does this mean? Your glPushMatrix and glPopMatrix calls aren't balanced. The matrix stacks aren't infinitely big-- if you push too many times in a row without popping, you overflow the stack. The stack size limits are all queryable, so you can figure out how much space you have to work in. Limits are driver specific, and are listed in this handy table. On Mac OS X, stack limits (like MAX_MODELVIEW_STACK_DEPTH) are the same across all hardware, but you'll see a different limit if you check the iPhone (or Windows, Linux, etc.)

What does this affect? When you overflow the stack, the matrix can't be pushed, so you can't restore it later. If you were rendering a hierarchy of objects where each child builds on the parent's transform (hand-bone connected to the arm-bone, etc) then your transforms will be wrong when you try to pop the stack, because your data was lost.

How can you prevent it? Find everywhere you push and pop and make sure the calls are balanced.

In a forward-looking application (i.e. written with OpenGL 3 or OpenGL ES 2 in mind) you won't use the matrix stacks at all, so you don't have this problem. Instead, you're responsible for doing all your own matrix math, and passing OpenGL the resulting matrix directly.
Quote this message in a reply
Moderator
Posts: 3,577
Joined: 2003.06
Post: #8
arekkusu Wrote:In a forward-looking application (i.e. written with OpenGL 3 or OpenGL ES 2 in mind) you won't use the matrix stacks at all, so you don't have this problem. Instead, you're responsible for doing all your own matrix math, and passing OpenGL the resulting matrix directly.

Or passing it your own software-transformed geometry... It never ends. You obviously have to keep track of your push/pop balance, because even if you do the transforms yourself and have your own standard custom combinations, you'll still wind up in situations where you will need arbitrary custom transform stacks anyway. There's just no practical way around it in the end: learn to keep track of push/pop balance, whether for the purpose of using existing OpenGL transform convenience routines, or eventually using your own some day.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #9
Yes, of course you'll have to track your own state. I meant that you won't have the problem of GL's arbitrarily sized stack limit.
Quote this message in a reply
Moderator
Posts: 3,577
Joined: 2003.06
Post: #10
Sorry. Blush I got hung up on the "you won't use the matrix stacks at all" snippet... [edit] ... and you'd still have to deal with your own stack limit one way or another, is what I meant [/edit]
Quote this message in a reply
Member
Posts: 215
Joined: 2008.06
Post: #11
Success! I have **FINALLY** gotten point sprites working correctly. After much struggling, frustration, and a slew of websites that offered little to no help whatsoever here is my answer:

To use textures with point sprites you need to do the following:

  1. Find out the limits of your point sprite implementation by using the glGetFloatv( GL_ALIASED_POINT_SIZE_RANGE, <float[2]>) call. This will populate your <float[2]> with the upper and lower limits for your texture sizes (generally, but not always, 1 and 64).
  2. Load in your texture, enable it's type (I believe that it MUST be GL_TEXTURE_2D), and bind the texture.
  3. Enable GL_POINT_SPRITE_ARB and set attenuation, fade thresholds, and pass in the min and max sizes.
  4. Set texture coordinate replacement parameters using glTexEnvi( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE).
  5. Specify your point size, using glPointSize(<float>) and (optionally, mostly for particle systems) turn off the depth mask.
  6. Call glBegin( GL_POINTS ), specify 3d vertices, and then glEnd.


Here is the exact code I am using. The loadPoTTextureFromImageNamed: call returns a texture containing GLuint data and a GL_TEXTURE_2D type. Other than that, it's all pretty self explanatory. Let me know if you find something out of whack. Hope it helps!

Code:
//Make space for particle limits and fill it from OGL call.
GLfloat sizes[2];
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, sizes);
    
//Create the texture we want to use.
BBSTexture* t = [BBSTexture loadPoTTextureFromImageNamed:@"Particle1.png"];
    
//Enable our texture type (in this case, it must be GL_TEXTURE_2D)
glEnable([t type]);
    
//Bind the texture data.
glBindTexture([t type], [t data]);
    
//Enable blending and set for particles
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    
//Enable point sprites and set params for points.
glEnable(GL_POINT_SPRITE_ARB);
float quadratic[] =  { 1.0f, 0.0f, 0.01f };
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic );
glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 60.0f );
    
//Tell it the max and min sizes we can use using our pre-filled array.
glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, sizes[0] );
glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, sizes[1] );
    
//Tell OGL to replace the coordinates upon drawing.
glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
    
//Set the size of the points.
glPointSize(32.0f);
    
//Turn off depth masking so particles in front will not occlude particles behind them.
glDepthMask(GL_FALSE);
    
//Save the current transform.
glPushMatrix();
    
//Begin drawing points.
glBegin(GL_POINTS);
//Iterate through our particles, setting the color and specifying their position.
for (Particle* p in particles)
{
    glColor4f([[p color] magnitudeX], [[p color] magnitudeY] - [p lifespan], [[p color] magnitudeZ] - ([p lifespan] * 2), [[p color] magnitudeW]);
    glVertex3f([p x], [p y], [p z]);
}
glEnd();    //Stop drawing points.
    
//Return to the previous matrix.
glPopMatrix();

I am painfully aware that there are a lot of ways to optimize this, but I feel this example code is more demonstrative than if I had enables and disables elsewhere. Again, I hope that this helps.

Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  OpenGL Texture Loading &amp; Sprites corporatenewt 2 11,089 Jan 30, 2008 12:39 PM
Last Post: ynda20
  Fast OpenGL Sprites Holmes 8 5,999 Sep 2, 2004 12:19 AM
Last Post: Holmes
  openGL and SDL question (loading and using sprites) KidTsunami 7 5,831 Jun 13, 2003 04:04 PM
Last Post: OneSadCookie
  Where to save sprites in memory in OpenGL? forseti 6 4,535 Aug 6, 2002 10:06 AM
Last Post: DaFalcon