verpeteren / rust-simd-noise

SIMD noise library for Rust
https://crates.io/crates/simdnoise
252 stars 20 forks source link

with_seed() does not give enough randomness. #42

Open martinlindhe opened 2 years ago

martinlindhe commented 2 years ago

Consider the following code.

No matter the amount of random seeds, it only generates 8 unique outputs.

// main.rs
use simdnoise::NoiseBuilder;
use sha1::{Sha1, Digest};
use rand::Rng;
use hex::ToHex;
use std::collections::HashMap;

fn main() {

    let width = 100;
    let height = 100;
    let mut ground = vec!(0; width * height);

    let mut subjcts = HashMap::new();

    for i in 0..10000 {

        let mut rng = rand::thread_rng();
        let seed: u32 = rng.gen();

        let noise = NoiseBuilder::fbm_2d(width, height)
            .with_seed(seed as i32)
            .generate_scaled(0., 255.);

        for i in 0..width * height {
            ground[i] = noise[i] as u8;
        }

        let mut hasher = Sha1::new();
        hasher.update(&ground);
        let result = hasher.finalize();
        let hash_s = result.encode_hex::<String>();

        *subjcts.entry(hash_s).or_insert(1) += 1;
    }

    // list results
    for (key, val) in subjcts.iter() {
        println!("key_is: {} val_is: {}", key, val);
    }
}
// Cargo.toml
[package]
name = "simdnoise_seed"
version = "0.1.0"
edition = "2021"

[dependencies]
simdnoise = "3.1.6"
sha1 = "0.10"
hex = "0.4"
rand = "0.8"

output:

key_is: 32b00bf03c164bfa480e4a373a3d4f0e35dcda0e val_is: 1285
key_is: ed23a933cb23296682262fb2a88d227e69e8125d val_is: 1238
key_is: 05da58ef01dbed6fea816c02ca26cdb0930370ab val_is: 1214
key_is: 5cc514182aed4af4aa8406df2ce8639285b3b81e val_is: 1269
key_is: 61e8492dc6f75223d8459674a0dce7b679cc3cd3 val_is: 1275
key_is: 1f85d6aec7b530746c838c357f8adeaa4daf9816 val_is: 1220
key_is: 5811b7b15cd5c36b2efafd6f0d77863d60b98e54 val_is: 1212
key_is: 8628b18331c4e637c5ecb1224ba6abca78ab450e val_is: 1295
martinlindhe commented 2 years ago

Maybe related to #33 ?

lukabavdaz commented 1 year ago

This indeed seems to be the same issue. Any success in tackling it?

martinlindhe commented 1 year ago

I just worked around it by tweaking frequency and some other parameters. Something like

let noise = NoiseBuilder::fbm_2d(width, height)
    .with_seed(seed as i32)
    .with_freq(0.07 + scale(seed as f32, 0., u32::MAX as f32, 0., 0.2)) 
    .generate_scaled(0., 255.);

fn scale(value_in: f32, base_min: f32, base_max: f32, limit_min: f32, limit_max: f32) -> f32 {
    ((limit_max - limit_min) * (value_in - base_min) / (base_max - base_min)) + limit_min
}

It does not fix the issue, but hides it a little.

lukabavdaz commented 1 year ago

That's an interesting workaround but not an ideal solution. @verpeteren any idea where the issue could lie? Not being able to properly seed the noise seems like a fairly serious issue.

verpeteren commented 1 year ago

I think that the clue lies in this comment. I need to dig deeper to understand what that means.

I created this branch for investigation