Merge branch 'dev'

This commit is contained in:
Crizomb 2025-09-28 18:47:37 +02:00
commit 62e28624eb
3 changed files with 103 additions and 59 deletions

View file

@ -6,8 +6,12 @@ type Sphere struct {
material Material material Material
} }
func (s Sphere) Distance(p Vector3) (float64, Material) { func (s Sphere) Distance(p Vector3) float64 {
return p.Length() - s.radius, s.material return p.Length() - s.radius
}
func (s Sphere) GetMaterial(p Vector3) Material {
return s.material
} }
// Box // Box
@ -16,9 +20,13 @@ type Box struct {
material Material material Material
} }
func (s Box) Distance(p Vector3) (float64, Material) { func (s Box) Distance(p Vector3) float64 {
q := p.Abs().Sub(s.dimensions) q := p.Abs().Sub(s.dimensions)
return q.Max(0.0).Length() + min(max(q.X, max(q.Y, q.Z)), 0.0), s.material return q.Max(0.0).Length() + min(max(q.X, max(q.Y, q.Z)), 0.0)
}
func (s Box) GetMaterial(p Vector3) Material {
return s.material
} }
// Plane // Plane
@ -27,6 +35,10 @@ type Plane struct {
material Material material Material
} }
func (s Plane) Distance(p Vector3) (float64, Material) { func (s Plane) Distance(p Vector3) float64 {
return p.Dot(s.normal), s.material return p.Dot(s.normal)
}
func (s Plane) GetMaterial(p Vector3) Material {
return s.material
} }

View file

