Development has moved to https://github.com/soypat/gsdf.
This project has been archived in favor of developing a more advanced solution. gsdf redesigns APIs to be vectorised speeding things up considerably and enabling usage of GPU which enables real-time visualization of shapes with infinite detail (no triangle rendering step required).
Most functionality in sdf has already been reimplemented at the time of archiving. Feel free to ask questions in the issue tracker!
A rewrite of the original Signed Distance Function CAD package sdfx for generating 2D and 3D geometry using Go.
- GUI with real-time rendering using sdf3ui (or SDF Viewer).
- 3d and 2d objects modelled with signed distance functions (SDFs).
- Minimal and idiomatic API.
- Render objects as triangles or save to STL, 3MF(experimental) file format.
- End-to-end testing using image comparison.
mustandformpackages provide panicking and normal error handling basic shape generation APIs for different scenarios.- Dead-simple, single method
Rendererinterface. - Import mesh files: Edit STL and 3MF files as if they were native SDFs using
sdfexp.ImportModel - Tetrahedron mesher: Measure volume or create physics models of your shapes using
sdfexp.UniformTetrahedronMesh. Experimental feature. Example result image.
For real-world examples with images see examples directory README.
See images of rendered shapes in render/testdata.
Here is a rendered bolt from one of the unit tests under form3_test.go
- Clean up thread API mess
- Add a 2D renderer and it's respective
Renderer2interface. - Make 3D renderer multicore
Advantages of deadsy/sdfx:
- Widely used
- More helper functions
- Working 2D renderer
Advantages of soypat/sdf:
- Very fast rendering
deadsy/sdfxis over 2 times slower and has ~5 times more allocations.
- Minimal and idiomatic API
Rendererinterface is dead-simple, idiomatic Go and not limited to SDFs- deadsy/sdfx
Renderer3interface has filledrenderpackage with technical debt.
- deadsy/sdfx
- Has
SDFUnionandSDFDiffinterfaces for blending shapes easilyMinPolyredesign to allow for n-degree polynomials. Also returns a sensible "undefined output"MinFuncbefore dividing by zero.
- No
nilvalued SDFs- deadsy/sdfx internally makes use of
nilSDFs as "empty" objects. This can later cause panics during rendering well after the point of failure causing hard to debug issues.
- deadsy/sdfx internally makes use of
- Well defined package organization.
- deadsy/sdfx dumps helper and utility functions in
sdf
- deadsy/sdfx dumps helper and utility functions in
- End-to-end tested.
- Ensures functioning renderer and SDF functions using image comparison preventing accidental changes.
- Error-free API under
must3andmust2packages for makers.- For simple projects these packages allow for streamlined error handling process using
panicinstead of returned errors. - deadsy/sdfx only allows for Go-style error handling like the
form3andform2packages.
- For simple projects these packages allow for streamlined error handling process using
- Sound use of
mathpackage for best precision and overflow prevention.math.Hypotused for all length calculations.deadsy/sdfxdoes not usemath.Hypot.
- Uses gonum's
spatialpackagesdfxhas own vector types with methods which hurt code legibilityspatialtypes from gonum library with correct Triangle degeneracy calculation.deadsy/sdfx's Degenerate calculation is incorrect.
- Idiomatic
threadpackage. Define arbitrary threads with ease usingThreaderinterface.deadsy/sdfxdefines threads with strings i.e."M16x2".sdfDefines threads with types corresponding to standards. i.e:thread.ISO{D:16, P:2}, which defines an M16x2 ISO thread.
See CONTRIBUTING.
The original sdfx package is amazing. I thank deadsy for putting all that great work into making an amazing tool I use daily. That said, there are some things that were not compatible with my needs:
Here is a benchmark rendering a threaded bolt:
$ go test -benchmem -run=^$ -bench ^(BenchmarkSDFXBolt|BenchmarkBolt)$ ./render
goos: linux
goarch: amd64
pkg: github.com/soypat/sdf/render
cpu: AMD Ryzen 5 3400G with Radeon Vega Graphics
BenchmarkSDFXBolt-8 6 196941244 ns/op 14700786 B/op 98261 allocs/op
BenchmarkBolt-8 13 87547265 ns/op 18136785 B/op 20754 allocs/op
PASS
ok github.com/soypat/sdf/render 4.390s
BenchmarkBolt-8 is this implementation of Octree. BenchmarkSDFXBolt-8 is the sdfx implementation of said algorithm.
- deadsy/sdfx#48 Vector API redesign
- deadsy/sdfx#35 Better STL save functions.
- deadsy/sdfx#50 Removing returned errors from shape generation functions
The vector math functions are methods which yield hard to follow operations. i.e:
return bb.Min.Add(bb.Size().Mul(i.ToV3().DivScalar(float64(node.meshSize)).
Div(node.cellCounts.ToV3().DivScalar(float64(node.meshSize))))) // actual code from original sdfx.A more pressing issue was the Renderer3 interface definition method, Render
type Renderer3 interface {
// ...
Render(s sdf.SDF3, meshCells int, output chan<- *Triangle3)
}This presented a few problems:
-
Raises many questions about usage of the function Render- who closes the channel? Does this function block? Do I have to call it as a goroutine?
-
To implement a renderer one needs to bake in concurrency which is a hard thing to get right from the start. This also means all rendering code besides having the responsibility of computing geometry, it also has to handle concurrency features of the language. This leads to rendering functions with dual responsibility- compute geometry and also handle the multi-core aspect of the computation making code harder to maintain in the long run
-
Using a channel to send individual triangles is probably a bottleneck.
-
I would liken
meshCellsto an implementation detail of the renderer used. This can be passed as an argument when instantiating the renderer used. -
Who's to say we have to limit ourselves to signed distance functions? With the new proposed
Rendererinterface this is no longer the case.
None planned.
Gopher rendition by Juliette Whittingslow.
Gopher design authored by Renée French
is licensed by the Creative Commons Attribution 3.0 licensed.