1

I'm trying to create procedural textures, and for that, I'm generating noise, and then writing that data to an image file, to be displayed. So far I generated the noise, and now I'm trying to write that to an image file, to display the noise. I expect my image to look like this, but instead it is entirely black.

enter image description here

Here's my code where I'm writing to the image file

    void write_noise_2d(int w, int h, int channels_num)
    {
        // initialize noise
        fnl_state noise = fnlCreateState();
        noise.noise_type = FNL_NOISE_OPENSIMPLEX2;

        // create data array for noise
        uint8_t* noise_data = malloc(w * h * channels_num * sizeof(uint8_t));
        int index = 0;
        // create noise throughout the entire image
        for(int x=0; x<w; x++)
        {
            for(int y=0; y<h; y++)
            {
                noise_data[index++] = fnlGetNoise2D(&noise, x, y);
            }
        }

        stbi_write_jpg("textures/noisemap.jpg", w, h, channels_num, noise_data, w * channels_num);
        free(noise_data);
    }

    write_noise_2d(512, 512, 3);

I did diligent research on this topic and even found some example source code, that worked when I just copied and pasted it, but when I implemented the noise functions, it no longer worked. Instead of displaying the noise data like I expected it to (as shown in the example image provided). Instead, it's nothing more than just a black square.

EDIT: For reference, this is the main resource I was using for this. Copying and pasting this code actually displays the data on the file, while my implementation doesn't.

http://chanhaeng.blogspot.com/2018/12/how-to-use-stbimagewrite.html

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
Chillzy
  • 89
  • 8
  • 1
    is `channels_num > 1`? You use it to allocate space for `noise_data`, but don't use it to fill `noise_data` ... seems fishy. – yano May 09 '23 at 16:06
  • I wrote the code to where `channels_num` could equal anything, but for now, I chose for it to be equal to 3 – Chillzy May 09 '23 at 16:15
  • 1
    Rather than looking at a graphical representation of the data (eg, the big black square), it would be more useful to actually analyze the file and see what is there. – William Pursell May 09 '23 at 16:15
  • @WilliamPursell What do you mean by that? Because I'm using the noise data as a texture, not just to analyze it for the fun of it. – Chillzy May 09 '23 at 16:17
  • ok well, for any `channels_num > 1` at best you're allocating more space than you're using. I'm guessing you need to align the noise data per channel, which doesn't look like you're doing. Even then, all black seems odd, seems like at least a portion of it should be "noisy"... ? – yano May 09 '23 at 16:18
  • @Chillzy I mean, read the data in the file and see if it matches your expectation. The extra layer of rendering the image is potentially introducing unnecessary complexity. The noise may be there, but not be visible. – William Pursell May 09 '23 at 16:19
  • As a simple test, you could write a file without noise, then write the file with noise and check if they are different.(eg, `cmp`, or `md5sum`, or whatever). if they are different, write a quick program to analyze the statistics of the differences and see if that matches your expectation ) – William Pursell May 09 '23 at 16:22
  • By writing without noise, what data to I write then? Do I just open up a blank file and then look at the differences between that and the file with noise? – Chillzy May 09 '23 at 16:23
  • 1
    If `channels_num` is 3 you are only filling in a third of the `noise_data` array. Also, `fnlGetNoise2D` appears to return a `float` in the range -1 to 1, not a channel value in the range 0 to 255. Most of the `float` values in the range -1 to 1 will be truncated to 0 when converted to `uint8_t`. – Ian Abbott May 09 '23 at 16:42
  • 1
    Since the sample image is grayscale, you should write each noise value to `channels_num` consecutive bytes of `noise_data`, i.e. set all 3 channels of the pixel to the same value. – Ian Abbott May 09 '23 at 16:45
  • Try something like `noise_data[index++] = (1 + fnlGetNoise2D(&noise, x, y)) * 127.999;` `for (int c = 1; c < channels_num; c++)` `{` `noise_data[index++] = noise_data[index - 1];` `}`. – Ian Abbott May 09 '23 at 16:58
  • 1
    Doesn't `fnlGetNoise2D()` return a float? You're storing it in a `uint8_t`. – pmacfarlane May 09 '23 at 17:28
  • @IanAbbott Thanks! I took your sample code and the image now works! Appreciate the help. – Chillzy May 09 '23 at 17:44

1 Answers1

1

As per @Ian Abbott's suggestion, I took the sample code provided, and now the image displays proper noise as shown below

enter image description here

Looks a little bit wonky but I can change that with the noise options provided by FNL (fastnoise lite for those wondering)

For future viewers, this is the new proper code that actually worked.

    void write_noise_2d(int w, int h, int channels_num)
{
    // initialize noise
    fnl_state noise = fnlCreateState();
    noise.noise_type = FNL_NOISE_OPENSIMPLEX2;
    noise.octaves = 8;
    // create data array for noise
    float* noise_data = malloc(w * h * channels_num * sizeof(float));
    int index = 0;
    // create noise throughout the entire image
    for(int x=0; x<w; x++)
    {
        for(int y=0; y<h; y++)
        {
            noise_data[index++] = (1 + fnlGetNoise2D(&noise, x, y)) * 127.999;
        }
    }

    stbi_write_jpg("textures/noisemap.jpg", w, h, channels_num, noise_data, w * channels_num);
    free(noise_data);
}

write_noise_2d(512, 512, 1);
Chillzy
  • 89
  • 8