Skip to main content

RayD

PyPI Downloads Code Size Total Lines License

RayD is a CUDA/OptiX library for differentiable ray geometry, edge queries, visibility, and RF-style multipath primitives. Version 0.6 provides two independent, backend-native Python APIs:

import rayd.drjit as rd
import rayd.torch as rt

RayD is not a full renderer. It exposes low-level geometry and wave-propagation primitives for custom renderers, RF simulators, acoustics, sensing, visibility analysis, and inverse-design systems without imposing a material-light- integrator framework.

Installation

Install both backends through the meta-distribution:

pip install rayd

Install only the backend you use when the other runtime is not needed:

pip install rayd-drjit
pip install rayd-torch

All three distributions share version 0.6.0. The rayd meta-distribution pins rayd-drjit and rayd-torch to exactly the same version.

Release artifacts cover CPython 3.10 through 3.14 on Windows x86-64 and manylinux_2_28_x86_64. The native backend wheels are CPython-specific while the Torch backend still contains the transitional _C extension. The _stable_ops library inside rayd-torch is untagged and uses the LibTorch 2.10 Stable ABI boundary. The rayd meta-distribution is a universal pure-Python wheel and is the only distribution that also publishes an sdist.

[!IMPORTANT] RayD 0.6 uses explicit backend namespaces. The parent rayd namespace does not select or re-export a default backend. Replace legacy import rayd as rd with import rayd.drjit as rd or import rayd.torch as rt.

For downstream migration details, see docs/downstream-migration.md.

Scope

RayD focuses on geometry and wave-propagation primitives:

  • differentiable ray-mesh intersection
  • scene-level GPU acceleration through OptiX
  • nearest-edge point and ray queries
  • primary-edge and secondary-edge sampling support
  • segment visibility and reflection-path tracing
  • equivalent-path correction (EPC) primitives
  • reflection and diffraction field accumulation
  • Dr.Jit and PyTorch reverse/forward automatic differentiation
  • source-level integration for native downstream CMake projects

RayD intentionally does not provide:

  • BSDFs or emitters
  • rendering integrators
  • scene loaders
  • bitmap or image I/O
  • a material-light-integrator framework
  • implicit conversions between Dr.Jit and Torch objects

Why RayD?

Mitsuba is an excellent physically based renderer, but it can be too high-level when the main workload is RF propagation, acoustics, sonar, visibility analysis, or a custom wave simulator. Those applications often need direct control over ray-scene queries, edges, reflection chains, diffraction state, and geometry gradients instead of a complete rendering runtime.

RayD keeps that API surface focused: meshes, scenes, rays, intersections, edges, visibility, and multipath query results.

Backend Capabilities

Capability Dr.Jit Torch
Ray-mesh intersection Yes Yes
Point/ray nearest edge Yes Yes
Top-k nearest edges Yes No
Segment visibility Yes Yes
Pair/chain/edge visibility helpers Yes Partial
Reflection tracing and accumulation Yes Yes
EPC path and field queries Yes Yes
Direct and chained diffraction Yes Yes
Surfel primitives Yes No
Reverse-mode AD Yes Yes
Forward-mode AD Yes Yes
torch.compile integration No Yes

Use backend_capabilities() on either backend for the machine-readable capability manifest. Unsupported functionality does not silently cross into the other runtime.

Each backend owns its scene objects, GPU allocations, current stream, OptiX pipelines, acceleration structures, and AD graph. A rayd.drjit.Scene cannot be passed to rayd.torch, and a rayd.torch.Scene cannot be passed to rayd.drjit.

Core API

The two backends use the same high-level vocabulary where their capabilities overlap:

  • Mesh: triangle geometry, transforms, UVs, and edge topology
  • Scene: mesh container plus OptiX acceleration structures
  • Ray / RayAD: batched origins, directions, and optional tmax
  • scene.intersect(ray): closest differentiable ray-mesh hit
  • scene.nearest_edge(query): nearest-edge point or ray query
  • scene.trace_reflections(...): specular reflection chains
  • scene.accumulate_reflections(...): reflected field/power accumulation
  • scene.accum_dfr_direct(...) / scene.accum_dfr(...): diffraction accumulation
  • scene.trace_dfr_paths(...): compact diffraction path export

The Dr.Jit backend additionally exposes:

  • scene.shadow_test(ray)
  • scene.nearest_edges(point, k) for k <= 16
  • scene.visible(...), visible_pair(...), visible_chain(...), and visible_edge(...)
  • scene.set_edge_mask(mask) / scene.edge_mask()
  • surfel intersection, compositing, and rendering primitives

Differentiation Contract

RayD differentiates continuous geometry and field quantities while treating the discrete winner selected during the forward pass as fixed:

  • primitive, edge, visibility, and path selection are discrete
  • hit distance, position, normals, transforms, ray parameters, materials, and supported field inputs retain gradients
  • native reflection and diffraction operators provide explicit JVP/VJP paths
  • unsupported AD strategies fail explicitly instead of silently copying data through the other backend

