Change the quad size in geometry shader for point rendering

Hi,

I would like to render point clouds using geometry shader. In the shader, I generate a quad for each point, the quad size is measured in object space, say 1 unit.

This may be good enough if the eye is closer to the scene, in which 1 unit is enough to cover several pixels. However if the eye is far from the scene, 1 unit is too small to occupy a single pixel and the point clouds seems to blinking.

So I would like to test if the offset value is larger than a minimum value, if not set it to the minimum.

However, I have tried some codes, it doesn’t seem to work.

Below is my vertex and geometry shader. I can only use opengl 2.1, to be backward compatible.

Vertext

#version 120
#extension GL_EXT_gpu_shader4 : enable
#extension GL_ARB_explicit_attrib_location : enable
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_geometry_shader4 : enable

layout(location = 6) attribute float label;
varying vec4 vColor;
uniform vec4 classColors[2];
void main(){
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    int index = int(round(label));
    
    if (index < 2) {
        vColor = classColors[index];    
    } else {
        vColor = vec4(0.0, 0.0, 0.0, 1.0);    
    }
}

Geometry

#version 120
#extension GL_EXT_gpu_shader4 : enable
#extension ARB_explicit_attrib_location : enable
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_geometry_shader4 : enable

const vec4 corners[4] = vec4[](vec4(-0.5, -0.5, 0.0, 0.0), vec4(0.5, -0.5, 0.0, 0.0), vec4(-0.5, 0.5, 0.0, 0.0), vec4(0.5, 0.5, 0.0, 0.0));
const vec2 uvs[4] = vec2[](vec2(0.0, 0.0),vec2(1.0, 0.0),vec2(0.0, 1.0),vec2(1.0, 1.0));

varying in vec4 vColor[];

varying out vec4 gColor;
varying out vec2 gUV;

void main(){
    // point size
    float d = 1.0;
    for(int i = 0; i < 4; ++i){
        vec4 offset = gl_ProjectionMatrix * (corners[i] * d);
        vec2 xy = offset.xy;
        if (length(xy) < 0.01)
            offset.xy = normalize(xy) * 0.01;
        gl_Position = gl_PositionIn[0] + offset;
        gUV = uvs[i];
        gColor = vColor[0];
        EmitVertex();
    }
    EndPrimitive();
}

I think, the relavent part is to modify here

vec2 xy = offset.xy;
        if (length(xy) < 0.01)
            offset.xy = normalize(xy) * 0.01;

Thanks,

Han

First, is there a reason not to use point sprites (glEnable(GL_POINT_SPRITE))? That will be more efficient than using a geometry shader to convert points to triangle strips. Point sprites are available in OpenGL 2.0 and later.

Other than that, the way to generate a fixed size in screen space is to multiply by gl_Position.w.