VisRTX is an experimental, scientific visualization-focused implementation of the Khronos ANARI standard.
VisRTX is designed to track ongoing developments of the ANARI standard and provide usable extensions where possible. Prospective backend implementors of ANARI are encouraged to use VisRTX as a much more complete example of a GPU-accelerated, ray tracing based implementation of ANARI.
Note that the ANARI implementation of VisRTX is a complete rewrite from previous
versions. Please refer to the v0.1.6 release of VisRTX for the previous
implementation.
VisRTX is supported on both Linux and Windows.
Building VisRTX requires the following:
- CMake 3.17+
- C++17 compiler
- NVIDIA Driver 530+
- CUDA 12+
- A GPU of compute capability 5.0 (Maxwell) or newer, or 7.5 (Turing) when
building with CUDA 13. Set
VISRTX_MIN_ARCHto raise that floor. - ANARI-SDK
Building VisRTX is done through invoking CMake on the source directory from a stand alone build directory. This might look like
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=path/to/desired/install /path/to/visrtx/source
make
make installThe OptiX and ANARI-SDK dependencies can be found via placing their installation
locations on CMAKE_PREFIX_PATH, either as an environment variable or a CMake
variable.
A successful build results in a single libanari_library_visrtx library that
will install to ${CMAKE_INSTALL_PREFIX}/lib, and is usable with any ANARI app
if either it is installed to the same location as the ANARI-SDK or
libanari_library_visrtx is placed on LD_LIBRARY_PATH respectively.
The following sections describes details of VisRTX's ANARI completeness, provided extensions, and known missing extensions to add in the future.
In addition to standard ANARI_KHR extensions, the following extensions are
also implemented in the visrtx device. Note that all extensions are subject to
change.
This extension indicates that applications can use pointers to CUDA device memory when created shared and captured arrays when using VisRTX. All the normal rules for shared and captured array data still apply.
This extension indicates that raw CUDA GPU buffers from frame objects can be
mapped for applications which are already using CUDA. Each enabled frame
channel has a CUDA counterpart that can be mapped:
"channel.colorCUDA""channel.depthCUDA""channel.albedoCUDA""channel.normalCUDA""channel.primitiveIdCUDA""channel.objectIdCUDA""channel.instanceIdCUDA"
GPU pointers returned by anariMapFrame() are device pointers intended to be
kept on the device. Applications which desire to copy data from the device back
to the host should instead map the ordinary (non-CUDA) channels.
Renderer-level camera-surface depth cueing on fast, interactive/default,
and quality, disabled by default. Supports linear, exponential, and
exponential-squared curves in world units, view-depth or camera-ray distance,
and constant linear RGB or the visible backdrop as the fog color. Coverage
alpha, misses, lighting transport, and geometric channels keep their existing
semantics. Debug/test Renderers and VisGL are outside this vendor extension.
See the fog contract and examples for discovery, parameters, validation, Commit behavior, and compatibility limits, and the conformance matrix for executable coverage.
Adds a rayBuffer camera whose primary rays are supplied per pixel by the
application. Each component is an optional ANARI_ARRAY2D whose dimensions
must match the frame size, indexed like the frame channels:
Parameters:
ray.org(FLOAT32_VEC3): ray origins (default: cameraposition).ray.dir(FLOAT32_VEC3): ray directions, normalized by the device (default: cameradirection).ray.tmin(FLOAT32): start of the ray interval (default:0).ray.tmax(FLOAT32): end of the ray interval (default:FLT_MAX).
Rays are not jittered and depth of field does not apply; imageRegion,
aspect, and up are ignored. If the buffer dimensions do not match the
frame size, a warning is issued and every ray misses.
The dataCentering parameter controls how spatial field data is interpreted
relative to the grid structure. This extension enables fine-grained control
over whether data values represent quantities at grid vertices (node-centered)
or at the center of grid cells (cell-centered).
Supported Values:
"node": Data is centered at grid vertices (node-centered). Each data value corresponds to a grid point."cell": Data is centered at cell centers. Each data value corresponds to the center of a voxel/cell.
Note
The spatial extent of a StructuredRegular volume depends on the dataCentering parameter.
When set to "node", the extent is [origin, origin + (data.size - 1) × spacing].
When set to "cell", the extent is [origin, origin + data.size × spacing].
Allows clipping a spatial field to an application-defined box in object space.
Two optional parameters on structuredRegular and nanovdb fields define the
box; omitting either leaves the bound open.
Parameters:
roi(FLOAT32_BOX3): the restriction box to apply (default: unbounded).
Adds coneAngle (float half-angle in radians, default pi/2, range [0,pi])
and coneSoftness (float fraction, default 0, range [0,1]) to quad lights.
Each enabled side emits about its own normal. Softness defines an inner angle
coneAngle*(1-coneSoftness) with smoothstep attenuation in angular space up to
the outer cutoff. Zero softness is a hard cutoff. Shaping multiplies radiance
without renormalizing power; the same restriction applies to illumination and
visible/reflected area-light proxies. The uniform area-sampling density is
unchanged. Unset parameters retain existing unshaped behavior.
The structuredRectilinear spatial field type provides efficient sampling of
structured grids with rectilinear (non-uniform) spacing. Unlike
structuredRegular which assumes uniform spacing, this type requires explicit
1D coordinate arrays for each axis.
Parameters:
data(ARRAY3D): The 3D voxel datacoordsX(ARRAY1D): X-axis coordinates (required)coordsY(ARRAY1D): Y-axis coordinates (required)coordsZ(ARRAY1D): Z-axis coordinates (required)filter: Filtering method (same as structuredRegular)dataCentering: Cell vs node centering (same as structuredRegular)
The axis coordinate arrays define the actual position of each voxel along that axis, enabling support for non-uniform grid spacing commonly found in scientific simulations.
The nanovdbRectilinear spatial field type extends NanoVDB support to
rectilinear grids. It supports all NanoVDB grid types (Fp4, Fp8, Fp16, FpN,
Float) with rectilinear coordinate transforms.
Parameters:
data(ARRAY1D): Serialized NanoVDB grid datacoordsX(ARRAY1D): X-axis coordinates (required)coordsY(ARRAY1D): Y-axis coordinates (required)coordsZ(ARRAY1D): Z-axis coordinates (required)filter: Filtering methoddataCentering: Cell vs node centering
This type automatically detects the grid type from the NanoVDB metadata and routes to the appropriate sampler implementation.
The mdl material type exposes NVIDIA's Material Definition Language
(MDL)
as an ANARI surface material. It enables physically based, fully programmable
shading defined in MDL modules, .mdle packages, or inline MDL source. This
extension is only available when VisRTX is built with
VISRTX_ENABLE_MDL_SUPPORT=ON (which requires the MDL SDK).
Parameters:
sourceType(ANARI_STRING, default"module"): Howsourceis interpreted. One of:"module": a fully-qualified MDL material name, or a.mdlepath"mdle": a path to a.mdlefile"code": inline MDL module source
source(ANARI_STRING, default"::visrtx::default::diffuseWhite"): The MDL content, interpreted persourceType.materialName(ANARI_STRING, optional): Selects the material withinsource. Formodule, when set,sourceis treated as a pure module name (no::materialsplit); formdleit must bemain; forcodeit defaults tomain.
MDL material inputs:
sourceType, source, and materialName only select the material. Every
other parameter set on the object is matched by name against the inputs of the
selected MDL material and used to override its argument block. Parameters whose
name does not correspond to a material input are ignored (with a warning), and
inputs left unset keep their MDL-declared defaults.
The ANARI parameter type must match the MDL input type, following the natural
mapping (e.g. ANARI_BOOL → bool, ANARI_FLOAT32 → float,
ANARI_FLOAT32_VEC3 → float3/color, ANARI_INT32_VEC2 → int2, etc.).
MDL texture inputs accept two forms:
ANARI_STRING: a path to an image file, loaded on demand. An optional companion parameter"<inputName>.colorspace"(ANARI_STRING, one of"srgb"(default) or"raw") controls how the texels are interpreted.ANARI_SAMPLER: an existing ANARI sampler object, bound directly to the MDL texture input.
With native MDL enabled, mdl materials accept dynamic metadata parameters:
sceneData.<name>(ANARI_STRING): bind an MDLscene::data_lookup_*name toattribute0,attribute1,attribute2,attribute3, orcolor.
Uniform eligibility is inferred from the effective attribute source. Geometry and instance constants, including the element selected from an instance array, are uniform within the rendered instance. Overriding vertex, face-varying or primitive data makes a uniform lookup invalid. Array contents are not scanned to infer constancy. No additional uniform metadata parameter is required.
Float, float2/3/4 and color lookups use the existing ANARI attribute interpolation
and padding rules. Values are prepared once per shading hit and shared with MDL
texture coordinates; scene-data lookups retain all four components and color.
Geometry constants use ANARI_FLOAT32_VEC4; arrays can use supported
scalar/vector attribute types. No geometry array is copied for these
bindings. Names are case-sensitive, material-local and may be chosen by the MDL
author. For example, sceneData.temperature = "attribute1" supplies
scene::data_lookup_float("temperature", default_value).
Missing names, absent attributes, invalid slots and nonfinite values return the
shader's default. scene::data_isvalid tests only binding and cached attribute
presence; it does not read cached values and ignores their numeric validity.
Integer and matrix lookups continue to return their defaults.
These dynamic metadata names are reserved and are not matched to shader inputs;
they are not enumerated as literal parameter names by the query API. Binding and
argument edits retain the material and compiled code; changing the source builds
a table for that source's string IDs.
With native MDL enabled, frame mdl.animationTime (ANARI_FLOAT32, default
0) supplies seconds to state::animation_time(). Time is local to each frame.
Changing it resets that frame's accumulation, including when the application uses
manual accumulationVersion; no material recompilation or geometry upload is
needed. Nonfinite times produce a warning and use zero. Negative finite times
are allowed for callers that need a signed timeline.
The following section describes what additional parameters and properties can be used on various ANARI objects.
The device itself can take a single INT32 parameter "cudaDevice" to select
which CUDA GPU should be used for rendering. Once this value has been set and
the implementation has initialized CUDA for itself, then changing this to
another value will be ignored (a warning will tell you this if it happens). The
device will initialize CUDA for itself if any object gets created from the
device.
The following properties are available to query on ANARIFrame:
| Name | Type | Description |
|---|---|---|
| numSamples | INT32 | get the number of pixel samples currently accumulated |
| nextFrameReset | BOOL | query whether the next frame will reset accumulation |
The numSamples property is the lower bound of pixel samples taken when the
checkerboard renderer parameter (see below) is enabled because not every pixel
will have the same number of samples accumulated.
The nextFrameReset property can give the application feedback for when
accumulation is about to reset in the next frame. When the property is queried
and the current frame is complete, all committed objects since the last
rendering operation will be internally updated (may be expensive).
The following extensions are either partially or fully implemented by VisRTX:
KHR_ARRAY1D_REGIONKHR_CAMERA_DEPTH_OF_FIELDKHR_CAMERA_ORTHOGRAPHICKHR_CAMERA_PERSPECTIVEKHR_DEVICE_SYNCHRONIZATIONKHR_FRAME_ACCUMULATIONKHR_FRAME_CHANNEL_ALBEDOKHR_FRAME_CHANNEL_INSTANCE_IDKHR_FRAME_CHANNEL_NORMALKHR_FRAME_CHANNEL_OBJECT_IDKHR_FRAME_CHANNEL_PRIMITIVE_IDKHR_FRAME_COMPLETION_CALLBACKKHR_GEOMETRY_CONEKHR_GEOMETRY_CURVEKHR_GEOMETRY_CYLINDERKHR_GEOMETRY_ISOSURFACEKHR_GEOMETRY_QUADKHR_GEOMETRY_SPHEREKHR_GEOMETRY_TRIANGLEKHR_INSTANCE_TRANSFORMKHR_INSTANCE_TRANSFORM_ARRAYKHR_LIGHT_DIRECTIONALKHR_LIGHT_HDRIKHR_LIGHT_POINTKHR_LIGHT_QUADKHR_LIGHT_RINGKHR_LIGHT_SPOTKHR_MATERIAL_MATTEKHR_MATERIAL_PHYSICALLY_BASEDKHR_RENDERER_AMBIENT_LIGHTKHR_RENDERER_BACKGROUND_COLORKHR_RENDERER_BACKGROUND_IMAGEKHR_RENDERER_DENOISEKHR_SAMPLER_IMAGE1DKHR_SAMPLER_IMAGE2DKHR_SAMPLER_IMAGE3DKHR_SAMPLER_IMAGExD_CLAMP_TO_BORDERKHR_SAMPLER_PRIMITIVEKHR_SAMPLER_TRANSFORMKHR_SPATIAL_FIELD_NANOVDBKHR_SPATIAL_FIELD_STRUCTURED_REGULARKHR_VOLUME_TRANSFER_FUNCTION1DEXT_SAMPLER_COMPRESSED_IMAGE2DEXT_SAMPLER_COMPRESSED_FORMAT_BC123EXT_SAMPLER_COMPRESSED_FORMAT_BC45EXT_SAMPLER_COMPRESSED_FORMAT_BC67NV_ARRAY_CUDANV_FRAME_BUFFERS_CUDAVISRTX_CAMERA_RAY_BUFFERVISRTX_GEOMETRY_NEURAL(requiresVISRTX_ENABLE_NEURAL)VISRTX_GEOMETRY_SDFVISRTX_MATERIAL_MATERIALX(requiresVISRTX_ENABLE_MATERIALX_SUPPORT)VISRTX_MATERIAL_MDL(requiresVISRTX_ENABLE_MDL_SUPPORT)VISRTX_MDL_SCENE_DATA(requiresVISRTX_ENABLE_MDL_SUPPORT)VISRTX_MDL_ANIMATION_TIME(requiresVISRTX_ENABLE_MDL_SUPPORT)VISRTX_RENDERER_DEBUGVISRTX_RENDERER_DEFAULTVISRTX_RENDERER_FASTVISRTX_RENDERER_INTERACTIVEVISRTX_RENDERER_QUALITYVISRTX_SPATIAL_FIELD_DATA_CENTERINGVISRTX_SPATIAL_FIELD_NANOVDB_RECTILINEARVISRTX_SPATIAL_FIELD_REGION_OF_INTERESTVISRTX_SPATIAL_FIELD_STRUCTURED_RECTILINEARVISRTX_TRIANGLE_BACK_FACE_CULLING
For any found bugs in extensions that are implemented, please open an issue!
The ANARI_VISRTX_LIGHT_QUAD_FOCUS extension adds quad focus (nonnegative exponent, default 0) and focusTint (linear RGB, default black). Radiance is multiplied by mix(focusTint, white, abs(axis dot emissionDirection)^focus) and the cone cutoff/softness. White tint disables focus. Sampling density stays unchanged, with shared NEE/proxy radiance; no emission power renormalization is applied. TestQuadLightFocus covers retained edits, tint/default restoration, illumination and visible proxies in interactive and quality modes.
ANARI_VISRTX_LIGHT_QUAD_TEXTURE adds an optional colorMap ARRAY2D of
FLOAT32_VEC3 to quad lights. Finite nonnegative linear RGB values multiply
color * intensity; their average is not normalized. Array dimensions map
along edge1 and edge2 in [0,1]. Bilinear filtering clamps at edges.
Unsetting the map restores untextured emission. Direct and visible/reflected
emission use the same map, retaining sidedness and primary visibility.
When cone/focus extensions are available, their modulation is retained.
Uniform area sampling is retained; small bright features may need more samples.
Image edits refresh resident texels and power-based light selection. Invalid
formats or values warn and use untextured emission. This spatial image is
distinct from angular photometric intensity distributions.