func (p *Plane) RayInteraction(r *gnr.Ray) []*gnr.InteractionResult { // Ray: {P | P = r.Origin + t * r.Direction} // Plane: {P | P * p.Normal + p.Distance = 0} // Substitute: (r.Origin + t * r.Direction) * p.Normal + p.Distance = 0 t := -(p.Distance + gnr.VectorProduct(r.Origin, p.Normal)) / gnr.VectorProduct(r.Direction, p.Normal) if t < 0 { return []*gnr.InteractionResult{} } impact := gnr.CopyVector3f(r.Direction).ScalarMultiply(t).Add(r.Origin) return []*gnr.InteractionResult{{ Color: gnr.ColorWhite, PointOfImpact: impact, Normal: gnr.CopyVector3f(p.Normal), Distance: gnr.VectorDifference(impact, r.Origin).Magnitude(), }} }
func (t *Triangle) ToPlane() *Plane { v1 := gnr.VectorDifference(t.Points[1], t.Points[0]) v2 := gnr.VectorDifference(t.Points[2], t.Points[0]) normal := gnr.VectorCross(v1, v2) return &Plane{ Normal: normal, Distance: -gnr.VectorProduct(normal, t.Points[0]), } }
func (t *Triangle) Contains(p *gnr.Vector3f) bool { tp := t.ToPlane() na := (&Triangle{ Points: [3]*gnr.Vector3f{t.Points[0], t.Points[1], p}, }).ToPlane().Normal nb := (&Triangle{ Points: [3]*gnr.Vector3f{t.Points[1], t.Points[2], p}, }).ToPlane().Normal nc := (&Triangle{ Points: [3]*gnr.Vector3f{t.Points[2], t.Points[0], p}, }).ToPlane().Normal denom := math.Pow(tp.Normal.Magnitude(), 2) ba := gnr.VectorProduct(tp.Normal, na) / denom bb := gnr.VectorProduct(tp.Normal, nb) / denom bc := gnr.VectorProduct(tp.Normal, nc) / denom return ba >= 0 && ba <= 1 && bb >= 0 && bb <= 1 && bc >= 0 && bc <= 1 }
func (aab *AxisAlignedBox) RayInteraction(r *gnr.Ray) []*gnr.InteractionResult { planes := []gnr.Object{ &Plane{ Normal: &gnr.Vector3f{-1, 0, 0}, Distance: -gnr.VectorProduct(&gnr.Vector3f{-1, 0, 0}, aab.Min), }, &Plane{ Normal: &gnr.Vector3f{1, 0, 0}, Distance: -gnr.VectorProduct(&gnr.Vector3f{1, 0, 0}, aab.Max), }, &Plane{ Normal: &gnr.Vector3f{0, -1, 0}, Distance: -gnr.VectorProduct(&gnr.Vector3f{0, -1, 0}, aab.Min), }, &Plane{ Normal: &gnr.Vector3f{0, 1, 0}, Distance: -gnr.VectorProduct(&gnr.Vector3f{0, 1, 0}, aab.Max), }, &Plane{ Normal: &gnr.Vector3f{0, 0, -1}, Distance: -gnr.VectorProduct(&gnr.Vector3f{0, 0, -1}, aab.Min), }, &Plane{ Normal: &gnr.Vector3f{0, 0, 1}, Distance: -gnr.VectorProduct(&gnr.Vector3f{0, 0, 1}, aab.Max), }, } irs := gnr.ObjectSlice(planes).AggregateSliceInteractionResult(func(irs []*gnr.InteractionResult, o gnr.Object) []*gnr.InteractionResult { newIrs := o.RayInteraction(r) p := o.(*Plane) newIrs = gnr.InteractionResultSlice(newIrs).SelectInteractionResult(func(ir *gnr.InteractionResult) *gnr.InteractionResult { // Correct for IEEE754 errors by aligning PoIs with sides of box if math.Abs(p.Normal.X) == 1 { ir.PointOfImpact.X = -p.Distance * p.Normal.X } if math.Abs(p.Normal.Y) == 1 { ir.PointOfImpact.Y = -p.Distance * p.Normal.Y } if math.Abs(p.Normal.Z) == 1 { ir.PointOfImpact.Z = -p.Distance * p.Normal.Z } return ir }) return append(irs, newIrs...) }) irs = gnr.InteractionResultSlice(irs).Where(func(ir *gnr.InteractionResult) bool { return aab.Contains(ir.PointOfImpact) }) return irs }
func (s *Sphere) RayInteraction(r *gnr.Ray) []*gnr.InteractionResult { // Ray: {P | P = r.Origin + t * r.Direction} // Sphere: {P | mag(P - s.Center)^2 - s.Radius^2 = 0} // substitution // mag(r.Origin + t * r.Direction)^2 - s.Radius^2 = 0 d := gnr.VectorDifference(r.Origin, s.Center) p := 2 * gnr.VectorProduct(r.Direction, d) q := math.Pow(d.Magnitude(), 2) - math.Pow(s.Radius, 2) p2 := math.Pow(p, 2) inSqrt := p2/4 - q if inSqrt < 0 { return []*gnr.InteractionResult{} } sqrt := math.Sqrt(inSqrt) t1 := -p/2 + sqrt t2 := -p/2 - sqrt P1 := gnr.VectorSum(r.Origin, gnr.CopyVector3f(r.Direction).ScalarMultiply(t1)) P2 := gnr.VectorSum(r.Origin, gnr.CopyVector3f(r.Direction).ScalarMultiply(t2)) irs := []*gnr.InteractionResult{ {Color: gnr.ColorWhite}, {Color: gnr.ColorWhite}, } irs[0].PointOfImpact = P1 irs[0].Normal = gnr.VectorDifference(P1, s.Center) irs[0].Distance = gnr.VectorDifference(P1, r.Origin).Magnitude() if inSqrt != 0 { irs[1].PointOfImpact = P2 irs[1].Normal = gnr.VectorDifference(P2, s.Center) irs[1].Distance = gnr.VectorDifference(P2, r.Origin).Magnitude() } else { irs = irs[0:1] } return irs }
func (p *Plane) DistanceToPoint(pt *gnr.Vector3f) float64 { n := gnr.CopyVector3f(p.Normal).Normalize() return math.Abs(gnr.VectorProduct(n, pt) + p.Distance) }