Skip to content

Commit 1268d24

Browse files
committed
remove display
1 parent efa7f67 commit 1268d24

2 files changed

Lines changed: 48 additions & 41 deletions

File tree

docs/src/gpu_raytracing_tutorial.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,7 @@ Let's use the exact same scene as the CPU tutorial - the Makie cat with room geo
3838
# Load and prepare the cat model
3939
include("raytracing-core.jl")
4040
bvh, ctx = example_scene()
41-
# We have a Makie extension for plotting the scene graph
42-
f, ax, pl = plot(bvh; axis=(; show_axis=false))
43-
f
44-
```
45-
```julia (editor=true, logging=false, output=true)
46-
cam = cameracontrols(ax.scene)
47-
cam.eyeposition[] = [0, 1.0, -4]
48-
cam.lookat[] = [0, 0, 2]
49-
cam.upvector[] = [0.0, 1, 0.0]
50-
cam.fov[] = 45.0
41+
md"**Scene loaded: $(length(bvh.primitives)) triangles, $(length(ctx.materials)) materials**"
5142
```
5243
## Part 2: GPU Kernel Version 1 - Basic Naive Approach
5344

@@ -277,3 +268,4 @@ DOM.img(src=Asset(data"gpu-benchmarks.png"), width="700px")
277268
* Add **adaptive sampling** (more samples only where needed)
278269
* Explore **shared memory** optimizations for BVH traversal
279270
* Implement **streaming multisampling** across frames
271+

docs/src/raytracing_tutorial_content.md

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,10 @@ left_wall = normal_mesh(Rect3f(Vec3f(-5, -1.5, -2), Vec3f(0.01, 5, 10)))
4747
sphere1 = Tesselation(Sphere(Point3f(-2, -1.5 + 0.8, 2), 0.8f0), 64)
4848
sphere2 = Tesselation(Sphere(Point3f(2, -1.5 + 0.6, 1), 0.6f0), 64)
4949

50-
# Build our BVH acceleration structure with material indices
50+
# Build our BVH acceleration structure
5151
scene_geometry = [cat_mesh, floor, back_wall, left_wall, sphere1, sphere2]
52-
bvh = Raycore.BVH(scene_geometry, (mesh_idx, tri_idx) -> UInt32(mesh_idx))
53-
f, ax, pl = plot(bvh; axis=(; show_axis=false))
54-
```
55-
Set the camera to something better:
56-
57-
```julia (editor=true, logging=false, output=true)
58-
cam = cameracontrols(ax.scene)
59-
cam.eyeposition[] = [0, 1.0, -4]
60-
cam.lookat[] = [0, 0, 2]
61-
cam.upvector[] = [0.0, 1, 0.0]
62-
cam.fov[] = 45.0
63-
update_cam!(ax.scene, cam)
64-
nothing
52+
bvh = Raycore.BVH(scene_geometry)
53+
md"**BVH built with $(length(bvh.primitives)) triangles**"
6554
```
6655
## Part 2: Helper Functions - Building Blocks
6756

@@ -212,7 +201,11 @@ trace((args...)-> shadow_kernel(args...; shadow_samples=8), bvh, samples=8)
212201

213202
## Part 7: Materials and Multiple Lights
214203

215-
Time to add color and multiple lights:
204+
Time to add color and multiple lights! To associate materials with geometry, we need to rebuild the BVH with **metadata** that links each triangle to its material.
205+
206+
### Triangle Metadata
207+
208+
When building a BVH, you can pass a `metadata_fn(mesh_idx, tri_idx)` that assigns custom data to each triangle. This metadata is stored in `triangle.metadata` and returned with every ray hit. For materials, we use the mesh index as metadata:
216209

