Hello,
I’m new to Julia, and am out of ideas on how to prevent my code from allocating. I’ve made a fairly naive translation of the Raytracing Weekend program into Julia. I’m aware that I’m not the first person to do this, and when comparing my code to others’ it doesn’t seem that different, but it seems significantly slower. My code runs about 10x slower than the Rust implementation I wrote. I was hoping to get it much closer than that.
Here’s the function I’m trying to understand:
@inline function hit(sphere::Sphere, ray::Ray, tMin::Float64, tMax::Float64)::Union{HitRecord,Nothing}
oc = ray.origin .- sphere.center
a = lengthSquared(ray.direction)
half_b = dot(oc, ray.direction)
c = lengthSquared(oc) - (sphere.radius * sphere.radius)
discriminant = (half_b * half_b) - (a * c)
if discriminant < 0
return nothing
end
sqrtd = sqrt(discriminant)
root = (-half_b - sqrtd) / a
if root < tMin || tMax < root
root = (-half_b + sqrtd) / a
if root < tMin || tMax < root
return nothing
end
end
t = root
p = at(ray, root)
outwardNormal = (p .- sphere.center) ./ sphere.radius
frontFace, normal = getFaceNormal(ray, outwardNormal)
HitRecord(p, normal, t, frontFace, sphere.material)
end
Here’s a link to the full code on github if you want to see more context.
The very last line that creates a HitRecord is allocating. (Determined by running with --track-allocation=user
.) I’ve tried a variety of things, including making Sphere generic over Material, and adding tons of extra type annotations, with no luck.
Most specifically, I’m trying to understand why there’s an allocation in this function where I’m returning an immutable struct. I’m guessing it still has something to do with how I’m storing material
, but in this thread about optimizing the raytracing weekend code, the code’s structs are very similar, storing an abstract Material
type on the HitRecord
.