2009-05-25 12 views
10

Estaba tratando de configurar los sprites de puntos en OpenGL para cambiar el tamaño con la distancia tal como lo haría un sprite con billboarded, pero no puedo obtener los valores en GL_POINT_DISTANCE_ATTENUATION_ARB para hacer algo útil. ¿Hay una correlación de valores a esto que coincida con una proyección dada? ¿Es lo que estoy tratando de hacer posible?¿Es posible utilizar sprites de puntos OpenGL para simular sprites de vallas publicitarias?

Render código que se utiliza:

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); 

Respuesta

7

Así es como hago el enfoque de mi pobre hombre para escalar el tamaño de punto:

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; 
} 

Puede hacer lo que quiera en el fragment shader, pero usted tiene que calcular el color, la iluminación y la textura usted mismo.

1

En mi experiencia atenuación tamaño de punto es no vale la pena. Es mucho mejor escribir un sombreador de vértices GLSL muy simple que establece el tamaño del punto manualmente de acuerdo con algún cálculo que realice por su cuenta. Me tomó alrededor de medio día aprender de cero todo el GLSL que necesitaba para que esto sucediera.

El código GLSL puede ser tan simple como estas pocas líneas:

attribute float psize; 

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

Dónde psize es el parámetro de tamaño de punto el usuario elige.

2

Aparte de GLSL, hacer lo que quiera es bastante simple con la atenuación de la distancia. Al ver cómo el tamaño de las cosas proyectadas disminuye cuadráticamente con su distancia en las proyecciones de perspectiva, solo necesita usar el factor cuadrático.

Si desea utilizar el tamaño de punto que establece manualmente a una distancia de, digamos, 150 unidades del ojo, simplemente use 1/(150^2) como factor cuadrático (y cero para los factores constantes y lineales - en todo caso, puede usar un número pequeño como 0.01 para el factor constante solo para evitar posibles divisiones en cero).

0

Sólo echar un vistazo en el código pmviewer.sourceforge.net está usando sprites de punto y cada punto tiene un color propio y tamaño para simular la interpretación del volumen: El vertex shader es:

vertexShader

// with ATI hardware, uniform variable MUST be used by output 
    // variables. That's why win_height is used by gl_FrontColor 
    attribute float a_hsml1; 
    uniform float win_height; 
    uniform vec4 cameralocin; 
    void main() 
    { 
    vec4 position=gl_ModelViewMatrix*gl_Vertex; 
    vec4 cameraloc=gl_ModelViewMatrix*cameralocin; 
    float d=distance(vec3(cameraloc),vec3(position)); 
    float a_hsml=gl_Normal.x; 
    float pointSize=win_height*a_hsml/d; // <- point diameter in 
             //pixels (drops like sqrt(1/r^2)) 
    gl_PointSize=pointSize; 
    gl_TexCoord[0]=gl_MultiTexCoord0; 
    gl_Position=ftransform(); 
    gl_FrontColor=vec4(gl_Color.r,gl_Color.g,gl_Color.b,gl_Color.a); 
    } 

Pixelshader

uniform sampler2D splatTexture; 
void main() 
{ 
vec4 color = gl_Color * texture2D(splatTexture, gl_TexCoord[0].st); 
gl_FragColor = color;\n" 
} 

sólo para enviar partículas a la GPU:

void PutOneArrayToGPU(unsigned int m_vbo, float *hArray, unsigned int num) 
{ 
glBindBuffer(GL_ARRAY_BUFFER, m_vbo); 
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * num, hArray, GL_STATIC_DRAW); 
int size = 0; 
glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); 
if ((unsigned)size != (sizeof(float) *num)) 
    { 
    fprintf(stderr, "WARNING: Pixel Buffer Object allocation failed!\n"); 
    fprintf(stderr, "TurningOff the GPU accelerated rendering\n"); 
    flag_GpuRender=false; 
    } 
return flag_GpuRender; 
} 

Entonces hacerlas:

void DrawPointsByGPU() 
    { 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glBindBuffer(GL_ARRAY_BUFFER, m_vboPos); 
    glVertexPointer(3, GL_FLOAT, 0, 0); 

    glEnableClientState(GL_COLOR_ARRAY); 
    glBindBuffer(GL_ARRAY_BUFFER, m_vboColor); 
    glColorPointer(4, GL_FLOAT, 0, 0); 

    glEnableClientState(GL_NORMAL_ARRAY); 
    glBindBuffer(GL_ARRAY_BUFFER, m_vboHSML); 
    glNormalPointer(GL_FLOAT, 3*sizeof(float), 0); 

    glDrawArrays(GL_POINTS, 0, m_numParticles); 

    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glDisableClientState(GL_NORMAL_ARRAY); 
    glDisableClientState(GL_COLOR_ARRAY); 
    glDisableClientState(GL_VERTEX_ARRAY); 

    }; 
Cuestiones relacionadas