@ -30,7 +30,7 @@ func shadow(point Vector3) float64 {
res := 1.0 res := 1.0
dist_total := 0.0 dist_total := 0.0
for range MAX_STEP { for range MAX_STEP {
dist, _ := scene.Distance(p) dist := scene.Distance(p)
if dist < EPS { if dist < EPS {
return 0 return 0
} }
@ -62,8 +62,9 @@ func reflect(point Vector3, direction Vector3, normal Vector3, mat Material, ref
func rayMarch(origin Vector3, direction Vector3, reflectNumber int) (bool, Vector3) { func rayMarch(origin Vector3, direction Vector3, reflectNumber int) (bool, Vector3) {
p := origin p := origin
for range MAX_STEP { for range MAX_STEP {
dist, mat := scene.Distance(p) dist := scene.Distance(p)
if dist < EPS { if dist < EPS {
mat := scene.GetMaterial(p)
normal := Gradient(scene, p, EPS).Normalized() normal := Gradient(scene, p, EPS).Normalized()
phongShade := phongShading(p, normal, mat) phongShade := phongShading(p, normal, mat)
shadowCoeff := max(shadow(p), 0.3) shadowCoeff := max(shadow(p), 0.3)

View file

@ -5,18 +5,14 @@ import (
) )
type SDF interface { type SDF interface {
Distance(Vector3) (float64, Material) Distance(Vector3) float64
} GetMaterial(Vector3) Material
func DistanceOnly(sdf SDF, p Vector3) float64 {
dist, _ := sdf.Distance(p)
return dist
} }
func Gradient(sdf SDF, p Vector3, eps float64) Vector3 { func Gradient(sdf SDF, p Vector3, eps float64) Vector3 {
dx := (DistanceOnly(sdf, p.Add(Vector3{X: eps})) - DistanceOnly(sdf, p.Add(Vector3{X: -eps}))) / (2 * eps) dx := (sdf.Distance(p.Add(Vector3{X: eps})) - sdf.Distance(p.Add(Vector3{X: -eps}))) / (2 * eps)
dy := (DistanceOnly(sdf, p.Add(Vector3{Y: eps})) - DistanceOnly(sdf, p.Add(Vector3{Y: -eps}))) / (2 * eps) dy := (sdf.Distance(p.Add(Vector3{Y: eps})) - sdf.Distance(p.Add(Vector3{Y: -eps}))) / (2 * eps)
dz := (DistanceOnly(sdf, p.Add(Vector3{Z: eps})) - DistanceOnly(sdf, p.Add(Vector3{Z: -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} return Vector3{X: dx, Y: dy, Z: dz}
} }
@ -27,29 +23,40 @@ type TranslatedSDF struct {
translate Vector3 translate Vector3
} }
func (s TranslatedSDF) Distance(p Vector3) (float64, Material) { func (s TranslatedSDF) Distance(p Vector3) float64 {
return s.primitive.Distance(p.Sub(s.translate)) return s.primitive.Distance(p.Sub(s.translate))
} }
func (s TranslatedSDF) GetMaterial(p Vector3) Material {
return s.primitive.GetMaterial(p.Sub(s.translate))
}
type RotatedSDF struct { type RotatedSDF struct {
primitive SDF primitive SDF
rotVector Vector3 rotVector Vector3
angle float64 angle float64
} }
func (s RotatedSDF) Distance(p Vector3) (float64, Material) { func (s RotatedSDF) Distance(p Vector3) float64 {
rotated_p := Rotate(p, s.rotVector, s.angle) rotated_p := Rotate(p, s.rotVector, s.angle)
return s.primitive.Distance(rotated_p) return s.primitive.Distance(rotated_p)
} }
func (s RotatedSDF) GetMaterial(p Vector3) Material {
rotated_p := Rotate(p, s.rotVector, s.angle)
return s.primitive.GetMaterial(rotated_p)
}
type ScaledSDF struct { type ScaledSDF struct {
primitive SDF primitive SDF
scale float64 scale float64
} }
func (s ScaledSDF) Distance(p Vector3) (float64, Material) { func (s ScaledSDF) Distance(p Vector3) float64 {
dist, color := s.primitive.Distance(p.Scale(1 / s.scale)) return s.primitive.Distance(p.Scale(1 / s.scale))
return dist * s.scale, color }
func (s ScaledSDF) GetMaterial(p Vector3) Material {
return s.primitive.GetMaterial(p.Scale(1 / s.scale))
} }
type RepeatSDF struct { type RepeatSDF struct {
@ -57,29 +64,39 @@ type RepeatSDF struct {
cellSize Vector3 cellSize Vector3
} }
func (s RepeatSDF) Distance(p Vector3) (float64, Material) { func (s RepeatSDF) Distance(p Vector3) float64 {
x, y, z := p.Unpack() x, y, z := p.Unpack()
sx, sy, sz := s.cellSize.Unpack() sx, sy, sz := s.cellSize.Unpack()
round := math.RoundToEven round := math.RoundToEven
nearest_cell := Vector3{sx * round(x/sx), sy * round(y/sy), sz * round(z/sz)} nearest_cell := Vector3{sx * round(x/sx), sy * round(y/sy), sz * round(z/sz)}
return s.primitive.Distance(p.Sub(nearest_cell)) return s.primitive.Distance(p.Sub(nearest_cell))
} }
func (s RepeatSDF) GetMaterial(p Vector3) Material {
x, y, z := p.Unpack()
sx, sy, sz := s.cellSize.Unpack()
round := math.RoundToEven
nearest_cell := Vector3{sx * round(x/sx), sy * round(y/sy), sz * round(z/sz)}
return s.primitive.GetMaterial(p.Sub(nearest_cell))
}
type UnionSDF struct { type UnionSDF struct {
primitive1 SDF primitive1 SDF
primitive2 SDF primitive2 SDF
} }
func (s UnionSDF) Distance(p Vector3) (float64, Material) { func (s UnionSDF) Distance(p Vector3) float64 {
d1, color1 := s.primitive1.Distance(p) return min(s.primitive1.Distance(p), s.primitive2.Distance(p))
d2, color2 := s.primitive2.Distance(p) }
d := min(d1, d2)
func (s UnionSDF) GetMaterial(p Vector3) Material {
d1, color1 := s.primitive1.Distance(p), s.primitive1.GetMaterial(p)
d2, color2 := s.primitive2.Distance(p), s.primitive2.GetMaterial(p)
color := color1 color := color1
if d2 < d1 { if d2 < d1 {
color = color2 color = color2
} }
return d, color return color
} }
type SubstractionSDF struct { type SubstractionSDF struct {
@ -87,12 +104,12 @@ type SubstractionSDF struct {
primitive2 SDF primitive2 SDF
} }
func (s SubstractionSDF) Distance(p Vector3) (float64, Material) { func (s SubstractionSDF) Distance(p Vector3) float64 {
d1, color1 := s.primitive1.Distance(p) return max(s.primitive1.Distance(p), -s.primitive2.Distance(p))
d2, _ := s.primitive2.Distance(p) }
d := max(d1, -d2) func (s SubstractionSDF) GetMaterial(p Vector3) Material {
return d, color1 return s.primitive1.GetMaterial(p)
} }
type IntersectionSDF struct { type IntersectionSDF struct {
@ -100,14 +117,13 @@ type IntersectionSDF struct {
primitive2 SDF primitive2 SDF
} }
func (s IntersectionSDF) Distance(p Vector3) (float64, Material) { func (s IntersectionSDF) Distance(p Vector3) float64 {
return max(s.primitive1.Distance(p), s.primitive2.Distance(p))
}
d1, mat1 := s.primitive1.Distance(p) func (s IntersectionSDF) GetMaterial(p Vector3) Material {
d2, mat2 := s.primitive2.Distance(p) mat1, mat2 := s.primitive1.GetMaterial(p), s.primitive2.GetMaterial(p)
d := max(d1, d2) return MixedMaterial{mat1, mat2, 0.5, p}
var mat Material = MixedMaterial{mat1, mat2, 0.5, p}
return d, mat
} }
type SmoothUnionSDF struct { type SmoothUnionSDF struct {
@ -116,15 +132,20 @@ type SmoothUnionSDF struct {
k float64 k float64
} }
func (s SmoothUnionSDF) Distance(p Vector3) (float64, Material) { func (s SmoothUnionSDF) Distance(p Vector3) float64 {
k := 4 * s.k k := 4 * s.k
d1, mat1 := s.primitive1.Distance(p) d1 := s.primitive1.Distance(p)
d2, mat2 := s.primitive2.Distance(p) d2 := s.primitive2.Distance(p)
h := max(k-math.Abs(d1-d2), 0.0) h := max(k-math.Abs(d1-d2), 0.0)
d := min(d1, d2) - h*h*0.25/k return min(d1, d2) - h*h*0.25/k
}
func (s SmoothUnionSDF) GetMaterial(p Vector3) Material {
k := 4 * s.k
d1, mat1 := s.primitive1.Distance(p), s.primitive1.GetMaterial(p)
d2, mat2 := s.primitive2.Distance(p), s.primitive2.GetMaterial(p)
t := SmoothStep(d2-d1, -k, k) t := SmoothStep(d2-d1, -k, k)
var mat Material = MixedMaterial{mat2, mat1, t, p} return MixedMaterial{mat2, mat1, t, p}
return d, mat
} }
type SmoothSubstractionSDF struct { type SmoothSubstractionSDF struct {
@ -133,15 +154,20 @@ type SmoothSubstractionSDF struct {
k float64 k float64
} }
func (s SmoothSubstractionSDF) Distance(p Vector3) (float64, Material) { func (s SmoothSubstractionSDF) Distance(p Vector3) float64 {
k := 4 * s.k k := 4 * s.k
d1, mat1 := s.primitive1.Distance(p) d1 := s.primitive1.Distance(p)
d2, mat2 := s.primitive2.Distance(p) d2 := s.primitive2.Distance(p)
h := max(k-math.Abs(-d1-d2), 0.0) h := max(k-math.Abs(-d1-d2), 0.0)
d := max(d1, -d2) + h*h*0.25/k return max(d1, -d2) + h*h*0.25/k
}
func (s SmoothSubstractionSDF) GetMaterial(p Vector3) Material {
k := 4 * s.k
d1, mat1 := s.primitive1.Distance(p), s.primitive1.GetMaterial(p)
d2, mat2 := s.primitive2.Distance(p), s.primitive2.GetMaterial(p)
t := SmoothStep(d1-d2, -k, k) t := SmoothStep(d1-d2, -k, k)
var mat Material = MixedMaterial{mat1, mat2, t, p} return MixedMaterial{mat1, mat2, t, p}
return d, mat
} }
type SmoothIntersectionSDF struct { type SmoothIntersectionSDF struct {
@ -150,13 +176,18 @@ type SmoothIntersectionSDF struct {
k float64 k float64
} }
func (s SmoothIntersectionSDF) Distance(p Vector3) (float64, Material) { func (s SmoothIntersectionSDF) Distance(p Vector3) float64 {
k := 4 * s.k k := 4 * s.k
d1, mat1 := s.primitive1.Distance(p) d1 := s.primitive1.Distance(p)
d2, mat2 := s.primitive2.Distance(p) d2 := s.primitive2.Distance(p)
h := max(k-math.Abs(d1-d2), 0.0) h := max(k-math.Abs(d1-d2), 0.0)
d := max(d1, d2) + h*h*0.25/k return max(d1, d2) + h*h*0.25/k
t := SmoothStep(d2-d1, -k, k) }
var mat Material = MixedMaterial{mat1, mat2, t, p}
return d, mat func (s SmoothIntersectionSDF) GetMaterial(p Vector3) Material {
k := 4 * s.k
d1, mat1 := s.primitive1.Distance(p), s.primitive1.GetMaterial(p)
d2, mat2 := s.primitive2.Distance(p), s.primitive2.GetMaterial(p)
t := SmoothStep(d2-d1, -k, k)
return MixedMaterial{mat1, mat2, t, p}
} }