Skip to main content

RayD: minimalist differentiable ray tracing package wrapping Dr.Jit and OptiX.

Project description

RayD

PyPI Downloads Code Size Total Lines License

RayD is a minimalist differentiable ray tracing package wrapping OptiX ray tracing with Dr.Jit autodiff.

pip install rayd

RayD is not a full renderer. It is a thin wrapper around Dr.Jit and OptiX for building your own renderers and simulators.

The goal is simple: expose differentiable ray-mesh intersection on the GPU without bringing in a full graphics framework.

RayD provides three frontends:

  • Dr.Jit (Native) — direct Dr.Jit array API, maximum control
  • PyTorchrayd.torch module, CUDA torch.Tensor in/out, integrates with torch.autograd
  • Slang — C++ POD/handle bridge for Slang cpp target interop

Why RayD?

RayD is for users who want OptiX acceleration and autodiff, but do not want a full renderer.

Why not Mitsuba? Mitsuba is excellent for graphics rendering, but often too high-level for RF, acoustics, sonar, or custom wave simulation. In those settings, direct access to ray-scene queries and geometry gradients is usually more useful than a full material-light-integrator stack.

RayD keeps only the geometric core:

  • differentiable ray-mesh intersection
  • scene-level GPU acceleration through OptiX
  • edge acceleration structures for nearest-edge queries
  • primary-edge sampling support for edge-based gradient terms

For intersection workloads, RayD targets Mitsuba-level performance and matching results with a much smaller API surface.

What RayD Provides

  • Mesh: triangle geometry, transforms, UVs, and edge topology
  • Scene: a container of meshes plus OptiX acceleration
  • scene.intersect(ray): differentiable ray-mesh intersection
  • scene.shadow_test(ray): occlusion testing
  • scene.nearest_edge(query): nearest-edge queries for points and rays
  • edge acceleration data that is useful for edge sampling and edge diffraction methods

Performance

The chart below was generated on March 25, 2026 on an NVIDIA GeForce RTX 5080 and AMD Ryzen 7 9800X3D, comparing RayD (0.1.2) against Mitsuba 3.8.0 with the cuda_ad_rgb variant.

Raw benchmark data is stored in docs/performance_benchmark.json.

  • RayD is consistently faster on static forward and static gradient workloads across all three scene sizes.
  • Dynamic reduced forward reaches parity or better from the medium scene onward, and dynamic full is effectively tied on the largest case.
  • On the largest 192x192 mesh / 384x384 ray benchmark, RayD vs Mitsuba average latency in milliseconds is: static full 0.162 vs 0.190, static reduced 0.124 vs 0.224, dynamic full 0.741 vs 0.740, dynamic reduced 0.689 vs 0.714, gradient static 0.411 vs 0.757, gradient dynamic 1.324 vs 1.413.
  • Correctness stayed aligned throughout the sweep: forward mismatch counts remained 0, and the largest static gradient discrepancy was 9.54e-7.

RayD vs Mitsuba performance benchmark

Quick Examples

If you only want to see the package in action, start here:

Differentiable Cornell Box with Edge Sampling

GPU path tracing + interior AD + edge sampling (Li et al.) in ~180 lines (examples/renderer/cornell_box.py):

Differentiable Cornell box render and edge-AD gradient

Build meshes, put them in a scene, launch rays, define a loss, and backpropagate through geometry.

Minimal Differentiable Ray Tracing Example

The example below traces a single ray against one triangle and backpropagates the hit distance to the vertex positions.

import rayd as rd
import drjit as dr


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]),
)

verts = 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(verts)

mesh.vertex_positions = verts

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

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

its = scene.intersect(ray)
loss = dr.sum(its.t)
dr.backward(loss)

print("t =", its.t)
print("grad z =", dr.grad(verts)[2])

This is the core RayD workflow. Replace the single ray with your own batched rays, RF paths, acoustic paths, or edge-based objectives.

PyTorch Frontend

rayd.torch is an optional Python-level wrapper that mirrors the native API using CUDA torch.Tensor inputs and outputs. AD mode is inferred automatically from requires_grad.

import rayd.torch as rt

verts = torch.tensor([...], device="cuda", requires_grad=True)
mesh = rt.Mesh(verts, faces)
scene = rt.Scene()
scene.add_mesh(mesh)
scene.build()

its = scene.intersect(rt.Ray(origins, directions))
loss = (its.t - target).pow(2).mean()
loss.backward()  # gradients flow to verts

