@@ -5,6 +5,44 @@ using KernelAbstractions
55using KernelAbstractions: @kernel , @index , @Const
66import KernelAbstractions as KA
77using Statistics
8+
9+ # ============================================================================
10+ # MaterialScene Helper
11+ # ============================================================================
12+
13+ """
14+ MaterialScene(geometry_material_pairs) -> (bvh, materials)
15+
16+ Create a BVH and materials array from a vector of (geometry, material) tuples.
17+
18+ # Arguments
19+ - `geometry_material_pairs`: Vector of `(mesh, material)` tuples
20+
21+ # Returns
22+ - `bvh`: BVH with material indices as triangle metadata
23+ - `materials`: Vector of materials
24+
25+ # Example
26+ ```julia
27+ scene = [
28+ (sphere_mesh, Material(...)),
29+ (floor_mesh, Material(...)),
30+ ]
31+ bvh, materials = MaterialScene(scene)
32+ ```
33+ """
34+ function MaterialScene (geometry_material_pairs:: Vector{<:Tuple{<:Any, M}} ) where {M}
35+ meshes = [p[1 ] for p in geometry_material_pairs]
36+ materials = M[p[2 ] for p in geometry_material_pairs]
37+
38+ # Create BVH with material index as metadata
39+ function metadata_fn (mesh_idx, _tri_idx)
40+ return Int32 (mesh_idx)
41+ end
42+ bvh = Raycore. BVH (meshes, metadata_fn)
43+ return bvh, materials
44+ end
45+
846# ============================================================================
947# SoA Access Macros
1048# ============================================================================
@@ -123,11 +161,12 @@ struct ReflectionRayWork
123161 hit_idx:: Int32 # Index back to primary hit
124162end
125163
126- struct ReflectionHitWork{T}
164+ struct ReflectionHitWork
127165 hit_found:: Bool
128- tri_idx :: T # Store triangle index instead of full triangle
166+ material_idx :: Int32 # Store material index ( triangle metadata)
129167 dist:: Float32
130168 bary:: Vec3f
169+ normal:: Vec3f # Store interpolated normal
131170 ray:: Raycore.Ray
132171 primary_hit_idx:: Int32
133172end
308347 normal = Vec3f (normalize (v0 * u + v1 * v + v2 * w))
309348
310349 # Get material
311- mat = ctx. materials[tri. material_idx ]
350+ mat = ctx. materials[tri. metadata ]
312351 base_color = Vec3f (mat. base_color. r, mat. base_color. g, mat. base_color. b)
313352 # Start with ambient
314353 total_color = base_color * ctx. ambient
363402 dummy_ray = Raycore. Ray (o= Point3f (0 , 0 , 0 ), d= Vec3f (0 , 0 , 1 ), t_max= 0.0f0 )
364403
365404 if hit_found
366- mat = ctx. materials[tri. material_idx ]
405+ mat = ctx. materials[tri. metadata ]
367406 if mat. metallic > 0.0f0
368407 # Compute reflection
369408 hit_point = ray. o + ray. d * dist
@@ -413,10 +452,18 @@ end
413452
414453 if ray. t_max > 0.0f0
415454 hit_found, tri, dist, bary = Raycore. closest_hit (bvh, ray)
416- # Write to SoA using @set
417- @set reflection_hit_soa[idx] = (hit_found= hit_found, tri_idx= tri. primitive_idx,
418- dist= dist, bary= Vec3f (bary),
419- ray= ray, primary_hit_idx= hit_idx)
455+ if hit_found
456+ # Compute normal here so we don't need to store the triangle
457+ v0, v1, v2 = Raycore. normals (tri)
458+ u, v, w = bary[1 ], bary[2 ], bary[3 ]
459+ normal = Vec3f (normalize (v0 * u + v1 * v + v2 * w))
460+ # Write to SoA using @set
461+ @set reflection_hit_soa[idx] = (hit_found= true , material_idx= tri. metadata,
462+ dist= dist, bary= Vec3f (bary), normal= normal,
463+ ray= ray, primary_hit_idx= hit_idx)
464+ else
465+ reflection_hit_soa. hit_found[idx] = false
466+ end
420467 else
421468 # Write only hit_found as false for dummy rays
422469 reflection_hit_soa. hit_found[idx] = false
431478@kernel function shade_reflections_and_blend! (
432479 @Const (hit_queue),
433480 @Const (reflection_hit_soa), # SoA version: NamedTuple of arrays
434- @Const (bvh_triangles), # Need original triangles for material lookup
435481 @Const (ctx),
436482 @Const (sky_color),
437483 shading_queue # In/out: update with reflection contribution
@@ -444,21 +490,17 @@ end
444490 @get hit_found, tri, pixel_x, pixel_y, sample_idx = hit_queue[idx]
445491
446492 if hit_found
447- mat = ctx. materials[tri. material_idx ]
493+ mat = ctx. materials[tri. metadata ]
448494
449495 if mat. metallic > 0.0f0
450- # Access from SoA directly (using different variable names for clarity)
451- @get hit_found, tri_idx , dist, bary, ray = reflection_hit_soa[idx]
496+ # Access from SoA directly
497+ @get hit_found, material_idx , dist, bary, normal , ray = reflection_hit_soa[idx]
452498 # Compute reflection color (simplified - no recursive shadows for performance)
453499 reflection_color = if hit_found
454500 refl_point = ray. o + ray. d * dist
455- # Get triangle from BVH using stored index
456- refl_tri = bvh_triangles[tri_idx]
457- v0, v1, v2 = Raycore. normals (refl_tri)
458- u, v, w = bary
459- refl_normal = Vec3f (normalize (v0 * u + v1 * v + v2 * w))
501+ refl_normal = normal
460502
461- refl_mat = ctx. materials[refl_tri . material_idx]
503+ refl_mat = ctx. materials[material_idx]
462504 refl_base_color = Vec3f (refl_mat. base_color. r, refl_mat. base_color. g, refl_mat. base_color. b)
463505
464506 # Simplified lighting (ambient + first light only, no shadows)
@@ -614,7 +656,7 @@ function WavefrontRenderer(
614656 shadow_ray_queue = similar_soa (img, ShadowRayWork, num_shadow_rays)
615657 shadow_result_queue = similar_soa (img, ShadowResult, num_shadow_rays)
616658 reflection_ray_soa = similar_soa (img, ReflectionRayWork, num_rays)
617- reflection_hit_soa = similar_soa (img, ReflectionHitWork{Int32} , num_rays)
659+ reflection_hit_soa = similar_soa (img, ReflectionHitWork, num_rays)
618660 shading_queue = similar_soa (img, ShadedResult, num_rays)
619661 sample_accumulator = similar (img, Vec3f, num_rays)
620662 active_count = similar (img, Int32, 1 )
@@ -749,7 +791,6 @@ function render!(renderer::WavefrontRenderer)
749791 refl_shade_kernel! (
750792 renderer. primary_hit_queue,
751793 renderer. reflection_hit_soa,
752- renderer. bvh. primitives,
753794 renderer. ctx,
754795 renderer. sky_color,
755796 renderer. shading_queue,
0 commit comments