0

I am attempting to create a Worley Noise function. I looked around and read the original paper by Steven Worley and wrote my implementation. The output does not appear to be correct though. I expect to see something like this.

enter image description here

But it outputs this.

enter image description here

I'm not sure what I am doing wrong. I have looked online at other peoples programs and I do it the same way. Here is the code.

float WorleyNoise::noise( Vector3 input ) {
    unsigned int lastRandom;
    unsigned int numberFeaturePoints;

    Vector3 randomDiff;
    Vector3 featurePoint;

    int cubeX;
    int cubeY;
    int cubeZ;

    float distanceArray[ 3 ];
    for ( int i = 0; i < 3; i++ ) {
        distanceArray[ i ] = 6666.0f;
    }

    int evalX = ( int ) floorf( input.m_x );
    int evalY = ( int ) floorf( input.m_y );
    int evalZ = ( int ) floorf( input.m_z );

    for ( int i = -1; i < 2; ++i ) {
        for ( int j = -1; j < 2; ++j ) {
            for ( int k = -1; k < 2; ++k ) {
                cubeX = evalX + i;
                cubeY = evalY + j;
                cubeZ = evalZ + k;

                lastRandom = lcg_random( hash( ( unsigned int ) ( cubeX + m_seed ), ( unsigned int ) cubeY, ( unsigned int ) cubeZ ) );
                numberFeaturePoints = lookup( lastRandom );

                for ( unsigned int l = 0; l < numberFeaturePoints; ++l ) {
                    lastRandom = lcg_random( lastRandom );
                    randomDiff.m_x = ( float ) lastRandom / 0x100000000;

                    lastRandom = lcg_random( lastRandom );
                    randomDiff.m_y = ( float ) lastRandom / 0x100000000;

                    lastRandom = lcg_random( lastRandom );
                    randomDiff.m_z = ( float ) lastRandom / 0x100000000;

                    featurePoint.m_x = randomDiff.m_x + ( float ) cubeX;
                    featurePoint.m_y = randomDiff.m_y + ( float ) cubeY;
                    featurePoint.m_z = randomDiff.m_z + ( float ) cubeZ;

                    insert( distanceArray, euclidian_distance( input, featurePoint ) );
                }
            }
        }
    }

    return Utility::clampf( combine_function_1( distanceArray ), 0.0f, 1.0f );
}

unsigned int WorleyNoise::hash( unsigned int i, unsigned int j, unsigned int k ) {
    return ( unsigned int ) ( ( ( ( ( ( OFFSET_BASIS ^ ( unsigned int ) i ) * FNV_PRIME ) ^ ( unsigned int ) j ) * FNV_PRIME ) ^ ( unsigned int ) k ) * FNV_PRIME );
}

unsigned int WorleyNoise::lcg_random( unsigned int last ) {
    return ( unsigned int ) ( ( 1103515245 * last + 12345 ) % 0x100000000 );
}

 void WorleyNoise::insert( float arr[] , float value ) {
    float temp = 0.0f;

    for ( int i = 2; i >= 0; i-- ) {
        if ( value > arr[ i ] ) {
            break;
        }

        temp = arr[ i ];
        arr[ i ] = value;
        if ( i + 1 < 3 ) {
            arr[ i + 1 ] = temp;
        }
    }
}

 unsigned int WorleyNoise::lookup( unsigned int value ) {
    value = value & 0xffffffff;
    if ( value < 393325350 )
        return 1;
    if ( value < 1022645910 )
        return 2;
    if ( value < 1861739990 )
        return 3;
    if ( value < 2700834071 )
         return 4;
    if ( value < 3372109335 )
         return 5;
    if ( value < 3819626178 )
         return 6;
    if ( value < 4075350088 )
        return 7;
    if ( value < 4203212043 )
        return 8;
    return 9;
}

float WorleyNoise::euclidian_distance( Vector3 p1, Vector3 p2 ) {
    return ( p1.m_x - p2.m_x ) * ( p1.m_x - p2.m_x ) + ( p1.m_y - p2.m_y ) * ( p1.m_y - p2.m_y ) + ( p1.m_z - p2.m_z ) *  ( p1.m_z - p2.m_z );
}

float WorleyNoise::combine_function_1( float arr[] ) {
    return arr[ 0 ];
}

I then output the results like so with pngwriter.

void WorleyNoise::to_png( const std::string &file, unsigned int width, unsigned int height ) {
    pngwriter png( width, height, 0, file.c_str() );

    for ( unsigned int i = 0; i < width; i++ ) {
        for ( unsigned int j = 0; j < height; j++ ) {
            float value = noise( Vector3( i, j, 0 ) );

            png.plot( i, j, ( double ) value, ( double ) value, ( double ) value );
        }
    }

    png.close();
}

So what is going wrong here? I've looked all over, especially at this tutorial and cannot figure out why it does not output correctly. Any help is greatly appreciated, thanks.

CMilby
  • 624
  • 1
  • 6
  • 23
  • Aren't the feature points supposed to be generated once per "image"? I think you are generating the feature points for each point, you need to generate the feature points once (constructor of `WorleyNoise` for example) and then use those points for determining the color of every point in image. If you need another image, then you need to re-generate the feature points. – triple_r Nov 25 '15 at 17:58
  • I'm honestly not sure now. When I insert the point should I save them to a list then cycle through them and call the distance function for their surrounding points? – CMilby Nov 25 '15 at 18:32
  • I think so. If the feature points remain the same for the whole image, then you would get those nice Voronoi-diagram-like shapes, instead of the random points. You don't need to cycle through all the points though, that is what your program does, cycles through only the points that are in the same cell as the point that you are looking at or the 8 neighboring cells. – triple_r Nov 25 '15 at 20:12
  • Looking at your code more carefully, I think your random number generator is repeatable (has a constant seed), so it is supposed to generate the same feature points every time for every cell (the seed is based on cell coordinate). So, I don't know exactly what is wrong that the feature points don't stay the same. I'll look a bit more though to see if I can find anything. – triple_r Nov 25 '15 at 20:15
  • Have you tried scaling the image? So, the three lines that you calculate cube location `int evalX = ( int ) floorf( input.m_x );`, what happens if you change those to `int evalX = ( int ) floorf( input.m_x / scale);` where `scale` is a number larger than 1, let's say `10.0` or `100.0`. – triple_r Nov 25 '15 at 20:29
  • Changing the scale will just cause the image to be all white. There is no noise at all. – CMilby Nov 25 '15 at 21:23
  • `pngwriter` is expecting values in [0,1] range for the color. I think you'll need to scale your coordinates down as @triple_r said and then scale your distance result down to get something more in the proper range. – Khouri Giordano Nov 25 '15 at 21:42
  • I ran a test to see the distribution of values. On a 200x200 pixel picture only about 10 values were not 0 or 1 exactly. – CMilby Nov 25 '15 at 22:36

0 Answers0