Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use OpenGL point sprites to simulate billboard sprites?

I was trying to set point sprites in OpenGL to change size with distance just as a billboarded sprite would, but I can't get the values in GL_POINT_DISTANCE_ATTENUATION_ARB to do anything useful. Is there a correlation of values to this that would match a given projection? Is what I'm trying to do even possible?

Render code being used:

glPointParameterfARB  = (PFNGLPOINTPARAMETERFARBPROC)wglGetProcAddress("glPointParameterfARB");
glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)wglGetProcAddress("glPointParameterfvARB");

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluPerspective(100.0, 800.0/600.0, 0.1, 10.0);

float quadratic[] =  { 5.0f, 0.1f, 10.0f };
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic );

float maxSize = 0.0f;
glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize );
if( maxSize > 100.0f )  maxSize = 100.0f;
glPointSize( maxSize );

glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 0.1f );
glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 0.1f );
glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, maxSize );

glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE );

glEnable( GL_POINT_SPRITE_ARB );

glScalef(0.75,1,1);
glTranslatef(0.00,0.0,-1.0);
glScalef(0.5,0.5,0.5);
glRotatef(counter*0.1+0.5,1.0,1.0,0.0);

glBegin( GL_POINTS );

for( int i = 0; i < 100; ++i )
{
    glColor4f( i%10*0.1, i/10*0.1, 0.5, 1.0f );

    glVertex3f( i%10*0.2-1.0,i/10*0.2-1.0,
    ((i%10-5)*(i%10-5)+(i/10-5)*(i/10-5))*0.01 );
}

glEnd();

glDisable( GL_POINT_SPRITE_ARB );
like image 272
zaratustra Avatar asked May 25 '09 19:05

zaratustra


3 Answers

Here's how I make my poor man's approach to scaling the point size:

void render() {
    glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
    glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
    glEnable(GL_POINT_SPRITE);
    glActiveTexture(GL_TEXTURE0);
    glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);

    /* Activate shader program here */
    /* Send pointSize to shader program */

    glBegin(GL_POINTS);
        /* Render points here */
        glVertex3f(...);
    glEnd(GL_POINTS);
}

Vertex shader:

uniform float pointSize;
void main() {
    gl_Position = ftransform();
    gl_PointSize = pointSize / gl_Position.w;
}

You can do whatever you want in the fragment shader, but you'll have to compute the color, lighting and texturing yourself.

like image 117
Eric Avatar answered Oct 10 '22 00:10

Eric


GLSL aside, doing what you want is pretty simple with distance attenuation. Seeing as how the projected size of things decreases quadratically with their distance in perspective projections, you only need to use the quadratic factor.

If you want to use the point size you manually set at a distance of, say, 150 units from the eye, just use 1/(150^2) as the quadratic factor (and zero for the constant and linear factors -- if anything, you may want to use some small number like 0.01 for the constant factor just to avoid potential divisions by zero).

like image 38
Dolda2000 Avatar answered Oct 10 '22 01:10

Dolda2000


In my experience point size attenuation isn't worth the trouble. You're much better off writing a very simple GLSL vertex shader that sets the point size manually according to some calculation you perform on your own. It took me about half a day to learn from scratch all the GLSL I needed to make this happen.

The GLSL code may be as simple as these few lines:

attribute float psize;

void main()
{   
    gl_FrontColor = gl_Color;
    gl_PointSize = psize;
    gl_Position = ftransform();
}

Where psize is the point size parameter the user chooses.

like image 44
shoosh Avatar answered Oct 10 '22 01:10

shoosh