Key conventions:

  • vectors use shape (N, 3) or (N, 2); (3,) and (2,) are accepted as batch size 1
  • index tensors use shape (F, 3); images use shape (H, W); transforms use shape (4, 4)
  • CPU tensors are rejected; rayd.torch does not do implicit device transfers

The native Dr.Jit API remains unchanged and does not depend on PyTorch.

Slang Frontend

RayD ships a Slang interop layer for Slang's cpp target. Slang code can import rayd_slang; and call RayD scene queries directly.

Minimal Slang Example

import rayd_slang;

export float traceRayT(uint64_t sceneHandle,
                       float ox, float oy, float oz,
                       float dx, float dy, float dz)
{
    SceneHandle scene = makeSceneHandle(sceneHandle);
    Ray ray = makeRay(float3(ox, oy, oz), float3(dx, dy, dz));
    Intersection hit = sceneIntersect(scene, ray);
    return itsT(hit);  // use accessor, not hit.t
}

Load and call from Python:

import rayd as rd
import rayd.slang as rs

m = rs.load_module("my_shader.slang")  # use rayd.slang.load_module, not slangtorch.loadModule

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

t = m.traceRayT(scene.slang_handle, 0.25, 0.25, -1.0, 0.0, 0.0, 1.0)

Differentiable Slang Example

sceneIntersectAD returns an IntersectionAD with analytic gradients dt_do (∂t/∂origin) and dt_dd (∂t/∂direction):

import rayd_slang;

export IntersectionAD traceAD(uint64_t sceneHandle,
                              float ox, float oy, float oz,
                              float dx, float dy, float dz)
{
    SceneHandle scene = makeSceneHandle(sceneHandle);
    Ray ray = makeRay(float3(ox, oy, oz), float3(dx, dy, dz));
    return sceneIntersectAD(scene, ray);
}

Use it from Python with torch.autograd:

import torch
import rayd as rd
import rayd.slang as rs

m = rs.load_module("my_shader.slang")
scene = rd.Scene()
scene.add_mesh(mesh)
scene.build()

class DiffTrace(torch.autograd.Function):
    @staticmethod
    def forward(ctx, oz):
        ctx.save_for_backward(oz)
        hit = m.traceAD(scene.slang_handle, 0.25, 0.25, oz.item(), 0, 0, 1)
        return torch.tensor(hit.t, device=oz.device)

    @staticmethod
    def backward(ctx, g):
        oz, = ctx.saved_tensors
        hit = m.traceAD(scene.slang_handle, 0.25, 0.25, oz.item(), 0, 0, 1)
        return torch.tensor(hit.dt_do.z * g.item(), device=oz.device)

oz = torch.tensor(-1.0, device="cuda", requires_grad=True)
t = DiffTrace.apply(oz)
t.backward()
print(f"t={t.item()}, dt/doz={oz.grad.item()}")  # t=1.0, dt/doz=-1.0

load_module() runs slangc -target cpp, auto-generates pybind11 bindings, and links against rayd_core. See docs/slang_interop.md for the full compilation pipeline, API reference, and known workarounds.

Edge Acceleration Structure

RayD also provides a scene-level edge acceleration structure.

This is useful for:

  • edge sampling
  • nearest-edge queries
  • visibility-boundary terms
  • geometric edge diffraction models

In other words, RayD is not limited to triangle hits. It also gives you direct access to edge-level geometry queries, which are important in many non-graphics simulators.

Compiling Locally

RayD is a Python package with a C++/CUDA extension.

You need Python >=3.10, CUDA Toolkit >=11.0, CMake, a C++17 compiler, drjit>=1.2.0, nanobind==2.11.0, and scikit-build-core.

On Windows, use Visual Studio 2022 with Desktop C++ tools. On Linux, use GCC or Clang with C++17 support.

Recommended environment

conda create -n myenv python=3.10 -y
conda activate myenv
python -m pip install -U pip setuptools wheel
python -m pip install cmake scikit-build-core nanobind==2.11.0
python -m pip install "drjit>=1.2.0"

Install

conda activate myenv
python -m pip install .

Dependencies

RayD depends on:

  • Python 3.10+
  • Dr.Jit 1.2.0+
  • OptiX 8+

RayD does not include:

  • BSDFs
  • emitters
  • integrators
  • scene loaders
  • image I/O
  • path tracing infrastructure

That is by design.

Repository Layout

Testing

python -m unittest tests.drjit.test_geometry -v

Optional PyTorch wrapper tests:

python -m unittest tests.torch.test_geometry -v

Optional Slang interop and gradient tests (requires slangtorch):

python -m unittest tests.slang.test_slang -v

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

BSD 3-Clause. See LICENSE.

Project details


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.1.3.tar.gz (1.1 MB view details)

