ジオメトリシェーダでポイントスプライト

OpenGLに、ポイントスプライトという機能があります。

点(Vertex)に対してテクスチャを貼り付けて表示するもので、パーティクルの表示等によく使われるみたいです。

もうちょっと自由度ほしいなーというのと、シェーダのお勉強のために、同等の機能をシェーダを使って実装してみました。

  • バーテックスシェーダ

    CPUから渡された座標をそのままジオメトリシェーダに渡します。

    #version 120
    void main()
    {
     gl_Position = gl_Vertex;
    }
    
  • ジオメトリシェーダ

    四角形ポリゴンを作ってテクスチャ座標を指定します。

    ※GL_GEOMETRY_INPUT_TYPE_EXTにはGL_POINTSを、GL_GEOMETRY_OUTPUT_TYPE_EXTにはGL_TRIANGLE_STRIPを指定しておきます。

    #version 120
    #extension GL_EXT_geometry_shader4 : enable
    uniform vec2 size; // 描画サイズ(CPUからglUniform2fで渡す)
    void main() {
     gl_Position = gl_ModelViewProjectionMatrix * gl_PositionIn[0];
     gl_Position.x -= size.x/2;
     gl_Position.y += size.y/2;
     gl_TexCoord[0].st = vec2(0,0);
     EmitVertex();
     gl_Position.y -= size.y;
     gl_TexCoord[0].st = vec2(0,1);
     EmitVertex();
     gl_Position.x += size.x;
     gl_Position.y += size.y;
     gl_TexCoord[0].st = vec2(1,0);
     EmitVertex();
     gl_Position.y -= size.y;
     gl_TexCoord[0].st = vec2(1,1);
     EmitVertex();
    }
    
  • フラグメントシェーダ

    テクスチャを参照して色を設定します。

    #version 120
    uniform sampler2D tex0;
    void main (void)
    {
     gl_FragColor = texture2D(tex0, gl_TexCoord[0].st);
    }
    

CPU側では、表示したいテクスチャをglBindTextureしてglUniform1iした上でこんな感じで描画しましょう。

glBegin(GL_POINTS)
glVertex3d(x,y,z);
glEnd();