How gl_LaunchIDEXT Works in GLSL Ray Tracing

This article explains how the gl_LaunchIDEXT built-in variable identifies the current ray launch thread coordinates in GLSL ray tracing pipelines. It covers the data structure of the variable, how the hardware maps it from the API dispatch call, its role in converting pixel indices into world-space rays, and how it interacts with the overall launch grid dimensions.

Definition and Data Type

In GLSL, gl_LaunchIDEXT is an input variable provided by the GL_EXT_ray_tracing extension. It is defined as a 3D unsigned integer vector:

in uvec3 gl_LaunchIDEXT;

This variable represents the unique integer coordinates of the current execution thread within the overall ray tracing dispatch. Each invocation of a ray generation shader receives its own distinct gl_LaunchIDEXT value, corresponding directly to its position within the launch grid.

Thread Identification Mechanism

When an application issues a ray tracing dispatch command via the graphics API (such as vkCmdTraceRaysKHR in Vulkan), it specifies a three-dimensional grid size comprising width, height, and depth. The hardware scheduler instantiates a thread for every cell in this grid.

The coordinate assignment works as follows:

  • Indexing Range: Coordinates run from (0, 0, 0) up to (width - 1, height - 1, depth - 1).
  • Discrete Identification: gl_LaunchIDEXT.x corresponds to the current column, gl_LaunchIDEXT.y corresponds to the current row, and gl_LaunchIDEXT.z corresponds to the layer or slice of the dispatch.
  • Dimensional Flexibility: Although ray tracing is typically performed for 2D render targets—where depth is set to 1 and gl_LaunchIDEXT.z remains 0—the third dimension allows for multi-layer rendering, stereoscopic setups, or volumetric data generation.

Mapping Coordinates to Ray Generation

The primary function of gl_LaunchIDEXT occurs in the ray generation shader, where it maps an execution thread to an output pixel or sample. Because gl_LaunchIDEXT provides integer coordinates, it must be converted into normalized coordinates to compute the primary camera ray.

A standard implementation converts gl_LaunchIDEXT to normalized device coordinates (NDC) using the corresponding grid dimensions stored in gl_LaunchSizeEXT:

// Add 0.5 to sample the center of the pixel
vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5);
vec2 inUV = pixelCenter / vec2(gl_LaunchSizeEXT.xy);
vec2 d = inUV * 2.0 - 1.0;

// Transform NDC to view-space/world-space ray directions
vec4 target = invProjection * vec4(d.x, d.y, 1.0, 1.0);
vec3 rayDirection = (invView * vec4(normalize(target.xyz), 0.0)).xyz;
vec3 rayOrigin = (invView * vec4(0.0, 0.0, 0.0, 1.0)).xyz;

Through this mechanism, each thread uses its ID to calculate the precise angle and starting point of the ray it is responsible for tracing into the scene.

Storing and Writing Results

Beyond ray computation, gl_LaunchIDEXT determines where to write the final color or payload data. Once scene traversal and shading conclude, the ray generation shader uses gl_LaunchIDEXT.xy directly as the write coordinates for storage images using functions like imageStore():

imageStore(outputImage, ivec2(gl_LaunchIDEXT.xy), vec4(finalColor, 1.0));

This guarantees that the computed radiance for a given launch index maps deterministically to the corresponding pixel in the target frame buffer.