Quick Start

Build your first scene and trace rays with RayD

Overview#

Every RayD workflow follows the same pattern:

  1. Create a Mesh with vertices and faces
  2. Add it to a Scene and call scene.build()
  3. Create Ray objects and call scene.intersect()

Your First Ray-Mesh Intersection#

import rayd as rd
import drjit as dr
 
rd.set_device(0)
 
# Create a mesh with two triangles forming a quad
mesh = rd.Mesh(
    dr.cuda.Array3f(
        [-1.0, 1.0, 1.0, -1.0],
        [-1.0, -1.0, 1.0, 1.0],
        [3.0, 3.0, 3.0, 3.0],
    ),
    dr.cuda.Array3i([0, 0], [1, 2], [2, 3]),
)
 
scene = rd.Scene()
scene.add_mesh(mesh)
scene.build()
 
# Trace four rays
rays = rd.Ray(
    dr.cuda.Array3f(
        [0.0, 0.75, 1.5, -0.5],
        [0.0, 0.75, 0.0, -0.5],
        [-1.0, -1.0, -1.0, -1.0],
    ),
    dr.cuda.Array3f(
        [0.0, 0.0, 0.0, 0.0],
        [0.0, 0.0, 0.0, 0.0],
        [1.0, 1.0, 1.0, 1.0],
    ),
)
 
its = scene.intersect(rays)
 
for i, valid in enumerate(list(its.is_valid())):
    if valid:
        print(f"ray[{i}] hit: t={float(its.t[i]):.4f}, prim_id={int(its.prim_id[i])}")
    else:
        print(f"ray[{i}] miss")

What Just Happened#

  • rd.Mesh takes vertex positions as Array3f and face indices as Array3i
  • rd.Scene is the container — add meshes and call build() to construct the OptiX BVH
  • rd.Ray takes origin and direction as Array3f — both can be batches of rays
  • scene.intersect() returns an Intersection with hit distance t, hit point p, normal n, and primitive IDs

Differentiable Intersection#

To backpropagate through the intersection, use AD arrays:

import drjit as dr
import rayd as rd
 
rd.set_device(0)
 
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 = 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]),
)
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])

Note

When using AD arrays, scene.intersect() automatically returns an IntersectionAD with Dr.Jit gradients attached to the geometric outputs.

Next Steps#