Wout van Poppel Game Tools & Gameplay Programmer

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.

Sample code

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

Details

  • Date: 2014-2015
  • System: PC
  • Engine: Own engine
  • Language(s): C++
  • Dev time: 7 weeks
  • Solo project

Images