Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ Packages that have spawned from polyform's undertaking and have since been refac
- [sfm](https://github.com/EliCDavis/sfm) - Utilities for interacting with reconstruction data from different SFM programs
- [bitlib](https://github.com/EliCDavis/bitlib) - Utilities for reading and writing binary data

## Contributing

Learn how to [create your own nodes](./docs/guides/CreatingNodes/README.md) for others to use.

## Procedural Generation Examples

You can at the different projects under the [examples](/examples/) folder for different examples on how to procedurally generate meshes.
Expand Down
3 changes: 3 additions & 0 deletions cmd/polyform/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/EliCDavis/polyform/drawing/texturing"
_ "github.com/EliCDavis/polyform/drawing/texturing"
_ "github.com/EliCDavis/polyform/drawing/texturing/normals"
_ "github.com/EliCDavis/polyform/drawing/texturing/pattern"

_ "github.com/EliCDavis/polyform/formats/colmap"
_ "github.com/EliCDavis/polyform/formats/gltf"
Expand All @@ -42,6 +43,7 @@ import (
_ "github.com/EliCDavis/polyform/math/geometry"
_ "github.com/EliCDavis/polyform/math/noise"
_ "github.com/EliCDavis/polyform/math/quaternion"
_ "github.com/EliCDavis/polyform/math/sdf"
_ "github.com/EliCDavis/polyform/math/trig"
_ "github.com/EliCDavis/polyform/math/trs"
_ "github.com/EliCDavis/polyform/math/unit"
Expand All @@ -50,6 +52,7 @@ import (

_ "github.com/EliCDavis/polyform/modeling"
_ "github.com/EliCDavis/polyform/modeling/extrude"
_ "github.com/EliCDavis/polyform/modeling/marching"
_ "github.com/EliCDavis/polyform/modeling/meshops"
_ "github.com/EliCDavis/polyform/modeling/meshops/gausops"
_ "github.com/EliCDavis/polyform/modeling/primitives"
Expand Down
4 changes: 4 additions & 0 deletions docs/resources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,7 @@ Resources either directly contributing to the code, or are just interesting find
- Morton Encoding
- [_"Morton encoding/decoding through bit interleaving: Implementations"_ Jeroen Baert's Blog](https://www.forceflow.be/2013/10/07/morton-encodingdecoding-through-bit-interleaving-implementations/)
- [Code](https://github.com/Forceflow/libmorton)
- Quad Spheres
- [_"Wraparound square tile maps on a sphere"_ by Redblob](https://www.redblobgames.com/x/1938-square-tiling-of-sphere/)
- [_"Mapping a Cube to a Sphere"_ by Harry van Langen](https://hvlanalysis.blogspot.com/2023/05/mapping-cube-to-sphere.html?m=1)
- [_"Survey of Cube Mapping Methods in Interactive Computer Graphics"_ by M. Lambers](https://marlam.de/publications/cubemaps/lambers2019cubemaps.pdf)
8 changes: 8 additions & 0 deletions drawing/coloring/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,11 @@ func Interpolate(a, b color.Color, t float64) color.Color {
A: uint8(aVal),
}
}

func Greyscale(c color.Color) float64 {
r, g, b, _ := c.RGBA()
rF := float64(r >> 8)
gF := float64(g >> 8)
bF := float64(b >> 8)
return (rF + gF + bF) / (255 * 3)
}
4 changes: 2 additions & 2 deletions drawing/texturing/blur.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ func convolve1DGaussian[T any](space vector.Space[T], src Texture[T], dst Textur
func RadialGaussianBlur[T any](space vector.Space[T], src Texture[T], radius int, sigma float64) Texture[T] {
kernel := gaussianKernel(radius, sigma)

tmp := NewTexture[T](src.width, src.height)
out := NewTexture[T](src.width, src.height)
tmp := Empty[T](src.width, src.height)
out := Empty[T](src.width, src.height)

// Horizontal then vertical
convolve1DGaussian(space, src, tmp, kernel, true)
Expand Down
6 changes: 3 additions & 3 deletions drawing/texturing/color.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func DivideColor(a, b Texture[coloring.Color]) (*Texture[coloring.Color], error)
return nil, ErrMismatchDimensions
}

result := NewTexture[coloring.Color](a.width, a.height)
result := Empty[coloring.Color](a.width, a.height)
a.ScanParallel(func(x, y int, v coloring.Color) {
other := b.Get(x, y)
result.Set(x, y, coloring.Color{
Expand All @@ -25,7 +25,7 @@ func DivideColor(a, b Texture[coloring.Color]) (*Texture[coloring.Color], error)

func MaxColor(a Texture[coloring.Color], other float64) Texture[coloring.Color] {

result := NewTexture[coloring.Color](a.width, a.height)
result := Empty[coloring.Color](a.width, a.height)
a.ScanParallel(func(x, y int, v coloring.Color) {
result.Set(x, y, coloring.Color{
R: max(v.R, other),
Expand All @@ -40,7 +40,7 @@ func MaxColor(a Texture[coloring.Color], other float64) Texture[coloring.Color]

func ClampColor(a Texture[coloring.Color], minimum, maximum float64) Texture[coloring.Color] {

result := NewTexture[coloring.Color](a.width, a.height)
result := Empty[coloring.Color](a.width, a.height)
a.ScanParallel(func(x, y int, v coloring.Color) {
result.Set(x, y, coloring.Color{
R: min(max(v.R, minimum), maximum),
Expand Down
14 changes: 13 additions & 1 deletion drawing/texturing/errors.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package texturing

import "errors"
import (
"errors"
"fmt"

"github.com/EliCDavis/vector/vector2"
)

var ErrMismatchDimensions = errors.New("mismatch texture resolutions")

type InvalidDimension vector2.Vector[int]

func (id InvalidDimension) Error() string {
v := vector2.Vector[int](id)
return fmt.Sprintf("invalid texture dimensions %dx%d", v.X(), v.Y())
}
4 changes: 2 additions & 2 deletions drawing/texturing/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func OneMinus(in Texture[float64]) Texture[float64] {
result := NewTexture[float64](in.width, in.height)
result := Empty[float64](in.width, in.height)
for y := range in.height {
for x := range in.width {
result.Set(x, y, 1-in.Get(x, y))
Expand Down Expand Up @@ -47,7 +47,7 @@ func (n MultiplyFloat1Node) Result(out *nodes.StructOutput[Texture[float64]]) {
return
}

result := NewTexture[float64](textures[0].Width(), textures[0].Height())
result := Empty[float64](textures[0].Width(), textures[0].Height())
for y := range result.Height() {
for x := range result.Width() {
v := textures[0].Get(x, y)
Expand Down
12 changes: 6 additions & 6 deletions drawing/texturing/gradient.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type RadialGradient[T any] struct {
}

func (rg RadialGradient[T]) Texture() Texture[T] {
tex := NewTexture[T](rg.Width, rg.Height)
tex := Empty[T](rg.Width, rg.Height)
center := vector2.New(rg.Width, rg.Height).
ToFloat64().
Scale(0.5)
Expand All @@ -45,7 +45,7 @@ func (n RadialGradientNode[T]) LinearGradient(out *nodes.StructOutput[Texture[T]
height := nodes.TryGetOutputValue(out, n.Height, 1)

if n.Gradient == nil {
out.Set(NewTexture[T](width, height))
out.Set(Empty[T](width, height))
return
}

Expand All @@ -69,7 +69,7 @@ type LinearGradient[T any] struct {
}

func (lg LinearGradient[T]) Texture() Texture[T] {
tex := NewTexture[T](lg.Width, lg.Height)
tex := Empty[T](lg.Width, lg.Height)

boxCenter := vector3.New(lg.Width, lg.Height, 0).
ToFloat64().
Expand Down Expand Up @@ -109,7 +109,7 @@ func (n LinearGradientNode[T]) LinearGradient(out *nodes.StructOutput[Texture[T]
height := nodes.TryGetOutputValue(out, n.Height, 1)

if n.Gradient == nil {
out.Set(NewTexture[T](width, height))
out.Set(Empty[T](width, height))
return
}

Expand All @@ -124,7 +124,7 @@ func (n LinearGradientNode[T]) LinearGradient(out *nodes.StructOutput[Texture[T]
}

func ApplyGradient[T any](time Texture[float64], gradient coloring.Gradient[T]) Texture[T] {
result := NewTexture[T](time.width, time.height)
result := Empty[T](time.width, time.height)
for y := range result.height {
for x := range result.width {
result.Set(x, y, gradient.Sample(time.Get(x, y)))
Expand All @@ -145,7 +145,7 @@ func (n ApplyGradientNode[T]) Texture(out *nodes.StructOutput[Texture[T]]) {

time := nodes.GetOutputValue(out, n.Time)
if n.Gradient == nil {
out.Set(NewTexture[T](time.Width(), time.Height()))
out.Set(Empty[T](time.Width(), time.Height()))
return
}

Expand Down
2 changes: 1 addition & 1 deletion drawing/texturing/noise.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func texture(
out.CaptureError(fmt.Errorf("invalid height dimension: %d", height))
return
}
t := NewTexture[float64](width, height)
t := Empty[float64](width, height)

scale := nodes.TryGetOutputValue(out, Scale, vector2.One[float64]())
offset := nodes.TryGetOutputValue(out, Offset, 0)
Expand Down
23 changes: 22 additions & 1 deletion drawing/texturing/normals/fill.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,30 @@ import (
"image"
"image/color"
"image/draw"

"github.com/EliCDavis/polyform/drawing/texturing"
"github.com/EliCDavis/polyform/nodes"
"github.com/EliCDavis/vector/vector2"
"github.com/EliCDavis/vector/vector3"
)

func Fill(img draw.Image) {
func FillImage(img draw.Image) {
blue := color.RGBA{128, 128, 255, 255}
draw.Draw(img, img.Bounds(), &image.Uniform{blue}, image.Point{}, draw.Src)
}

type NewNode struct {
Dimensions nodes.Output[vector2.Int]
}

func (n NewNode) NormalMap(out *nodes.StructOutput[NormalMap]) {
dim := nodes.TryGetOutputValue(out, n.Dimensions, vector2.New(256, 256))
if dim.MinComponent() <= 0 {
out.CaptureError(texturing.InvalidDimension(dim))
return
}

tex := texturing.Empty[vector3.Float64](dim.X(), dim.Y())
tex.Fill(vector3.New(0, 0, 1.))
out.Set(tex)
}
35 changes: 10 additions & 25 deletions drawing/texturing/normals/heightmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,20 @@ const ivec3 off = ivec3(-1,0,1);
vec4 bump = vec4( cross(va,vb), s11 );
*/

// https://stackoverflow.com/questions/5281261/generating-a-normal-map-from-a-height-map
func ImageFromHeightmap(heightmap image.Image, scale float64) *image.RGBA {
dst := image.NewRGBA(heightmap.Bounds())

texturing.ConvolveImage(heightmap, func(x, y int, values []color.Color) {
// s11 := float64(colors.Red(values[4])) / 255

s01 := float64(coloring.Red(values[3])) / 255.
s21 := float64(coloring.Red(values[5])) / 255.
s10 := float64(coloring.Red(values[1])) / 255.
s12 := float64(coloring.Red(values[7])) / 255.

va := vector3.New(2, 0, (s21-s01)*scale).Normalized()
vb := vector3.New(0, 2, (s12-s10)*scale).Normalized()
n := va.Cross(vb)
func ImageToHeightmap(img image.Image, scale float64) HeightMap {
bounds := img.Bounds()
heightmap := texturing.Empty[float64](bounds.Dx(), bounds.Dy())

dst.Set(x, y, color.RGBA{
R: uint8((0.5 + (n.X() / 2.)) * 255),
G: uint8((0.5 + (n.Y() / 2.)) * 255),
B: uint8((0.5 + (n.Z() / 2.)) * 255),
A: 255,
})
heightmap.MutateParallel(func(x, y int, v float64) float64 {
return coloring.Greyscale(img.At(x, y)) * scale
})

return dst
return heightmap
}

func FromHeightmap(heightmap texturing.Texture[float64], scale float64) texturing.Texture[vector3.Float64] {
dst := texturing.NewTexture[vector3.Float64](heightmap.Width(), heightmap.Height())
// https://stackoverflow.com/questions/5281261/generating-a-normal-map-from-a-height-map
func FromHeightmap(heightmap HeightMap, scale float64) NormalMap {
dst := texturing.Empty[vector3.Float64](heightmap.Width(), heightmap.Height())

texturing.Convolve(heightmap, func(x, y int, values []float64) {
s01 := values[3]
Expand All @@ -71,7 +56,7 @@ func FromHeightmap(heightmap texturing.Texture[float64], scale float64) texturin
return dst
}

func ToNormalmap(normals texturing.Texture[vector3.Float64]) image.Image {
func RasterizeNormalmap(normals NormalMap) image.Image {
return normals.ToImage(func(n vector3.Float64) color.Color {
return color.RGBA{
R: uint8((0.5 + (n.X() / 2.)) * 255),
Expand Down
Loading
Loading