217210
```julia (editor=true, logging=false, output=true)
218211
struct PointLight
@@ -233,25 +226,34 @@ struct RenderContext
233226
ambient::Float32
234227
end
235228

236-
# Create lights and materials
229+
# Define materials for each mesh (order matches scene_geometry)
230+
materials = [
231+
Material(RGB(0.8f0, 0.6f0, 0.4f0), 0.0f0, 0.8f0), # 1: cat
232+
Material(RGB(0.3f0, 0.5f0, 0.3f0), 0.0f0, 0.9f0), # 2: floor
233+
Material(RGB(0.8f0, 0.6f0, 0.5f0), 0.8f0, 0.05f0), # 3: back wall
234+
Material(RGB(0.7f0, 0.7f0, 0.8f0), 0.0f0, 0.8f0), # 4: left wall
235+
Material(RGB(0.9f0, 0.9f0, 0.9f0), 0.8f0, 0.02f0), # 5: sphere1 - metallic
236+
Material(RGB(0.3f0, 0.6f0, 0.9f0), 0.5f0, 0.3f0), # 6: sphere2 - semi-metallic
237+
]
238+
239+
# Rebuild BVH with material indices as metadata
240+
# The metadata_fn receives (mesh_idx, tri_idx) and returns data stored per-triangle
241+
bvh = Raycore.BVH(scene_geometry, (mesh_idx, tri_idx) -> UInt32(mesh_idx))
242+
243+
# Create lights
237244
lights = [
238245
PointLight(Point3f(3, 4, -2), 50.0f0, RGB(1.0f0, 0.9f0, 0.8f0)),
239246
PointLight(Point3f(-3, 2, 0), 20.0f0, RGB(0.7f0, 0.8f0, 1.0f0)),
240247
PointLight(Point3f(0, 5, 5), 15.0f0, RGB(1.0f0, 1.0f0, 1.0f0))
241248
]
242249

243-
materials = [
244-
Material(RGB(0.8f0, 0.6f0, 0.4f0), 0.0f0, 0.8f0), # cat
245-
Material(RGB(0.3f0, 0.5f0, 0.3f0), 0.0f0, 0.9f0), # floor
246-
Material(RGB(0.8f0, 0.6f0, 0.5f0), 0.8f0, 0.05f0), # back wall
247-
Material(RGB(0.7f0, 0.7f0, 0.8f0), 0.0f0, 0.8f0), # left wall
248-
Material(RGB(0.9f0, 0.9f0, 0.9f0), 0.8f0, 0.02f0), # sphere1 - metallic
249-
Material(RGB(0.3f0, 0.6f0, 0.9f0), 0.5f0, 0.3f0), # sphere2 - semi-metallic
250-
]
251-
252250
ctx = RenderContext(lights, materials, 0.1f0)
253251
nothing
254252
```
253+
Now when a ray hits a triangle, we can look up its material using `triangle.metadata`:
254+
```julia
255+
mat = ctx.materials[triangle.metadata] # Get material for hit triangle
256+
```
255257
```julia (editor=true, logging=false, output=true)
256258
# Compute lighting from all lights - reusing our compute_light function!
257259
function compute_multi_light(bvh, ctx, point, normal, mat; shadow_samples=1)
@@ -269,6 +271,7 @@ end
269271
function material_kernel(bvh, ctx, tri, dist, bary, ray)
270272
hit_point = ray.o + ray.d * dist
271273
normal = compute_normal(tri, bary)
274+
# Look up material using triangle's metadata (mesh index we stored during BVH construction)
272275
mat = ctx.materials[tri.metadata]
273276

274277
color = compute_multi_light(bvh, ctx, hit_point, normal, mat, shadow_samples=2)
@@ -387,16 +390,28 @@ We built a complete ray tracer with:
387390

388391
**Key Raycore Functions:**
389392

390-
* `Raycore.BVH(meshes)` - Build acceleration structure
393+
* `Raycore.BVH(meshes)` - Build acceleration structure (default metadata = primitive index)
394+
* `Raycore.BVH(meshes, metadata_fn)` - Build with custom per-triangle metadata
391395
* `Raycore.Ray(o=origin, d=direction)` - Create ray
392-
* `Raycore.closest_hit(bvh, ray)` - Find nearest intersection
393-
* `Raycore.any_hit(bvh, ray)` - Test for any intersection
396+
* `Raycore.closest_hit(bvh, ray)` - Find nearest intersection, returns `(hit, triangle, distance, bary_coords)`
397+
* `Raycore.any_hit(bvh, ray)` - Test for any intersection (fast shadow test)
394398
* `Raycore.reflect(wo, normal)` - Compute reflection direction
399+
* `triangle.metadata` - Access custom data stored per-triangle
400+
401+
**Key Patterns:**
395402

396-
**Key Pattern:** The `compute_light` function is reusable across the entire tutorial:
403+
1. **Material Scene Pattern** - Associate materials with geometry using metadata:
404+
```julia
405+
# Build BVH with mesh index as metadata
406+
bvh = Raycore.BVH(meshes, (mesh_idx, tri_idx) -> UInt32(mesh_idx))
407+
408+
# In your shader, look up material from hit triangle
409+
mat = materials[triangle.metadata]
410+
```
397411

412+
2. **Reusable Lighting** - The `compute_light` function handles both hard and soft shadows:
398413
* `shadow_samples=1` → hard shadows
399-
* `shadow_samples=4` → soft shadows
414+
* `shadow_samples>1` → soft shadows
400415

401-
This shows how a well-designed function can handle multiple use cases cleanly!
416+
This shows how well-designed functions can handle multiple use cases cleanly!
402417

0 commit comments

Comments
 (0)