代码之家  ›  专栏  ›  技术社区  ›  zaratustra

是否可以使用OpenGL点精灵来模拟广告牌精灵?

  •  10
  • zaratustra  · 技术社区  · 15 年前

    我试着在OpenGL中设置点sprites来改变大小和距离,就像广告牌上的sprite一样,但是我无法获取 GL_POINT_DISTANCE_ATTENUATION_ARB 做任何有用的事。是否存在与给定投影匹配的值的相关性?我想做的是可能的吗?

    正在使用的呈现代码:

    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 );
    
    4 回复  |  直到 6 年前
        1
  •  7
  •   Eric    15 年前

    以下是我如何让我可怜的人缩小点数的方法:

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

    顶点着色器:

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

    你可以在片段着色中做你想做的任何事情,但是你必须自己计算颜色、灯光和纹理。

        2
  •  2
  •   Dolda2000    14 年前

    撇开glsl不谈,做你想做的事情是非常简单的距离衰减。在透视投影中,可以看到物体的投影大小随距离呈四次方减小,只需使用二次因子即可。

    如果要使用手动设置的点大小,例如距眼睛150个单位的距离,只需使用1/(150^2)作为二次因子(对于常量和线性因子为零,如果有任何情况,您可能需要使用一些较小的数字,如0.01作为常量因子,以避免可能被零分割)。

        3
  •  1
  •   shoosh    15 年前

    根据我的经验,点尺寸衰减不值得麻烦。您最好编写一个非常简单的glsl顶点明暗器,根据自己执行的计算手动设置点大小。我花了大约半天时间从零开始学习实现这一目标所需的所有GLSL。

    GLSL代码可能与以下几行代码一样简单:

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

    在哪里? psize 是用户选择的点大小参数。

        4
  •  0
  •   Arman    13 年前

    只需在pmviewer.sourceforge.net中查看,代码使用点精灵,每个点都有自己的颜色和大小来模拟体积渲染: 顶点明暗器是:

    顶点着色器

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

    像素着色

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

    只需将粒子发送到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;
    }
    

    然后渲染它们:

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