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
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);
}