gl_PointSize and GL_PROGRAM_POINT_SIZE in GLSL
In OpenGL and GLSL, rendering point primitives
(GL_POINTS) requires defining their screen-space
dimensions. When the GL_PROGRAM_POINT_SIZE capability is
enabled via the OpenGL API, point sizing control is handed directly to
the shader pipeline through the built-in output variable
gl_PointSize. This bypasses the static, global point size
defined on the CPU, allowing developers to compute dynamic, per-vertex
point sizes directly on the GPU.
Default State vs. Enabled State
By default, desktop OpenGL relies on the global state function
glPointSize(float size) to determine point dimensions. When
GL_PROGRAM_POINT_SIZE is disabled:
- OpenGL ignores any values assigned to
gl_PointSizeinside the vertex or geometry shaders. - All rendered points use the fixed diameter specified by the host
application via
glPointSize().
Once enabled on the CPU side using
glEnable(GL_PROGRAM_POINT_SIZE), the pipeline behavior
changes:
- The rasterizer ignores the global
glPointSize()state. - The rasterizer reads the float value assigned to
gl_PointSizefrom the last active vertex-processing stage (Vertex Shader, Tessellation Evaluation Shader, or Geometry Shader).
Behavior in the Shader Pipeline
When GL_PROGRAM_POINT_SIZE is enabled, setting
gl_PointSize becomes the responsibility of the shader:
- Pixel Dimensions: The value written to
gl_PointSizedefines the width and height of the point primitive in window coordinates (pixels). For example, settinggl_PointSize = 10.0;rasterizes a 10x10 pixel square centered on the vertex's projected position. - Undefined Output: If the capability is enabled but
the shader fails to assign a value to
gl_PointSize, the resulting point size is undefined. On many drivers, this falls back to 1.0 pixel or leads to rendering artifacts. - Per-Vertex Variation: Because
gl_PointSizeis written per vertex, sizes can be calculated dynamically based on vertex attributes or camera distance. A common application is distance attenuation:
// Attenuate point size based on distance in view space
gl_PointSize = baseSize / -viewPosition.z;Clamping and Hardware Limits
The value assigned to gl_PointSize is subject to
hardware-dependent boundary constraints:
- Size Limits: Values are clamped to the supported
point size range provided by the graphics driver. This range can be
queried on the CPU side using
glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range). - Zero or Negative Values: If
gl_PointSizeevaluates to a value less than or equal to zero, the rasterizer typically discards the primitive, resulting in no fragments being generated.
OpenGL Core Profile and OpenGL ES Differences
In standard Desktop OpenGL Compatibility and Core Profiles,
GL_PROGRAM_POINT_SIZE must be explicitly toggled with
glEnable().
In contrast, OpenGL ES and WebGL do not require enabling
GL_PROGRAM_POINT_SIZE. In those APIs, writing to
gl_PointSize inside the vertex shader is always enabled and
is the mandatory method for sizing GL_POINTS.