feat: add terrain generation using perlin noise #12

Merged
s452622 merged 11 commits from terrain-generation-second-approach into master 2022-01-25 12:18:30 +01:00
10 changed files with 216 additions and 22 deletions
Showing only changes of commit e7a5d0aa2b - Show all commits

View File

@ -1,16 +0,0 @@
#pragma once
#include "glew.h"
#include "freeglut.h"
#include <string>
#include <iostream>
namespace Core
{
GLuint LoadTexture(const char* filepath);
// textureID - identyfikator tekstury otrzymany z funkcji LoadTexture
// shaderVariableName - nazwa zmiennej typu 'sampler2D' w shaderze, z ktora ma zostac powiazana tekstura
// programID - identyfikator aktualnego programu karty graficznej
// textureUnit - indeks jednostki teksturujacej - liczba od 0 do 7. Jezeli uzywa sie wielu tekstur w jednym shaderze, to kazda z nich nalezy powiazac z inna jednostka.
void SetActiveTexture(GLuint textureID, const char* shaderVariableName, GLuint programID, int textureUnit);

View File

@ -142,6 +142,8 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="src\RawModel.cpp" />
<ClCompile Include="src\HeightGenerator.cpp" />
<ClCompile Include="src\Camera.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\Render_Utils.cpp" />
@ -151,8 +153,11 @@
<ClCompile Include="src\SOIL\SOIL.c" />
<ClCompile Include="src\SOIL\stb_image_aug.c" />
<ClCompile Include="src\Texture.cpp" />
<ClCompile Include="src\Terrain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\RawModel.h" />
<ClInclude Include="src\HeightGenerator.h" />
<ClInclude Include="src\Camera.h" />
<ClInclude Include="src\objload.h" />
<ClInclude Include="src\Render_Utils.h" />
@ -164,7 +169,7 @@
<ClInclude Include="src\SOIL\stbi_DDS_aug_c.h" />
<ClInclude Include="src\SOIL\stb_image_aug.h" />
<ClInclude Include="src\Texture.h" />
<ClInclude Include="Textures.h" />
<ClInclude Include="src\Terrain.h" />
</ItemGroup>
<ItemGroup>
<None Include="assimp-vc141-mt.dll" />

View File

@ -42,6 +42,15 @@
<ClCompile Include="src\Render_Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\HeightGenerator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Terrain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\RawModel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Shader_Loader.h">
@ -77,7 +86,13 @@
<ClInclude Include="src\objload.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Textures.h">
<ClInclude Include="src\HeightGenerator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Terrain.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\RawModel.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>

View File

@ -0,0 +1,61 @@
#include "HeightGenerator.h"
#include <random>
#include <iostream>
#include <math.h>
# define MY_PI 3.14159265358979323846
std::random_device rd; // obtain a random number from hardware
const int HeightGenerator::SEED = rd();
const float HeightGenerator::AMPLITUDE = 75.f;
const int HeightGenerator::OCTAVES = 3;
const float HeightGenerator::ROUGHNESS = 0.3f;
const int HeightGenerator::xOffset = 0;
const int HeightGenerator::zOffset = 0;
float HeightGenerator::generateHeight(int x, int z) {
float total = 0;
float d = pow(2, OCTAVES - 1);
for (int i = 0; i < OCTAVES; i++) {
float freq = pow(2, i) / d;
float amp = pow(ROUGHNESS, i) * AMPLITUDE;
total += getInterpolatedNoise((x + xOffset) * freq, (z + zOffset) * freq) * amp;
}
return total;
}
float HeightGenerator::getInterpolatedNoise(float x, float z) {
int intX = int(x);
int intZ = int(z);
float fracX = x - intX;
float fracZ = z - intZ;
float v1 = getSmoothNoise(intX, intZ);
float v2 = getSmoothNoise(intX + 1, intZ);
float v3 = getSmoothNoise(intX, intZ + 1);
float v4 = getSmoothNoise(intX + 1, intZ + 1);
float i1 = interpolate(v1, v2, fracX);
float i2 = interpolate(v3, v4, fracX);
return interpolate(i1, i2, fracZ);
}
float HeightGenerator::interpolate(float a, float b, float blend) {
double theta = blend * MY_PI;
float f = float(1.f - cos(theta)) * 0.5f;
return a * (1.f - f) + b * f;
}
float HeightGenerator::getSmoothNoise(int x, int z) {
float corners = (getNoise(x - 1, z - 1) + getNoise(x + 1, z - 1) + getNoise(x - 1, z + 1) + getNoise(x + 1, z + 1)) / 16.f;
float sides = (getNoise(x - 1, z) + getNoise(x + 1, z) + getNoise(x, z - 1) + getNoise(x, z + 1)) / 8.f;
float center = getNoise(x, z) / 4.f;
return corners + sides + center;
}
float HeightGenerator::getNoise(int x, int z) {
std::mt19937 gen(SEED + x * 49632 + z * 325176);
std::uniform_real_distribution<> distr(0, 100000000);
return distr(gen) * 2.f - 1.f;
}

View File

@ -0,0 +1,18 @@
#pragma once
class HeightGenerator
{
public:
float generateHeight(int x, int z);
static const int SEED;
private:
static const float AMPLITUDE;
static const int OCTAVES;
static const float ROUGHNESS;
static const int xOffset;
static const int zOffset;
float getInterpolatedNoise(float x, float z);
float getSmoothNoise(int x, int z);
float interpolate(float a, float b, float blend);
float getNoise(int x, int z);
};

View File

@ -0,0 +1,6 @@
#include "RawModel.h"
RawModel::RawModel(int vaoID, int vertexCount) {
this->vaoID = vaoID;
this->vertexCount = vertexCount;
}

View File

@ -0,0 +1,11 @@
#pragma once
class RawModel
{
public:
RawModel() = default;
RawModel(int vaoID, int vertexCount);
private:
int vaoID;
int vertexCount;
};

View File

@ -0,0 +1,73 @@
#include "Terrain.h"
#include "glew.h"
#include "freeglut.h"
const float Terrain::SIZE = 800.f;
const int Terrain::VERTEX_COUNT = 128;
const int Terrain::COUNT = Terrain::VERTEX_COUNT * Terrain::VERTEX_COUNT;
Terrain::Terrain(int gridX, int gridZ, GLuint textureID) {
x = gridX * SIZE;
z = gridZ * SIZE;
texture = textureID;
model = generateTerrain();
}
RawModel Terrain::generateTerrain() {
float vertices[COUNT * 3];
float normals[COUNT * 3];
float textureCoords[COUNT * 2];
int indices[6 * (VERTEX_COUNT - 1) * (VERTEX_COUNT - 1)];
int vertexPointer = 0;
for (int i = 0; i < VERTEX_COUNT; i++) {
for (int j = 0; j < VERTEX_COUNT; j++) {
vertices[vertexPointer * 3] = float(j) / float(VERTEX_COUNT - 1) * SIZE;
vertices[vertexPointer * 3 + 1] = 0;
vertices[vertexPointer * 3 + 2] = float(i) / float(VERTEX_COUNT - 1) * SIZE;
normals[vertexPointer * 3] = 0;
normals[vertexPointer * 3 + 1] = 1;
normals[vertexPointer * 3 + 2] = 0;
textureCoords[vertexPointer * 2] = float(j) / float(VERTEX_COUNT - 1) * SIZE;
textureCoords[vertexPointer * 2 + 1] = float(i) / float(VERTEX_COUNT - 1) * SIZE;
vertexPointer++;
}
}
int pointer = 0;
for (int gz = 0; gz < VERTEX_COUNT; gz++) {
for (int gx = 0; gx < VERTEX_COUNT; gx++) {
int topLeft = gz * VERTEX_COUNT + gx;
int topRight = topLeft + 1;
int bottomLeft = (gz + 1) * VERTEX_COUNT + gx;
int bottomRight = bottomLeft + 1;
indices[pointer++] = topLeft;
indices[pointer++] = bottomLeft;
indices[pointer++] = topRight;
indices[pointer++] = topRight;
indices[pointer++] = bottomLeft;
indices[pointer++] = bottomRight;
}
}
unsigned int vaoID;
glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);
unsigned int vboID;
glGenBuffers(1, &vboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices, GL_STATIC_DRAW);
storeDataInAttributeList(0, 3, vertices);
storeDataInAttributeList(1, 2, textureCoords);
storeDataInAttributeList(2, 3, normals);
glBindVertexArray(0);
return RawModel(vaoID, sizeof indices / sizeof indices[0]);
}
void Terrain::storeDataInAttributeList(int attributeNumber, int coordinateSize, float data[]) {
unsigned int vboID;
glGenBuffers(1, &vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
glVertexAttribPointer(attributeNumber, coordinateSize, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "RawModel.h"
class Terrain
{
public:
Terrain() = default;
Terrain(int gridX, int gridZ, GLuint textureID);
private:
static const float SIZE;
static const int VERTEX_COUNT;
static const int COUNT;
float x;
float z;
GLuint texture;
RawModel model;
RawModel generateTerrain();
void storeDataInAttributeList(int attributeNumber, int coordinateSize, float data[]);
};

View File

@ -12,6 +12,8 @@
#include "Texture.h"
#include "Camera.h"
#include "SOIL/stb_image_aug.h"
#include "HeightGenerator.h"
#include "Terrain.h"
GLuint skyboxProgram, skyboxBuffer;
GLuint bubbleProgram;
@ -175,9 +177,7 @@ bool isInBoundaries(glm::vec3 nextPosition) {
nextPosition.y < skyboxBoundary&& nextPosition.x < skyboxBoundary&& nextPosition.x > -skyboxBoundary;
}
std::random_device rd; // obtain a random number from hardware
std::mt19937 gen(rd()); // seed the generator
std::default_random_engine gen(HeightGenerator::SEED); // seed the generator
std::uniform_int_distribution<> distr(-skyboxVerticeParameter, skyboxVerticeParameter); // define the range
std::vector<glm::vec3> genBubbleKeyPoints() {
@ -514,6 +514,9 @@ void init()
initCube();
initSkybox();
//GLuint textureID = Core::LoadTexture('textura_terrain');
//Terrain terrain = new Terrain(0, 0, textureID);
}
void shutdown()
@ -521,7 +524,6 @@ void shutdown()
shaderLoader.DeleteProgram(programTexture);
shaderLoader.DeleteProgram(skyboxProgram);
shaderLoader.DeleteProgram(bubbleProgram);
}
void idle()