Showcasing a completely procedurally generated island environment.
Island shaped by Perlin noise on a demisphere, textured with a grass texture algorithm and colored Perlin noise for the sand and rock textures. Water textured by Worley noise and a Voronoi diagram. Also showcases procedurally generated brick textures.
This project was made for an IGAD class on procedural content generation. It was made in a custom developed C++ rendering engine, supporting each of OpenGL, DirectX9 and DirectX11.
C++ code to generate a height field using Perlin noise and storing it in a float array.
#include <cmath>
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
//2D noise helper function
static float GetNoise2D(int a_X, int a_Y)
{
int n = a_X + a_Y * 57;
n = (n << 13) ^ n;
int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return 1.0f - ((float)nn / 1073741824.0f);
}
//Cosine interpolation helper function
static float GetCosineInterpolation(float a_A, float a_B,float a_X)
{
float ft = x * 3.1415927f;
float f = (1.0f - cosf(ft)) * 0.5f;
return a * (1.0f - f) + b * f;
}
//2D Perlin noise helper function
static float GetPerlin2D(float x,float y)
{
float floorx = (float)((int)x); //Floor the x and y values
float floory =( float)((int)y);
float s, t, u, v;
s = GetNoise2D(floorx, floory); //Get noise from the surrounding pixels of the current x/y values
t = GetNoise2D(floorx + 1, floory);
u = GetNoise2D(floorx, floory + 1);
v = GetNoise2D(floorx + 1, floory + 1);
float int1=GetCosineInterpolation(s, t, x - floorx); //Interpolate x between the bottom 2 pixels of the surrounding noise
float int2=GetCosineInterpolation(u, v, x - floorx); //Interpolate x between the top 2 pixels of the surrounding noise
return GetCosineInterpolation(int1, int2, y - floory); //Interpolate y between the previous two values to get the final result
}
Heightfield Heightfield::GenerateHeightPerlin(int a_Width, int a_Height, int a_Octaves, float a_Persistence, float a_Amplitude, float a_Zoom)
{
Heightfield _output;
float* _outputData = new float[a_Width*a_Height];
//Loop through all points of the height field
for(int y=0;y<a_Height;y++)
{
for(int x=0;x<a_Width;x++)
{
float getnoise =0;
//Loop through the number of octaves specified
for(int a=0;a<a_Octaves;a++)
{
float frequency = powf(2.0f,(float)(1+a)); //This increases the frequency of the Perlin noise with every loop of the octave.
float amplitude = powf(a_Persistence,(float)a) * a_Amplitude; //This decreases the amplitude of the Perlin noise with every loop of the octave.
//Calculate noise value using the perlin noise functions above, and applying zoom, amplitude and frequency.
getnoise += GetPerlin2D(((float)x)*frequency/a_Zoom,((float)y)/a_Zoom*frequency)*amplitude;
}
float h = MAX(0.0f, MIN(1.0f, ((getnoise + 1.0f) / 2.0f))); //Clamp noise between 0 and 1
_outputData[y*a_Width+x] = h;
}
}
_output.m_HeightData = _outputData;
_output.m_Height = a_Height;
_output.m_Width = a_Width;
return _output;
}