vendredi 24 juin 2022

Repeating patterns in OpenSimplex noise?

I'm trying to generate a random field of stars using OpenSimplex noise, but I'm noticing repeating patterns appearing and now that I've noticed it, I can't stop noticing it. I think I've found a workaround but I still like to know why this is happening.

At the moment my code generates a 2D greyscale image using OpenSimplex noise, then sets every pixel below a threshold value to 0, so only a small, supposedly random set of "stars" are left. I'll post the code below but this is what I'm seeing (I can't embed images yet so please check the links):

My code as it stands is using this package for the noise implementation: https://github.com/ojrac/opensimplex-go

package main

import (
    "flag"
    "fmt"
    "image"
    "image/color"
    "image/png"
    "math/rand"
    "os"
    "time"

    "github.com/ojrac/opensimplex-go"
)

const (
    startupMessage = "starfieldtest"
)

var (
    flgSize          int
    flgSeed          int64
    flgCullThreshold float64
)

func init() {
    rand.Seed(time.Now().UnixNano())
    seed := rand.Int63()

    flag.IntVar(&flgSize, "size", 2048, "size of the starfield")
    flag.Int64Var(&flgSeed, "seed", seed, "random noise seed value")
    flag.Float64Var(&flgCullThreshold, "cull", 0.998, "normalised threshold to cull values below")
}

func main() {
    fmt.Println(startupMessage)
    flag.Parse()

    img := generate(flgSize, flgSeed, float32(flgCullThreshold))

    outName := fmt.Sprintf("generated_%s.png", time.Now().Format("20060102150405"))
    pngFile, err := os.OpenFile(outName, os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        panic(err)
    }
    defer pngFile.Close()

    if err = png.Encode(pngFile, img); err != nil {
        panic(err)
    }

    fmt.Printf("Done!\n")
}

func generate(size int, seed int64, threshold float32) *image.Gray {

    noise := opensimplex.NewNormalized32(seed)

    pix := image.NewGray(image.Rect(0, 0, size, size))
    for y := 0; y < size; y++ {
        for x := 0; x < size; x++ {
            v := noise.Eval2(float32(x), float32(y))

            if v < threshold {
                v = 0
            }

            pix.SetGray(x, y, color.Gray{Y: uint8(v * 255.0)})
        }
    }

    return pix
}

I think I can get around it by using the Eval3 function and changing depth after a certain number of pixels, but is this expected behaviour because it's only really pseudo-random, or is OpenSimplex noise not supposed to do this? I can't really find any statement by anyone knowledgeable one way or the other as to whether this is just a limitation of pseudo-random noise or a problem with the implementation.




Aucun commentaire:

Enregistrer un commentaire