Render large circular points in modern OpenGL

2019-01-14 14:21发布

问题:

I want to render filled circles of a dynamically varying radius around a set of points whose 2D coordinates are stored in a VBO. So far I was using GL_POINT_SMOOTH, but having now shifted to OpenGL 4.0, this option is no longer available. I have seen a similar question here but that doesn't quite suit my need because the centres of the circles in that example are hard-coded in the fragment shader. How would I do this?

At the moment, my vertex shader looks like this:

#version 400

layout(location=0) in vec2 in_Position;
layout(location=1) in vec4 in_Color;
out vec4 ex_Color;

uniform vec4 bounds;

void main(void){
    float x = -1+2/(bounds.y-bounds.x)*(in_Position.x-bounds.x);
    float y = -1+2/(bounds.w-bounds.z)*(in_Position.y-bounds.z);
    gl_Position = vec4(x,y,0,1);
    ex_Color = in_Color;
}

And my fragment shader looks like this:

#version 400

in vec4 ex_Color;
out vec4 out_Color;

void main(void){
    out_Color = ex_Color;
}

With these shaders, I am getting square points.

回答1:

The "modern" way of drawing points works like this:

  1. Enable program point size mode:

    glEnable(GL_PROGRAM_POINT_SIZE);
    
  2. Render vertices with GL_POINTS primitive mode.

  3. In the vertex shader, set the built-in variable gl_PointSize to the desired size of the individual point:

    gl_Position = ...;
    gl_PointSize = ...;
    

    The value used for this point size could be constant if it's always the same, a uniform if you want to be able to adjust it between draw calls, or a vertex attribute if the point size is variable per point.

  4. This will generate fragments for a square point of the size specified by the value of gl_PointSize. In the fragment shader, you can use the built-in gl_PointCoord variable, which gives you the relative coordinate of the fragment within the point. It works very similarly to texture coordinates, providing a range of [0, 1] in each direction.

    For example, if you want textured points, which is very useful for particle systems, the fragment shader code could contain:

    outColor = texture(particleTex, gl_PointCoord);
    

    Or if you want round points, you can discard everything outside a circle based on the distance from the center:

    vec2 circCoord = 2.0 * gl_PointCoord - 1.0;
    if (dot(circCoord, circCoord) > 1.0) {
        discard;
    }
    

    Or similarly, you can make the fragments outside the circle transparent, and enable blending, to get round points.

Note that the range of supported point sizes is implementation dependent. You can query the available range with:

GLfloat sizeRange[2] = {0.0f};
glGetFloatv(GL_POINT_SIZE_RANGE, sizeRange);


标签: opengl-4