How gl_GeometryIndexEXT Distinguishes BLAS Geometries
In Vulkan ray tracing using GLSL, gl_GeometryIndexEXT is
a built-in input variable that uniquely identifies distinct geometric
subsets combined within a single Bottom-Level Acceleration Structure
(BLAS). This article explains how the index is assigned during
acceleration structure creation, which shader stages can access it, and
how developers utilize it to look up geometry-specific material and
vertex data efficiently without creating separate acceleration
structures.
The Role of Multiple Geometries in a BLAS
When setting up ray tracing through the
VK_KHR_ray_tracing_pipeline extension, a BLAS is built from
an array of geometry descriptions
(VkAccelerationStructureGeometryKHR). Rather than creating
a separate BLAS for every mesh, developers often pack multiple
geometries—such as different parts of a complex object or distinct
meshes that share the same transform—into a single BLAS.
Inside the shader pipeline, gl_GeometryIndexEXT serves
as the zero-based index representing the specific geometry description
that an active ray has intersected.
How Indexing Works
The value of gl_GeometryIndexEXT corresponds directly to
the order of the geometries submitted to the acceleration structure
build command:
- Array Submission Order: During the BLAS build,
geometries are provided via the
pGeometriesorppGeometriesarray inVkAccelerationStructureBuildGeometryInfoKHR. - Implicit Index Assignment: The driver assigns a
sequential, zero-based integer to each entry. The geometry defined at
array element
0receives an index of0, array element1receives1, and so on up to \(N-1\) geometries. - Hardware Traversal Tracking: When a ray traverses
the acceleration structure and tests primitives, the intersection
hardware tracks both the primitive index within the geometry and the
index of the geometry itself. Upon hitting a primitive, that geometry's
array index is passed to the execution environment as
gl_GeometryIndexEXT.
Shader Availability
To use gl_GeometryIndexEXT, the shader must enable the
ray tracing extension:
#extension GL_EXT_ray_tracing : requireThe variable is available as a read-only int in the
following ray tracing stages:
- Any-Hit Shader (
.rahit): Evaluates intersections, often used for alpha-testing transparency. - Closest-Hit Shader (
.rchit): Executes after the closest intersection is determined to calculate surface shading. - Intersection Shader (
.rint): Executes during procedural geometry testing.
Structural Distinction in the Hierarchy
To uniquely locate any primitive in a scene, the ray tracing pipeline provides three hierarchical levels of identifiers:
gl_InstanceCustomIndexEXT(orgl_InstanceID): Identifies the instance within the Top-Level Acceleration Structure (TLAS).gl_GeometryIndexEXT: Identifies the specific mesh or geometry description within the referenced BLAS.gl_PrimitiveID: Identifies the specific triangle or procedural primitive within that geometry.
Practical Application: Material and Buffer Fetching
The primary use case for gl_GeometryIndexEXT is fetching
per-geometry resources, such as distinct materials, textures, or
vertex/index buffer addresses.
Instead of routing every geometry through separate shader binding table (SBT) hit groups, developers typically use a single hit group per material domain and index into descriptor arrays dynamically:
struct GeometryData {
uint64_t vertexBufferAddress;
uint64_t indexBufferAddress;
int materialIndex;
};
layout(binding = 0, set = 0) readonly buffer GeometryBuffer {
GeometryData geometries[];
} sceneGeometries;
void main() {
// Retrieve metadata for the specific geometry hit
GeometryData currentGeo = sceneGeometries.geometries[gl_GeometryIndexEXT];
// Access the geometry-specific material
int matID = currentGeo.materialIndex;
// Process lighting and shading...
}By leveraging gl_GeometryIndexEXT, rendering engines can
merge multiple static meshes into unified BLAS instances, minimizing
driver overhead and significantly reducing total acceleration structure
memory consumption.