@@ -47,21 +47,10 @@ left_wall = normal_mesh(Rect3f(Vec3f(-5, -1.5, -2), Vec3f(0.01, 5, 10)))
4747sphere1 = Tesselation (Sphere (Point3f (- 2 , - 1.5 + 0.8 , 2 ), 0.8f0 ), 64 )
4848sphere2 = 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
5151scene_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)
218211struct PointLight
@@ -233,25 +226,34 @@ struct RenderContext
233226 ambient:: Float32
234227end
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
237244lights = [
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-
252250ctx = RenderContext (lights, materials, 0.1f0 )
253251nothing
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!
257259function compute_multi_light (bvh, ctx, point, normal, mat; shadow_samples= 1 )
269271function 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