Quickstart
Build a RayD scene, intersect a batch of rays, differentiate hit distances, and query the nearest edge in under five minutes.
This quickstart builds a two-triangle square, traces three rays against it, differentiates the hit distances with respect to the vertex positions, and runs one nearest-edge query. The same program is shown for both backends; pick the one you installed in Installation.
Run it#
Save the code as quickstart.py and run python quickstart.py.
import drjit as dr
import rayd.drjit as rd
# 1. A unit square in the z = 0 plane, made of two triangles.
vertices = dr.cuda.ad.Array3f([0.0, 1.0, 1.0, 0.0], [0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0])
faces = dr.cuda.Array3i([0, 0], [1, 2], [2, 3])
dr.enable_grad(vertices)
mesh = rd.Mesh(dr.detach(vertices), faces)
mesh.vertex_positions = vertices # attach the AD-tracked positions
# 2. Build the scene once before any query.
scene = rd.Scene()
scene.add_mesh(mesh)
scene.build()
# 3. Three rays shot down the -z axis; the last one misses.
ray = rd.RayAD(
dr.cuda.ad.Array3f([0.25, 0.75, 2.0], [0.50, 0.50, 2.0], [1.0, 1.0, 1.0]),
dr.cuda.ad.Array3f([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [-1.0, -1.0, -1.0]),
)
hit = scene.intersect(ray)
print("valid:", hit.is_valid())
print("t:", hit.t)
print("prim_id:", hit.prim_id)
# 4. Differentiate the summed hit distance of the valid rays.
dr.backward(dr.sum(dr.select(hit.is_valid(), hit.t, 0.0)))
print("dt/dz per vertex:", dr.grad(vertices).z)
# 5. Nearest edge to a point just above the diagonal.
edge = scene.nearest_edge(dr.cuda.Array3f([0.5], [0.5], [0.1]))
print("edge distance:", edge.distance, "global edge:", edge.global_edge_id, "boundary:", edge.is_boundary)Expected output#
Both backends print the same values (Dr.Jit formatting shown):
valid: [True, True, False]
t: [1, 1, inf]
prim_id: [1, 0, -1]
dt/dz per vertex: [-0.75, -0.25, -0.75, -0.25]
edge distance: [0.1] global edge: [1] boundary: [False]What happened#
Meshstores vertex positions and triangle indices. Dr.Jit takes structure-of-arrays inputs (Array3f(xs, ys, zs)); PyTorch takes(N, 3)CUDA tensors withfloat32positions andint32faces.Scene.build()uploads the geometry and builds the OptiX acceleration structure and the edge BVH. You must call it before the first query.scene.intersect(ray)returns one closest hit per ray. A miss hast = inf,prim_id = -1, andis_valid()false.tis measured in units of the ray direction, so the hit point iso + t * d.- The gradient is the derivative of
twith respect to each vertex z coordinate. Raising the square shortens the downward rays, so the values are negative, and each vertex receives its barycentric share of the two hits. RayD keeps the hit triangle fixed and differentiates the continuous quantities; see Differentiation. nearest_edgefinds the closest mesh edge to a point. Edge 1 is the shared diagonal, so it is not a boundary edge.
In Dr.Jit you select the differentiable code path by passing RayAD and AD arrays. In PyTorch you set requires_grad=True on the tensors you want gradients for.