func DiffusePhoton(scene []*geometry.Shape, emitter *geometry.Shape, ray geometry.Ray, colour geometry.Vec3, result chan<- PhotonHit, alpha geometry.Float, depth int, rand *rand.Rand) { if geometry.Float(rand.Float32()) > alpha { return } if shape, distance := ClosestIntersection(scene, ray); shape != nil { impact := ray.Origin.Add(ray.Direction.Mult(distance)) if depth == 0 && emitter == shape { // Leave the emitter first nextRay := geometry.Ray{impact, ray.Direction} DiffusePhoton(scene, emitter, nextRay, colour, result, alpha, depth, rand) } else { normal := shape.NormalDir(impact).Normalize() reverse := ray.Direction.Mult(-1) outgoing := normal if normal.Dot(reverse) < 0 { outgoing = normal.Mult(-1) } strength := colour.Mult(alpha / (1 + distance)) result <- PhotonHit{impact, strength, ray.Direction, uint8(depth)} if shape.Material == geometry.DIFFUSE { // Random bounce for color bleeding u := normal.Cross(reverse).Normalize().Mult(geometry.Float(rand.NormFloat64() * 0.5)) v := u.Cross(normal).Normalize().Mult(geometry.Float(rand.NormFloat64() * 0.5)) bounce := geometry.Vec3{ u.X + outgoing.X + v.X, u.Y + outgoing.Y + v.Y, u.Z + outgoing.Z + v.Z, } bounceRay := geometry.Ray{impact, bounce.Normalize()} bleedColour := colour.MultVec(shape.Colour).Mult(alpha / (1 + distance)) DiffusePhoton(scene, shape, bounceRay, bleedColour, result, alpha*0.66, depth+1, rand) } // Store Shadow Photons shadowRay := geometry.Ray{impact, ray.Direction} DiffusePhoton(scene, shape, shadowRay, geometry.Vec3{0, 0, 0}, result, alpha*0.66, depth+1, rand) } } }