Question

I'm using libnoise to generate 2D sprite forrests. enter image description here

Then I made my world larger, I am currently working within world 1.0 to -1.0. The problem now is that I can no longer generate the few pixels the trees are offset by (from their grid positions). So they are not all in rows. I used to take the noise value and when I placed a tree I would then multiply the noise value with an int to make it larger and modulus it to get a random deviation that was the same every-time in that point in the world.

// offset each forest decal by a small amount for asthetic purposes
surface_xy.x = surface_x + float(FOREST::HALF_UNIT - int(perlin_noise_value * 100.0) % FOREST::UNIT);
surface_xy.y = surface_y + float(FOREST::HALF_UNIT - int(perlin_noise_value * 200.0) % FOREST::UNIT);

Now that my world is larger my formula which must work anywhere in the world doesn't work because the noise value is very very small. How do I get a consistent random value in pixels between say for example -5 and 5 from 1.1055228575200001e-012? Or perhaps someone knows of an alternative to using the noise value.

Was it helpful?

Solution

How do I get a consistent random value in pixels between say for example -5 and 5 from 1.1055228575200001e-012?

You could look at the internal representation of the double and combine the bits into an int:

int from_noise(double noise)
{
    unsigned long long bits;
    memcpy(&bits, &noise, 8);
    unsigned x = bits ^ (bits >> 32);
    return x % 11 - 5;
}

Note: from_noise assumes that double and long long take 8 bytes, and int takes 4 bytes. Also, the function will return different results on big-endian and little-endian architectures.

OTHER TIPS

Ideally, you could do something like:

#define RANGE_MIN     (-5)
#define RANGE_MAX     (+5)
#define RESOLUTION    (1.1055228575200001e-012)
#define NUM_OF_VALUES ((int)((RANGE_MAX-RANGE_MIN)/RESOLUTION))

double GetRandVal()
{
    return rand()%NUM_OF_VALUES*RESOLUTION+RANGE_MIN;
}

Unfortunately, the maximum return-value of rand() is typically 32767, while the specified range and resolution in your example yield 9045493661191 values. So you will have to use rand() several times:

#define RANGE_MIN     (-5)
#define RANGE_MAX     (+5)
#define RESOLUTION    (1.1055228575200001e-012)
#define NUM_OF_VALUES ((unsigned long long)((RANGE_MAX-RANGE_MIN)/RESOLUTION))

int GetNumOfBits(unsigned long long val)
{
    int numOfBits = 0;
    while (val > 0)
    {
        numOfBits++;
        val >>= 1;
    }
    return numOfBits;
}

static int numOfBitsInRandMax = GetNumOfBits(RAND_MAX);
static int numOfBitsInNumVals = GetNumOfBits(NUM_OF_VALUES);
static int quotient  = numOfBitsInNumVals/numOfBitsInRandMax;
static int remainder = numOfBitsInNumVals%numOfBitsInRandMax;

double GetRandVal()
{
    unsigned long long randVal = 0;
    for (int i=0; i<quotient; i++)
        randVal = (randVal<<numOfBitsInRandMax)|rand();
    randVal = (randVal<<remainder)|(rand()&((1<<remainder)-1));
    return randVal%NUM_OF_VALUES*RESOLUTION+RANGE_MIN;
}

Please note however, that on the theoretical aspect, it reduces the level of true randomness.

And BTW, don't forget to seed the RNG using srand((unsigned int)time(NULL))...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top