Skip to main content
made desire clearer for future visitors
Source Link

For reference, this is sort of how I want my planet to look like instead notice how there is not a lot of frequency. It's just some occasional hills and valleys

For reference, this is sort of how I want my planet to look like instead notice how there is not a lot of frequency. It's just some occasional hills and valleys

Source Link

How to scale down noise frequency?

I'm making a space game and so far what I have is a system to generate spheres with noise on them, making them planets. I make a sphere, create noise data, write that data to an image file, and then bind it to the sphere as a texture, and from there, I use that to make terrain. The problem I'm having is there are too many hills and valleys, and just looks like a spikeball instead of a planet sphere

sphere wireframe

Here's the function I use to generate the noise data

void write_noise_2d(int w, int h, int channels_num, const char* bmp_path)
{
        // create random seed for noise
        srand(time(NULL));
        float seed = (float)rand()/RAND_MAX;
        // initialize noise
        fnl_state noise = fnlCreateState();
        noise.noise_type = FNL_NOISE_OPENSIMPLEX2;
        noise.octaves = 6;
        noise.lacunarity = 2.0f;
        noise.gain = 0.5f;
        noise.frequency = 0.01f;
        noise.seed = (int)seed;
        printf("Seed: %i\n", seed);
        noise.fractal_type = FNL_FRACTAL_FBM;
        // 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++] = fnlGetNoise2D(&noise, x * 0.3f, y * 0.3f);
            }
        }

        stbi_write_bmp(bmp_path, w, h, channels_num, noise_data);
        free(noise_data);
}

Here's the function where I bind the noise to the sphere

unsigned int load_noise_2d(const char* path, unsigned int shader_program, const char* sampler, 
bool remove_noise)
{
    unsigned int noise;
    glGenTextures(1, &noise);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, noise);
    // from what I heard no need to specify gl_repeat because that is the default
    // filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_MIPMAP);

    // image stats
    int width, height, num_channels;
    // load image
    unsigned char* noise_data = stbi_load(path, &width, &height, &num_channels, 0);
    if(noise_data)
    {
        // image options
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_SHORT, noise_data);
        glGenerateMipmap(GL_TEXTURE_2D);

        // send to the GPU for processing
        set_int(shader_program, sampler, 0);
        printf("Loaded noise map of %i by %i\n", width, height);
    }
    else
    {
        printf("Failed to load noisemap\n");
    }
    // deallocate data that's no longer needed
    stbi_image_free(noise_data);
    if(remove_noise == true)
    {
        remove(path);
        printf("Deleted noise file\n");
    }
    else
    {
        printf("Kept noise file\n");
        return 0;
    }

    return noise;
}

For reference, this is how the function calls look like

    // write noise data from FNL to texture
write_noise_2d(512, 512, 2, "textures/2dnoise.bmp");
// now we load the noise map back into the program to be used later
load_noise_2d("textures/2dnoise.bmp", earthlike, "noisemap", true);

And finally, here's the tessellation shader, where I had a problem before with the intensity being too high, but that's solved

#version 450 core

// determines what type of tessellation to do
layout(triangles, equal_spacing, cw) in;

// input from control shader
in vec3 vertex_coord[];
// output vec
out vec3 vert;
// simplex noise goes here
uniform sampler2D noisemap;
// allows for object transformations
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

out float height;

void main()
{
    // gets barycentric coordinates from the triangles
    vec3 x = gl_TessCoord.x * vertex_coord[0];
    vec3 y = gl_TessCoord.y * vertex_coord[1];
    vec3 z = gl_TessCoord.z * vertex_coord[2];
    vec3 v = x + y + z;
    // scale noise between an acceptable value
    float min_noise_value = 0.5f;
    float max_noise_value = 2.5f;
    float intensity_scale = 0.015f;
    float noise_range = max_noise_value - min_noise_value;
    // use texture for offsetting sphere vertices
    float noise = texture(noisemap, vec2(v)).r;
    // sphere offsetting multiplier
    height = min_noise_value + noise_range * noise * intensity_scale;
    // makes every triangle an equal distance from the center through normalization (that's how spheres are formed)
    vec3 pos = normalize(x + y + z);
    // apply noise
    pos *= height;
    // output tessellated shape
    gl_Position = projection * view * model * vec4(pos, 1.0);
}