Uploaded Source

Built Distributions

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

rayd-0.1.3-cp313-cp313-win_amd64.whl (2.5 MB view details)

Uploaded CPython 3.13Windows x86-64

rayd-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

rayd-0.1.3-cp312-cp312-win_amd64.whl (2.5 MB view details)

Uploaded CPython 3.12Windows x86-64

rayd-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

rayd-0.1.3-cp311-cp311-win_amd64.whl (2.5 MB view details)

Uploaded CPython 3.11Windows x86-64

rayd-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

rayd-0.1.3-cp310-cp310-win_amd64.whl (2.5 MB view details)

Uploaded CPython 3.10Windows x86-64

rayd-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (1.8 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

File details

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

File metadata

  • Download URL: rayd-0.1.3.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rayd-0.1.3.tar.gz
Algorithm Hash digest
SHA256 4a67de0e1bdd6f5c5558103b493ba1e9baaa05ef1bf9279ce2210ea6b3e0a3e2
MD5 d33f8751e291120dc32545e9dfa18846
BLAKE2b-256 b37a2eec46228b964ad8a80642918c82c932711805434fbc5256c9c06890cecb

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3.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.1.3-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: rayd-0.1.3-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rayd-0.1.3-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 ea7a955fcd5d8ce5007c2cbb10ac39585d3aa67568a15c20f368c472f2b76c64
MD5 d6444142ef2296bdbb19435e6e16a70b
BLAKE2b-256 d7c2df52ff8ccd4a35ae35e7b491207a7f10d23d5684e7a51bf631e269b1eb92

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp313-cp313-win_amd64.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.

File details

Details for the file rayd-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rayd-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6ffbdf744ded6b5f739a9d1a57afa46ce96e09adb976ef4dcc1080bbee8c1cb2
MD5 7f3fdda134c922a71d12ff23ef33c30c
BLAKE2b-256 24147752a6a0679a49768a059ad47ddf33315b1e2a67d38d26ab016118105d73

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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.

File details

Details for the file rayd-0.1.3-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: rayd-0.1.3-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rayd-0.1.3-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 1576f7c63326af534dbf9d941ea511e92a6523ba896fafab1d2c0733d43892f1
MD5 5fc9cae63a22dd97f7662d358ce65aa5
BLAKE2b-256 42ab9f8b946672900fda16a47dc32d8a1c8834da8dc06374ce8b17493a7da3a5

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp312-cp312-win_amd64.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.

File details

Details for the file rayd-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rayd-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 9470df489dc0900eb0443e53b357229aaf64d1dc6e135577841473ed804b1a77
MD5 6d579f53cef12cde19923302fe6732c5
BLAKE2b-256 c18dc8652bd0701f6f615ef915f04e788ff5ce2f6e51ee710a64df032595c15a

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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.

File details

Details for the file rayd-0.1.3-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: rayd-0.1.3-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rayd-0.1.3-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 e03f9468318537f1271781ab8abc28455b7d0574d23faf9e3eac540631720238
MD5 35314fad6f0e12e87b74c2e4c336b531
BLAKE2b-256 137e7b345a00801e59fa3e2f587a61097b8741f7f23551a0bf5545b476b1b55c

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp311-cp311-win_amd64.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.

File details

Details for the file rayd-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rayd-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 4a65be724272ec5bf73f5584c04d0b9e2f091d29cb32e70258a4b568b12bad54
MD5 b2c4cccdaa50264b8f000aa914a3d897
BLAKE2b-256 96adf3c1ee15d62f4edf3f11f65d06194c73c7d0b53a1dd189fd232ee44ee75b

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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.

File details

Details for the file rayd-0.1.3-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: rayd-0.1.3-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rayd-0.1.3-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 f49b1d2408a7b4719334c1e24cdc533a40be31a1b30f96d310d3391f8e573fbb
MD5 bbfb4ab81f8d86d02c928fc8dc2b6d14
BLAKE2b-256 921306bf610db9caaea3dc6ed1ee55a4264e85d5df9e079bb284092f170854ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp310-cp310-win_amd64.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.

File details

Details for the file rayd-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for rayd-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ad8234d2112f9b72a89360b15a5c89d116f6f9fde477746bc690f52e3a4f3902
MD5 5449fb1ec789912007dba1ddb49b35ef
BLAKE2b-256 54d74218d67cba67b6f02d57c9a9a5ab78f543f4afd63e1f90af29f48c63926e

See more details on using hashes here.

Provenance

The following attestation bundles were made for rayd-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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 Pingdom Monitoring Sentry Error logging StatusPage Status page