-
Notifications
You must be signed in to change notification settings - Fork 12
/
smooth_join.go
55 lines (51 loc) · 1.58 KB
/
smooth_join.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package main
import (
"math"
"sort"
"github.com/unixpickle/model3d/model3d"
)
const (
smoothJoinSDFDelta = 0.04
smoothJoinDelta = 0.02
smoothJoinConstraint = 0.5
)
// SmoothJoin joins solids and smooths them out so that
// they look cleanly joined together.
//
// The constraint argument controls how close to a joint a
// point should be to be considered for smoothing.
func SmoothJoin(constraint float64, solids ...model3d.Solid) model3d.Solid {
sdfs := make([]model3d.SDF, len(solids))
for i, solid := range solids {
subMesh := model3d.MarchingCubesSearch(solid, smoothJoinSDFDelta, 8)
sdfs[i] = model3d.MeshToSDF(subMesh)
}
mesh := model3d.MarchingCubesSearch(model3d.JoinedSolid(solids), smoothJoinDelta, 8)
sdfCache := map[model3d.Coord3D]float64{}
smoother := &model3d.MeshSmoother{
StepSize: 0.1,
Iterations: 100,
ConstraintFunc: func(origin, newCoord model3d.Coord3D) model3d.Coord3D {
var diff float64
if d, ok := sdfCache[origin]; !ok {
var distances []float64
for _, s := range sdfs {
distances = append(distances, math.Abs(s.SDF(origin)))
}
sort.Float64s(distances)
diff = distances[len(distances)-1] - distances[len(distances)-2]
sdfCache[origin] = diff
} else {
diff = d
}
dist := origin.Sub(newCoord).Norm()
maxDist := smoothJoinDelta + math.Max(0, constraint-diff)
if maxDist >= dist {
return model3d.Coord3D{}
}
return origin.Sub(newCoord).Scale(smoothJoinConstraint * (dist - maxDist) / dist)
},
}
mesh = smoother.Smooth(mesh)
return model3d.NewColliderSolid(model3d.MeshToCollider(mesh))
}