Skip to content

Commit

Permalink
Using Triangle3Writer and Line2Writer interfaces for the rendering ro…
Browse files Browse the repository at this point in the history
…utines.

This allows buffering so the []*Triangle3 and []*Line2 slices written to the output channel have more elements.
This results in fewer channel writes and removes channel performance as a bottleneck.
  • Loading branch information
deadsy committed Aug 11, 2023
1 parent 902290e commit fe19a07
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 35 deletions.
12 changes: 6 additions & 6 deletions render/dc2.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func (dc *dc2) corner(vi v2i.Vec) v2.Vec {
return dc.origin.Add(conv.V2iToV2(vi).MulScalar(dc.resolution))
}

func (dc *dc2) drawNode(node *node2, output chan<- []*sdf.Line2) {
func (dc *dc2) drawNode(node *node2, output sdf.Line2Writer) {

k := int(node.n) * 2

Expand All @@ -152,11 +152,10 @@ func (dc *dc2) drawNode(node *node2, output chan<- []*sdf.Line2) {
l2 := sdf.Line2{c2, c3}
l3 := sdf.Line2{c3, c0}

output <- []*sdf.Line2{&l0, &l1, &l2, &l3}

output.Write([]*sdf.Line2{&l0, &l1, &l2, &l3})
}

func (dc *dc2) qtOutput(node *node2, output chan<- []*sdf.Line2) {
func (dc *dc2) qtOutput(node *node2, output sdf.Line2Writer) {
if node.child != nil {
dc.qtOutput(&node.child[0], output)
dc.qtOutput(&node.child[1], output)
Expand All @@ -171,7 +170,7 @@ func (dc *dc2) qtOutput(node *node2, output chan<- []*sdf.Line2) {
}

// dualContouring2D generates line segments for an SDF2 using dual contouring.
func dualContouring2D(s sdf.SDF2, resolution float64, output chan<- []*sdf.Line2) {
func dualContouring2D(s sdf.SDF2, resolution float64, output sdf.Line2Writer) {
// Scale the bounding box about the center to make sure the boundaries
// aren't on the object surface.
bb := s.BoundingBox()
Expand All @@ -188,6 +187,7 @@ func dualContouring2D(s sdf.SDF2, resolution float64, output chan<- []*sdf.Line2
topNode := node2{v: v2i.Vec{0, 0}, n: levels - 1}
dc.processNode(&topNode)
dc.qtOutput(&topNode, output)
output.Close()
}

//-----------------------------------------------------------------------------
Expand All @@ -213,7 +213,7 @@ func (r *DualContouring2D) Info(s sdf.SDF2) string {
}

// Render produces a 2d line mesh over the bounding area of an sdf2.
func (r *DualContouring2D) Render(s sdf.SDF2, output chan<- []*sdf.Line2) {
func (r *DualContouring2D) Render(s sdf.SDF2, output sdf.Line2Writer) {
bbSize := s.BoundingBox().Size()
resolution := bbSize.MaxComponent() / float64(r.meshCells)
dualContouring2D(s, resolution, output)
Expand Down
12 changes: 5 additions & 7 deletions render/march2.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (l *lineCache) get(x, y int) float64 {

//-----------------------------------------------------------------------------

func marchingSquares(s sdf.SDF2, resolution float64) []*sdf.Line2 {
func marchingSquares(s sdf.SDF2, resolution float64, output sdf.Line2Writer) {
// Scale the bounding box about the center to make sure the boundaries
// aren't on the object surface.
bb := s.BoundingBox()
Expand All @@ -93,7 +93,6 @@ func marchingSquares(s sdf.SDF2, resolution float64) []*sdf.Line2 {
nx, ny := steps.X, steps.Y
dx, dy := inc.X, inc.Y

var lines []*sdf.Line2
var p v2.Vec
p.X = base.X
for x := 0; x < nx; x++ {
Expand All @@ -116,13 +115,12 @@ func marchingSquares(s sdf.SDF2, resolution float64) []*sdf.Line2 {
l.get(1, y+1),
l.get(0, y+1),
}
lines = append(lines, msToLines(corners, values, 0)...)
output.Write(msToLines(corners, values, 0))
p.Y += dy
}
p.X += dx
}

return lines
output.Close()
}

//-----------------------------------------------------------------------------
Expand All @@ -148,10 +146,10 @@ func (r *MarchingSquaresUniform) Info(s sdf.SDF2) string {
}

// Render produces a 2d line mesh over the bounding area of an sdf2.
func (r *MarchingSquaresUniform) Render(s sdf.SDF2, output chan<- []*sdf.Line2) {
func (r *MarchingSquaresUniform) Render(s sdf.SDF2, output sdf.Line2Writer) {
bbSize := s.BoundingBox().Size()
resolution := bbSize.MaxComponent() / float64(r.meshCells)
output <- marchingSquares(s, resolution)
marchingSquares(s, resolution, output)
}

//-----------------------------------------------------------------------------
Expand Down
9 changes: 5 additions & 4 deletions render/march2x.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (dc *dcache2) isEmpty(c *square) bool {
}

// Process a square. Generate line segments, or more squares.
func (dc *dcache2) processSquare(c *square, output chan<- []*sdf.Line2) {
func (dc *dcache2) processSquare(c *square, output sdf.Line2Writer) {
if !dc.isEmpty(c) {
if c.n == 1 {
// this square is at the required resolution
Expand All @@ -108,7 +108,7 @@ func (dc *dcache2) processSquare(c *square, output chan<- []*sdf.Line2) {
corners := [4]v2.Vec{c0, c1, c2, c3}
values := [4]float64{d0, d1, d2, d3}
// output the line(s) for this square
output <- msToLines(corners, values, 0)
output.Write(msToLines(corners, values, 0))
} else {
// process the sub squares
n := c.n - 1
Expand All @@ -125,7 +125,7 @@ func (dc *dcache2) processSquare(c *square, output chan<- []*sdf.Line2) {
//-----------------------------------------------------------------------------

// marchingSquaresQuadtree generates line segments for an SDF2 using quadtree subdivision.
func marchingSquaresQuadtree(s sdf.SDF2, resolution float64, output chan<- []*sdf.Line2) {
func marchingSquaresQuadtree(s sdf.SDF2, resolution float64, output sdf.Line2Writer) {
// Scale the bounding box about the center to make sure the boundaries
// aren't on the object surface.
bb := s.BoundingBox()
Expand All @@ -140,6 +140,7 @@ func marchingSquaresQuadtree(s sdf.SDF2, resolution float64, output chan<- []*sd
dc := newDcache2(s, bb.Min, resolution, levels)
// process the quadtree, start at the top level
dc.processSquare(&square{v2i.Vec{0, 0}, levels - 1}, output)
output.Close()
}

//-----------------------------------------------------------------------------
Expand All @@ -165,7 +166,7 @@ func (r *MarchingSquaresQuadtree) Info(s sdf.SDF2) string {
}

// Render produces a 2d line mesh over the bounding area of an sdf2.
func (r *MarchingSquaresQuadtree) Render(s sdf.SDF2, output chan<- []*sdf.Line2) {
func (r *MarchingSquaresQuadtree) Render(s sdf.SDF2, output sdf.Line2Writer) {
bbSize := s.BoundingBox().Size()
resolution := bbSize.MaxComponent() / float64(r.meshCells)
marchingSquaresQuadtree(s, resolution, output)
Expand Down
12 changes: 5 additions & 7 deletions render/march3.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,8 @@ func (l *layerYZ) Get(x, y, z int) float64 {

//-----------------------------------------------------------------------------

func marchingCubes(s sdf.SDF3, box sdf.Box3, step float64) []*sdf.Triangle3 {
func marchingCubes(s sdf.SDF3, box sdf.Box3, step float64, output sdf.Triangle3Writer) {

var triangles []*sdf.Triangle3
size := box.Size()
base := box.Min
steps := conv.V3ToV3i(size.DivScalar(step).Ceil())
Expand Down Expand Up @@ -181,15 +180,13 @@ func marchingCubes(s sdf.SDF3, box sdf.Box3, step float64) []*sdf.Triangle3 {
l.Get(1, y, z+1),
l.Get(1, y+1, z+1),
l.Get(0, y+1, z+1)}
triangles = append(triangles, mcToTriangles(corners, values, 0)...)
output.Write(mcToTriangles(corners, values, 0))
p.Z += dz
}
p.Y += dy
}
p.X += dx
}

return triangles
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -289,7 +286,7 @@ func (r *MarchingCubesUniform) Info(s sdf.SDF3) string {
}

// Render produces a 3d triangle mesh over the bounding volume of an sdf3.
func (r *MarchingCubesUniform) Render(s sdf.SDF3, output chan<- []*sdf.Triangle3) {
func (r *MarchingCubesUniform) Render(s sdf.SDF3, output sdf.Triangle3Writer) {
// work out the region we will sample
bb0 := s.BoundingBox()
bb0Size := bb0.Size()
Expand All @@ -298,7 +295,8 @@ func (r *MarchingCubesUniform) Render(s sdf.SDF3, output chan<- []*sdf.Triangle3
bb1Size = bb1Size.Ceil().AddScalar(1)
bb1Size = bb1Size.MulScalar(meshInc)
bb := sdf.NewBox3(bb0.Center(), bb1Size)
output <- marchingCubes(s, bb, meshInc)
marchingCubes(s, bb, meshInc, output)
output.Close()
}

//-----------------------------------------------------------------------------
Expand Down
9 changes: 5 additions & 4 deletions render/march3x.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (dc *dcache3) isEmpty(c *cube) bool {
}

// Process a cube. Generate triangles, or more cubes.
func (dc *dcache3) processCube(c *cube, output chan<- []*sdf.Triangle3) {
func (dc *dcache3) processCube(c *cube, output sdf.Triangle3Writer) {
if !dc.isEmpty(c) {
if c.n == 1 {
// this cube is at the required resolution
Expand All @@ -116,7 +116,7 @@ func (dc *dcache3) processCube(c *cube, output chan<- []*sdf.Triangle3) {
corners := [8]v3.Vec{c0, c1, c2, c3, c4, c5, c6, c7}
values := [8]float64{d0, d1, d2, d3, d4, d5, d6, d7}
// output the triangle(s) for this cube
output <- mcToTriangles(corners, values, 0)
output.Write(mcToTriangles(corners, values, 0))
} else {
// process the sub cubes
n := c.n - 1
Expand All @@ -137,7 +137,7 @@ func (dc *dcache3) processCube(c *cube, output chan<- []*sdf.Triangle3) {
//-----------------------------------------------------------------------------

// marchingCubesOctree generates a triangle mesh for an SDF3 using octree subdivision.
func marchingCubesOctree(s sdf.SDF3, resolution float64, output chan<- []*sdf.Triangle3) {
func marchingCubesOctree(s sdf.SDF3, resolution float64, output sdf.Triangle3Writer) {
// Scale the bounding box about the center to make sure the boundaries
// aren't on the object surface.
bb := s.BoundingBox()
Expand All @@ -152,6 +152,7 @@ func marchingCubesOctree(s sdf.SDF3, resolution float64, output chan<- []*sdf.Tr
dc := newDcache3(s, bb.Min, resolution, levels)
// process the octree, start at the top level
dc.processCube(&cube{v3i.Vec{0, 0, 0}, levels - 1}, output)
output.Close()
}

//-----------------------------------------------------------------------------
Expand All @@ -177,7 +178,7 @@ func (r *MarchingCubesOctree) Info(s sdf.SDF3) string {
}

// Render produces a 3d triangle mesh over the bounding volume of an sdf3.
func (r *MarchingCubesOctree) Render(s sdf.SDF3, output chan<- []*sdf.Triangle3) {
func (r *MarchingCubesOctree) Render(s sdf.SDF3, output sdf.Triangle3Writer) {
// work out the sampling resolution to use
bbSize := s.BoundingBox().Size()
resolution := bbSize.MaxComponent() / float64(r.meshCells)
Expand Down
14 changes: 7 additions & 7 deletions render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ import (

// Render3 renders a 3D triangle mesh over the bounding volume of an sdf3.
type Render3 interface {
Render(sdf3 sdf.SDF3, output chan<- []*sdf.Triangle3)
Render(sdf3 sdf.SDF3, output sdf.Triangle3Writer)
Info(sdf3 sdf.SDF3) string
}

// Render2 renders a 2D line set over the bounding area of an sdf2.
type Render2 interface {
Render(s sdf.SDF2, output chan<- []*sdf.Line2)
Render(s sdf.SDF2, output sdf.Line2Writer)
Info(s sdf.SDF2) string
}

Expand All @@ -41,7 +41,7 @@ func ToTriangles(
// To write the triangles.
output := sdf.WriteTriangles(&wg, &triangles)
// Run the renderer.
r.Render(s, output)
r.Render(s, sdf.NewTriangle3Buffer(output))
// Stop the writer reading on the channel.
close(output)
// Wait for the write to complete.
Expand All @@ -67,7 +67,7 @@ func ToSTL(
return
}
// run the renderer
r.Render(s, output)
r.Render(s, sdf.NewTriangle3Buffer(output))
// stop the STL writer reading on the channel
close(output)
// wait for the file write to complete
Expand All @@ -91,7 +91,7 @@ func To3MF(
return
}
// run the renderer
r.Render(s, output)
r.Render(s, sdf.NewTriangle3Buffer(output))
// stop the STL writer reading on the channel
close(output)
// wait for the file write to complete
Expand All @@ -115,7 +115,7 @@ func ToDXF(
return
}
// run the renderer
r.Render(s, output)
r.Render(s, sdf.NewLine2Buffer(output))
// stop the DXF writer reading on the channel
close(output)
// wait for the file write to complete
Expand All @@ -140,7 +140,7 @@ func ToSVG(
fmt.Printf("%s", err)
}
// run the renderer
r.Render(s, output)
r.Render(s, sdf.NewLine2Buffer(output))
// stop the SVG writer reading on the channel
close(output)
// wait for the file write to complete
Expand Down

0 comments on commit fe19a07

Please sign in to comment.