package main const EPS = 0.001 type SDF interface { Distance(Vector3) float64 } func Gradient(sdf SDF, p Vector3, eps float64) Vector3 { dx := (sdf.Distance(p.Add(Vector3{X: eps})) - sdf.Distance(p.Add(Vector3{X: -eps}))) / (2 * eps) dy := (sdf.Distance(p.Add(Vector3{Y: eps})) - sdf.Distance(p.Add(Vector3{Y: -eps}))) / (2 * eps) dz := (sdf.Distance(p.Add(Vector3{Z: eps})) - sdf.Distance(p.Add(Vector3{Z: -eps}))) / (2 * eps) return Vector3{X: dx, Y: dy, Z: dz} } // Some transformations see https://iquilezles.org/articles/distfunctions/ type translatedSDF struct { primitive SDF translate Vector3 } func (s translatedSDF) Distance(p Vector3) float64 { return s.primitive.Distance(p.Sub(s.translate)) } type rotatedSDF struct { primitive SDF rotVector Vector3 angle float64 } func (s rotatedSDF) Distance(p Vector3) float64 { rotated_p := rotate(p, s.rotVector, s.angle) return s.primitive.Distance(rotated_p) } type scaledSDF struct { primitive SDF scale float64 } func (s scaledSDF) Distance(p Vector3) float64 { return s.primitive.Distance(p.Scale(1/s.scale)) * s.scale } type infiniteRep struct { primitive SDF cellSize Vector3 } // TODO // func (s infiniteRep) Distance(p Vector3) float64 { // x, y, z := p.Unpack() // sx, sy, sz := s.cellSize.Unpack() // } // Sphere type Sphere struct { center Vector3 radius float64 } func (s Sphere) Distance(p Vector3) float64 { return p.Sub(s.center).Length() }