From eddb3f9709a7ec95ce9762f2a0302fac29e6401e Mon Sep 17 00:00:00 2001 From: Yongwei Xing Date: Tue, 9 Mar 2021 13:41:11 +0800 Subject: [PATCH] add perlin noise --- common/perlinnoise.go | 100 +++++++++++++++++++++++++++++++++ contourline.go | 20 +++---- example/example_contourline.go | 10 ++-- 3 files changed, 115 insertions(+), 15 deletions(-) create mode 100644 common/perlinnoise.go diff --git a/common/perlinnoise.go b/common/perlinnoise.go new file mode 100644 index 0000000..093244a --- /dev/null +++ b/common/perlinnoise.go @@ -0,0 +1,100 @@ +package common + +import ( + "math" + "math/rand" +) + +const ( + perlinYwrapb = 4 + perlinYwrap = 1 << perlinYwrapb + perlinZwrapb = 8 + perlinZwrap = 1 << perlinZwrapb + perlinSize = 4095 + perlinOctaves = 4 + perlinAmpFalloff = 0.5 +) + +type perlinNoise struct { + perlin []float64 +} + +func NewPerlinNoise() *perlinNoise { + perlin := &perlinNoise{perlin: nil} + perlin.perlin = make([]float64, perlinSize+1) + + for i, _ := range perlin.perlin { + perlin.perlin[i] = rand.Float64() + } + return perlin +} + +func (p *perlinNoise) Noise(x, y, z float64) float64 { + if x < 0 { + x = -x + } + + if y < 0 { + y = -y + } + + if z < 0 { + z = -z + } + + xi, yi, zi := int(math.Floor(x)), int(math.Floor(y)), int(math.Floor(z)) + xf, yf, zf := x-float64(xi), y-float64(yi), z-float64(zi) + + var rxf, ryf, n1, n2, n3 float64 + var r float64 + var ampl float64 = 0.5 + + for o := 0; o < perlinOctaves; o++ { + of := xi + (yi << perlinYwrapb) + (zi << perlinZwrapb) + + rxf = scaledCosin(xf) + ryf = scaledCosin(yf) + + n1 = p.perlin[of&perlinSize] + n1 += rxf * (p.perlin[(of+1)&perlinSize] - n1) + n2 = p.perlin[(of+perlinYwrap)&perlinSize] + n2 += rxf * (p.perlin[(of+perlinYwrap+1)&perlinSize] - n2) + n1 += ryf * (n2 - n1) + + of += perlinZwrap + n2 = p.perlin[of&perlinSize] + n2 += rxf * (p.perlin[(of+1)&perlinSize] - n2) + n3 = p.perlin[(of+perlinYwrap)&perlinSize] + n3 += rxf * (p.perlin[(of+perlinYwrap+1)&perlinSize] - n3) + n2 += ryf * (n3 - n2) + + n1 += scaledCosin(zf) * (n2 - n1) + + r += n1 * ampl + ampl *= perlinAmpFalloff + xi <<= 1 + xf *= 2 + yi <<= 1 + yf *= 2 + zi <<= 1 + zf *= 2 + + if xf >= 1.0 { + xi += 1 + xf -= 1 + } + if yf >= 1.0 { + yi += 1 + yf -= 1 + } + if zf >= 1.0 { + zi += 1 + zf -= 1 + } + } + return r +} + +func scaledCosin(x float64) float64 { + return 0.5 * (1.0 - math.Cos(x*math.Pi)) +} diff --git a/contourline.go b/contourline.go index 72a7e55..880df6f 100644 --- a/contourline.go +++ b/contourline.go @@ -11,7 +11,7 @@ type contourLine struct { lineNum int } -func NewContourLine(lineNum int) *contourLine{ +func NewContourLine(lineNum int) *contourLine { return &contourLine{ lineNum: lineNum, } @@ -22,24 +22,24 @@ func (cl *contourLine) Generative(c *canva) { ctex := gg.NewContextForRGBA(c.img) noise := perlin.NewPerlin(2, 2, 3, rand.Int63()) - for i:=0; i float64(c.width) || x < 0 || y > float64(c.height) || y < 0 || rand.Float64() < 0.001 { - x = rand.Float64()*float64(c.width) - y = rand.Float64()*float64(c.height) + x = rand.Float64() * float64(c.width) + y = rand.Float64() * float64(c.height) } } } diff --git a/example/example_contourline.go b/example/example_contourline.go index efd2a89..b472df7 100644 --- a/example/example_contourline.go +++ b/example/example_contourline.go @@ -10,11 +10,11 @@ import ( func main() { rand.Seed(time.Now().Unix()) colors := []color.RGBA{ - {0x58, 0x18, 0x45, 0xFF }, - {0x90, 0x0C, 0x3F, 0xFF }, - {0xC7, 0x00, 0x39, 0xFF }, - {0xFF, 0x57, 0x33, 0xFF }, - {0xFF, 0xC3, 0x0F, 0xFF }, + {0x58, 0x18, 0x45, 0xFF}, + {0x90, 0x0C, 0x3F, 0xFF}, + {0xC7, 0x00, 0x39, 0xFF}, + {0xFF, 0x57, 0x33, 0xFF}, + {0xFF, 0xC3, 0x0F, 0xFF}, } c := generativeart.NewCanva(800, 800) c.SetBackground(color.RGBA{0x1a, 0x06, 0x33, 0xFF})