For Dr.Jit, RayAD selects the differentiable intersection overload. Torch selects AD from tensors with requires_grad=True and supports both backward VJP and forward JVP for implemented operators.

Dr.Jit Quick Start

The following example traces one ray against a triangle and differentiates the hit distance with respect to the mesh vertices:

import drjit as dr
import rayd.drjit as rd


mesh = rd.Mesh(
    dr.cuda.Array3f(
        [0.0, 1.0, 0.0],
        [0.0, 0.0, 1.0],
        [0.0, 0.0, 0.0],
    ),
    dr.cuda.Array3i([0], [1], [2]),
)

vertices = dr.cuda.ad.Array3f(
    [0.0, 1.0, 0.0],
    [0.0, 0.0, 1.0],
    [0.0, 0.0, 0.0],
)
dr.enable_grad(vertices)
mesh.vertex_positions = vertices

scene = rd.Scene()
scene.add_mesh(mesh)
scene.build()

ray = rd.RayAD(
    dr.cuda.ad.Array3f([0.25], [0.25], [-1.0]),
    dr.cuda.ad.Array3f([0.0], [0.0], [1.0]),
)

hit = scene.intersect(ray)
dr.backward(dr.sum(hit.t))

print("t =", hit.t)
print("vertex z gradients =", dr.grad(vertices).z)

Torch Quick Start

The equivalent Torch example stays entirely in Torch tensors and autograd:

import torch
import rayd.torch as rt


vertices = torch.tensor(
    [[0.0, 0.0, 0.0],
     [1.0, 0.0, 0.0],
     [0.0, 1.0, 0.0]],
    device="cuda",
    dtype=torch.float32,
    requires_grad=True,
)
faces = torch.tensor(
    [[0, 1, 2]],
    device="cuda",
    dtype=torch.int32,
)

scene = rt.Scene()
scene.add_mesh(rt.Mesh(vertices, faces))
scene.build()

ray = rt.Ray(
    torch.tensor([[0.25, 0.25, -1.0]], device="cuda"),
    torch.tensor([[0.0, 0.0, 1.0]], device="cuda"),
)

hit = scene.intersect(ray)
hit.t.sum().backward()

print("t =", hit.t)
print("vertex z gradients =", vertices.grad[:, 2])

Torch vector inputs use contiguous CUDA float32 tensors with shape (N, 3); index tensors use CUDA int32, and masks use torch.bool. CUDA operations run on the current Torch stream.

Edge Queries

RayD provides scene-level GPU acceleration for point-to-edge and ray-to-edge queries. Typical uses include:

  • diffraction edge selection
  • closest-feature geometry terms
  • visibility-boundary estimators
  • differentiable geometric constraints

For finite ray queries, nearest-edge distance uses segment semantics on [0, tmax]. Dr.Jit's Scene.set_edge_mask(mask) filters the secondary-edge BVH in scene-global edge index space without changing the underlying edge topology or mesh offsets.

Multipath Queries

RayD includes low-level reflection, visibility, and diffraction primitives for custom wave simulators:

  • reflection chains with image sources and scene-global primitive IDs
  • batched segment visibility
  • equivalent-path correction geometry and complex reflected fields
  • reflection field/power accumulation onto receiver grids
  • direct, Keller-cone, suffix-reflection, and order-2/3 diffraction
  • coherent deterministic diffraction accumulation
  • compact path export for downstream channel/CIR processing

trace_* APIs return geometric or field records per ray/path. accum_* APIs reduce contributions into aggregate outputs such as receiver-grid cells. RayD does not choose the source model, receiver model, material policy, objective, or final channel representation for the caller.

Naming follows the public API standard in backends/drjit/API_NAMING_STANDARD.md: Dfr denotes diffraction, Refl denotes reflection, Epc denotes equivalent-path correction, and AD is reserved for automatic differentiation.

Examples

Dr.Jit examples are kept as runnable applications under backends/drjit/examples:

The Torch test and benchmark suite also serves as executable usage coverage:

Performance

The historical RayD-versus-Mitsuba benchmark was measured on an NVIDIA RTX 5080 and AMD Ryzen 7 9800X3D using a 192 x 192 mesh and 384 x 384 rays. RayD stayed aligned with Mitsuba while improving static forward and gradient latency. Representative average latencies in milliseconds were:

Workload RayD Mitsuba
Static full intersection 0.162 0.190
Static reduced intersection 0.124 0.224
Dynamic full intersection 0.741 0.740
Dynamic reduced intersection 0.689 0.714
Static gradient 0.411 0.757
Dynamic gradient 1.324 1.413

Forward mismatch counts were zero in that sweep, and the largest static gradient discrepancy was 9.54e-7. Current backend-to-backend benchmarks live under backends/torch/tests and should be rerun for the target GPU, CUDA toolkit, and workload before making deployment decisions.

