1

The Mathf.PerlinNoise(float x, float y) function returns a float that I use. I want a more completely random function that can use coordinates as it's seed.

My ideal would have the exact same input and output as the aforementioned Mathf.PerlinNoise function, . The point is that it can be switched out with the Perlin Noise function to return completely random floats that return the same float for any given coordinate each and every time.

Xevion
  • 570
  • 5
  • 17

1 Answers1

1

So your question consists of 2 problems:

  1. Create a seed from the 2 float values that always maps the same input to the same seed.

  2. Using a seed to generate a random float.

For the first problem this can be solved by creating a hashcode, there are different ways to do it but I'll refer to this answer by John Skeet for more information on that. For you the hashing would look like this:

public int GetHashCode(float x, float y)
{
    unchecked // Overflow is fine, just wrap
    {
        int hash = (int)2166136261;
        // Suitable nullity checks etc, of course :)
        hash = (hash * 16777619) ^ x.GetHashCode();
        hash = (hash * 16777619) ^ y.GetHashCode();
        return hash;
    }
}

So now problem 1 is solved we can move on to problem 2, here we have a problem since you require a float which the Random class doesn't support. If a double is good enough for you (floats from your PerlinNoise can be converted to double's), you could then do this:

public double GenerateRandom(float x, float y)
{
    return new Random(GetHashCode(x, y)).NextDouble();
}

If double is not good enough and you require it to be a float, I'll refer to this answer, all his solutions should work with a Random instance created using the hash function above as seed.

Hope this helps and good luck with your project!

  • How fast is this code? Seems like creating a `Random` instance would be somewhat expensive, especially if you're doing it hundreds of times per second like I'd be doing. – Xevion Jul 09 '20 at 10:08
  • @Xevion first of all one thing I didn't mention is that the `NextDouble` generates a value between 0 and 1, so keep in mind you either have to scale that to whatever range you require or if you want the full float range use the referenced answer to get that. –  Jul 09 '20 at 10:35
  • @Xevion as for the speed. First of all in computer science "hundreds of times per second" is not a lot. There certainly is a constant cost to creating these `Random` instances, which you might be able to avoid by using a hash to generate a random `float` but that probably won't be that much more efficient. Good randomness is quite complex sadly. I've run a benchmark and on my pc it takes ~2ms to use the `GenerateRandom` to generate a random `double` for 1000 points. So I should be able to do 500000 generations/second –  Jul 09 '20 at 10:47
  • Yeah, I'm going to be doing it a hell of a lot more than 100 times per second. And looking at that 2ms timing, that's really slow for just 1000 points. Was hoping for something like 1024^2 points at max 5ms (I know I'm dreaming but). – Xevion Jul 09 '20 at 11:53
  • @Xevion yes with those amounts you'll need to do other optimizations (parallel processing) but I don't think you're going to gain a lot by doing this another way. Either you have to use a different way of hashing to ensure the hash is uniformly random and then find a way to generate the random float directly from that hash, but my assumption is that this will not make a huge difference in calculation time (hashing is pretty expensive as well). Anyway you're question contains very limited information so it's impossible to say more. –  Jul 09 '20 at 13:30