Skip to content

Commit

Permalink
gsdfaux: new package to facilitate rendering for users
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Aug 25, 2024
1 parent 39445ba commit 6d8c361
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 282 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ local
*.zip
*.gz
*.tar
*.prof
*.pprof
*.cpuprof
*.heapprof

# image outputs
*.png
Expand Down
116 changes: 26 additions & 90 deletions examples/bolt/main.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,26 @@
package main

import (
"bufio"
"bytes"
"flag"
"fmt"
"log"
"os"
"runtime"
"time"

"github.com/soypat/gsdf"
"github.com/soypat/gsdf/forge/threads"
"github.com/soypat/gsdf/glbuild"
"github.com/soypat/gsdf/gleval"
"github.com/soypat/gsdf/glrender"
"github.com/soypat/gsdf/gsdfaux"
)

const visualization = "bolt.glsl"
const stl = "bolt.stl"

var useGPU = false

func init() {
flag.BoolVar(&useGPU, "gpu", useGPU, "Enable GPU usage")
flag.Parse()
if useGPU {
fmt.Println("enabled GPU usage")
runtime.LockOSThread() // For when using GPU this is required.
}
runtime.LockOSThread() // For when using GPU this is required.
}

// scene generates the 3D object for rendering.
func scene() (gleval.SDF3, error) {
func scene() (glbuild.Shader3D, error) {
const L, shank = 5, 3
threader := threads.ISO{D: 3, P: 0.5, Ext: true}
M3, err := threads.Bolt(threads.BoltParams{
Expand All @@ -44,93 +32,41 @@ func scene() (gleval.SDF3, error) {
if err != nil {
return nil, err
}
return makeSDF(M3)
return M3, nil
}

func main() {
if useGPU {
terminate, err := gleval.Init1x1GLFW()
if err != nil {
log.Fatal("failed to start GLFW", err.Error())
}
defer terminate()
}
sceneStart := time.Now()
func run() error {
useGPU := flag.Bool("gpu", false, "Enable GPU usage")
flag.Parse()
sdf, err := scene()
if err != nil {
fmt.Println("error making scene:", err)
os.Exit(1)
return err
}
elapsedScene := time.Since(sceneStart)
const resDiv = 200
const evaluationBufferSize = 1024 * 8
resolution := sdf.Bounds().Size().Max() / resDiv
renderer, err := glrender.NewOctreeRenderer(sdf, resolution, evaluationBufferSize)
fpstl, err := os.Create(stl)
if err != nil {
fmt.Println("error creating renderer:", err)
os.Exit(1)
return err
}
start := time.Now()
triangles, err := glrender.RenderAll(renderer)
defer fpstl.Close()
fpvis, err := os.Create(visualization)
if err != nil {
fmt.Println("error rendering triangles:", err)
os.Exit(1)
return err
}
elapsed := time.Since(start)
evals := sdf.(interface{ Evaluations() uint64 }).Evaluations()
defer fpvis.Close()

fp, err := os.Create(stl)
if err != nil {
fmt.Println("error creating file:", err)
os.Exit(1)
}
defer fp.Close()
start = time.Now()
w := bufio.NewWriter(fp)
_, err = glrender.WriteBinarySTL(w, triangles)
if err != nil {
fmt.Println("error writing triangles to file:", err)
os.Exit(1)
}
w.Flush()
fmt.Println("SDF created in ", elapsedScene, "evaluated sdf", evals, "times, rendered", len(triangles), "triangles in", elapsed, "wrote file in", time.Since(start))
err = gsdfaux.Render(sdf, gsdfaux.RenderConfig{
STLOutput: fpstl,
VisualOutput: fpvis,
Resolution: sdf.Bounds().Diagonal() / 200,
UseGPU: *useGPU,
})

return err
}

func makeSDF(s glbuild.Shader3D) (gleval.SDF3, error) {
err := glbuild.ShortenNames3D(&s, 32) // Shorten names to not crash GL tokenizer.
func main() {
err := run()
if err != nil {
return nil, err
}
if visualization != "" {
const sceneSize = 0.5
// We include the bounding box in the visualization.
bb := s.Bounds()
envelope, err := gsdf.NewBoundsBoxFrame(bb)
if err != nil {
return nil, err
}
visual := gsdf.Union(s, envelope)
// Scale size and translate to center so visualization is in camera range.
center := bb.Center()
visual = gsdf.Translate(visual, center.X, center.Y, center.Z)
visual = gsdf.Scale(visual, sceneSize/bb.Size().Max())
source := new(bytes.Buffer)
_, err = glbuild.NewDefaultProgrammer().WriteFragVisualizerSDF3(source, visual)
if err != nil {
return nil, err
}
err = os.WriteFile(visualization, source.Bytes(), 0666)
if err != nil {
return nil, err
}
}
if useGPU {
source := new(bytes.Buffer)
_, err := glbuild.NewDefaultProgrammer().WriteComputeSDF3(source, s)
if err != nil {
return nil, err
}
return gleval.NewComputeGPUSDF3(source, s.Bounds())
log.Fatal(err)
}
return gleval.NewCPUSDF3(s)
fmt.Println("bolt example done")
}
148 changes: 54 additions & 94 deletions examples/fibonacci-showerhead/main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package main

import (
"bytes"
"flag"
"fmt"
"log"
"runtime"
"time"

"os"

Expand All @@ -14,52 +13,78 @@ import (
"github.com/soypat/gsdf"
"github.com/soypat/gsdf/forge/threads"
"github.com/soypat/gsdf/glbuild"
"github.com/soypat/gsdf/gleval"
"github.com/soypat/gsdf/glrender"
"github.com/soypat/gsdf/gsdfaux"
)

// Showerhead parameters as defined by showerhead design.
const (
threadExtDiameter = 65.
threadedLength = 5.
threadTurns = 3.
threadPitch = threadedLength / threadTurns
)

// Constructuive parameters defined by our design.
const (
showerheadBaseThick = 2.5
showerheadWall = 4.
threadheight = 5.
)

var (
showerThread = threads.PlasticButtress{
D: threadExtDiameter,
P: threadPitch,
}
stl = "showerhead.stl"
visualization = "showerhead.glsl"
)

func init() {
runtime.LockOSThread() // In case we wish to use OpenGL.
}

func main() {
watch := stopwatch()
func run() error {
useGPU := flag.Bool("gpu", false, "Enable GPU usage")
flag.Parse()
object, err := scene()
if err != nil {
log.Fatalf("creating 3D object: %s", err)
return err
}
fpstl, err := os.Create(stl)
if err != nil {
return err
}
defer fpstl.Close()
fpvis, err := os.Create(visualization)
if err != nil {
return err
}
fmt.Println("created object in", watch())
useGPU := true
err = render(object, useGPU)
defer fpvis.Close()

err = gsdfaux.Render(object, gsdfaux.RenderConfig{
STLOutput: fpstl,
VisualOutput: fpvis,
Resolution: object.Bounds().Diagonal() / 200,
UseGPU: *useGPU,
})

return err
}

func main() {
err := run()
if err != nil {
log.Fatal(err)
}
fmt.Println("showerhead example done")
}

// scene returns the showerhead object.
func scene() (glbuild.Shader3D, error) {

// Showerhead parameters as defined by showerhead geometry.
const (
threadExtDiameter = 65.
threadedLength = 5.
threadTurns = 3.
threadPitch = threadedLength / threadTurns
)

// Constructuive parameters defined by our design.
const (
showerheadBaseThick = 2.5
showerheadWall = 4.
threadheight = 5.
)

var (
showerThread = threads.PlasticButtress{
D: threadExtDiameter,
P: threadPitch,
}
)
// Object accumulates the showerhead sdf.
var object glbuild.Shader3D

Expand Down Expand Up @@ -94,64 +119,6 @@ func scene() (glbuild.Shader3D, error) {
return object, nil
}

func render(s glbuild.Shader3D, useGPU bool) (err error) {
err = glbuild.ShortenNames3D(&s, 6)
if err != nil {
return fmt.Errorf("shortening shader names: %s", err)
}
bb := s.Bounds()
var sdf gleval.SDF3
watch := stopwatch()
if useGPU {
fmt.Println("using GPU")
{
terminate, err := gleval.Init1x1GLFW()
if err != nil {
return err
}
defer terminate()
}
source := new(bytes.Buffer)
_, err = glbuild.NewDefaultProgrammer().WriteComputeSDF3(source, s)
if err != nil {
return err
}
sdf, err = gleval.NewComputeGPUSDF3(source, bb)
} else {
sdf, err = gleval.NewCPUSDF3(s)
}

if err != nil || sdf == nil {
return fmt.Errorf("instantiating SDF: %s", err)
}

fmt.Println("instantiating evaluation SDF took", watch())
const size = 1 << 12
renderer, err := glrender.NewOctreeRenderer(sdf, bb.Size().Max()/350, size)
if err != nil {
return err
}

fp, err := os.Create("showerhead.stl")
if err != nil {
return fmt.Errorf("creating file: %s", err)
}
watch = stopwatch()
triangles, err := glrender.RenderAll(renderer)
if err != nil {
return fmt.Errorf("rendering triangles: %s", err)
}
e := sdf.(interface{ Evaluations() uint64 })
fmt.Println("evaluated SDF", e.Evaluations(), "times and rendered", len(triangles), "triangles in", watch())
watch = stopwatch()
_, err = glrender.WriteBinarySTL(fp, triangles)
if err != nil {
return fmt.Errorf("writing STL file: %s", err)
}
fmt.Println("wrote STL file in", watch())
return nil
}

func fibonacci(n int) ms2.Vec {
// Angle of divergence is very sensitive- 137.3 to 137.5 varies pattern greatly.
const angleOfDivergence = 137.3
Expand All @@ -162,10 +129,3 @@ func fibonacci(n int) ms2.Vec {
sa, ca := math.Sincos(a)
return ms2.Vec{X: r * ca, Y: r * sa}
}

func stopwatch() func() time.Duration {
start := time.Now()
return func() time.Duration {
return time.Since(start)
}
}
Loading

0 comments on commit 6d8c361

Please sign in to comment.