Device and Stream Selection

The Dr.Jit backend follows Dr.Jit's current-thread CUDA device:

import rayd.drjit as rd

rd.set_device(0)

Existing scenes and OptiX resources should not be reused across device switches in the same process.

The Torch backend follows the device of its CUDA tensors and launches work on the current Torch CUDA stream. Keep every tensor participating in one query on the same device.

Building from Source

RayD requires Python 3.10-3.14, CMake 3.22+, a C++17 compiler, CUDA, and the OptiX SDK. On Windows, use Visual Studio 2022 with Desktop C++ tools.

Create an environment and install common build tools:

conda create -n rayd python=3.11 -y
conda activate rayd
python -m pip install -U pip setuptools wheel
python -m pip install cmake ninja scikit-build-core

Build the Dr.Jit backend:

python -m pip install "drjit==1.3.1" "nanobind==2.9.2"
python -m pip install --no-build-isolation -ve backends/drjit

Build the Torch backend:

python -m pip install torch==2.10.0 --index-url https://download.pytorch.org/whl/cu128
python -m pip install --no-build-isolation -ve backends/torch

Native downstream projects can add the Torch backend with CMake and link against rayd_torch_native_core. The source-level integration declarations are provided by backends/torch/include/rayd/torch/integration.h. This interface is intended for projects built in the same CMake/libtorch graph; it is not a stable binary ABI across unrelated libtorch builds.

Repository Layout

  • backends/drjit: Dr.Jit Python bindings, C++/CUDA/OptiX implementation, examples, and tests
  • backends/torch: Torch Python API, dispatcher/autograd bindings, C++/CUDA/OptiX implementation, and tests
  • shared/include: backend-neutral device contracts and UTD math
  • tests/packaging: distribution, namespace, and wheel-layout checks
  • docs: migration, validation, and OptiX pipeline notes
  • CHANGELOG.md: release history

Testing

Run packaging and namespace checks from the repository root:

python -m unittest tests.packaging.test_project_metadata -v
python -m unittest tests.test_namespace_isolation -v

Run representative Dr.Jit suites:

python -m unittest backends.drjit.tests.drjit.test_geometry -v
python -m unittest backends.drjit.tests.drjit.test_visibility_topk -v
python -m unittest backends.drjit.tests.drjit.test_reflection_epc -v
python -m unittest backends.drjit.tests.drjit.test_reflection_accumulation -v
python -m unittest backends.drjit.tests.drjit.test_diffraction_accumulation -v

Run representative Torch suites:

python -m unittest backends.torch.tests.torch_backend.test_intersect_forward -v
python -m unittest backends.torch.tests.torch_backend.test_intersect_grad -v
python -m unittest backends.torch.tests.torch_backend.test_edge_queries -v
python -m unittest backends.torch.tests.torch_backend.test_multipath -v

The default local development environment used by this repository is witwin3; downstream migration and release validation in the 0.6 cycle were also run in witwin2.

Credits

RayD is developed with reference to:

Citation

@inproceedings{chen2026rfdt,
  title     = {Physically Accurate Differentiable Inverse Rendering
               for Radio Frequency Digital Twin},
  author    = {Chen, Xingyu and Zhang, Xinyu and Zheng, Kai and
               Fang, Xinmin and Li, Tzu-Mao and Lu, Chris Xiaoxuan
               and Li, Zhengxiong},
  booktitle = {Proceedings of the 32nd Annual International Conference
               on Mobile Computing and Networking (MobiCom)},
  year      = {2026},
  doi       = {10.1145/3795866.3796686},
  publisher = {ACM},
  address   = {Austin, TX, USA},
}

License

RayD is released under the BSD 3-Clause License. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rayd-0.6.0.tar.gz (8.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rayd-0.6.0-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

Details for the file rayd-0.6.0.tar.gz.

File metadata

  • Download URL: rayd-0.6.0.tar.gz
  • Upload date:
  • Size: 8.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rayd-0.6.0.tar.gz
Algorithm Hash digest
SHA256 55b0e709f77d651eeb25e998cea1f3fad14b4e58da431a05aea2814130d83f0c
MD5 954cf9bdb923dfe9f90a06e3f6f9512a
BLAKE2b-256 af55597beb731f88fa2aed63567b57084d7fadf2f67fc09f37f3429a6a34d273

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.6.0.tar.gz:

Publisher: pypi.yml on Asixa/RayD

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rayd-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: rayd-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 8.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rayd-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c66237afb91413bb9327d75dc9298d5d6cf8959a7cabfb7a7dd3b22ff46de9f
MD5 297ed8cf9855f34d8608940c6563610a
BLAKE2b-256 c5f7b8c4087c3ff5299c557d682df657147b5e1b79bcf4f86a569d3486cbab17

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.6.0-py3-none-any.whl:

Publisher: pypi.yml on Asixa/RayD

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page