[Add] Added detailmap for more detailed terrain.
This commit is contained in:
parent
6186952313
commit
8c701d39b7
@ -3,21 +3,48 @@ out vec4 FragColor;
|
||||
|
||||
in vec3 FragPos;
|
||||
in vec3 Normal;
|
||||
in vec3 WorldPos;
|
||||
in float Detail;
|
||||
|
||||
uniform vec3 objectColor;
|
||||
uniform vec3 lightColor;
|
||||
uniform vec3 lightDir; /* Normalised direction vector for the light source. */
|
||||
uniform bool u_IsTerrain;
|
||||
|
||||
void main() {
|
||||
/* Ambient lighting (cheap, constant base light) */
|
||||
float ambientStrength = 0.3;
|
||||
vec3 finalColor;
|
||||
vec3 norm = normalize(Normal);
|
||||
|
||||
/* Define colours for different terrain types. */
|
||||
if(u_IsTerrain) {
|
||||
vec3 grassColor1 = vec3(0.4, 0.6, 0.2);
|
||||
vec3 grassColor2 = vec3(0.3, 0.5, 0.15);
|
||||
vec3 rockColor = vec3(0.5, 0.5, 0.4);
|
||||
vec3 steepColor = vec3(0.35, 0.3, 0.25);
|
||||
|
||||
/* Create patchy grass colur using the detail noise. */
|
||||
float detailFactor = smoothstep(-0.2, 0.2, Detail);
|
||||
vec3 finalGrassColor = mix(grassColor1, grassColor2, detailFactor);
|
||||
|
||||
/* Blend from grass to rock between height of 2.0 and 4.0. */
|
||||
float heightFactor = smoothstep(2.0, 4.0, WorldPos.y);
|
||||
finalColor = mix(finalGrassColor, rockColor, heightFactor);
|
||||
|
||||
/* Flat surface has a normal.y of 1.0. A steep slope is closer to 0. */
|
||||
float slopeFactor = 1.0 - smoothstep(0.6, 0.8, norm.y);
|
||||
finalColor = mix(finalColor, steepColor, slopeFactor);
|
||||
|
||||
} else {
|
||||
finalColor = objectColor;
|
||||
}
|
||||
|
||||
/* Standard lighting calculations. */
|
||||
float ambientStrength = 0.4;
|
||||
vec3 ambient = ambientStrength * lightColor;
|
||||
|
||||
/* Diffuse lighting (depends on angle of the surface) */
|
||||
vec3 norm = normalize(Normal);
|
||||
float diff = max(dot(norm, normalize(-lightDir)), 0.0);
|
||||
vec3 diffuse = diff * lightColor;
|
||||
|
||||
vec3 result = (ambient + diffuse) * objectColor;
|
||||
vec3 result = (ambient + diffuse) * finalColor;
|
||||
FragColor = vec4(result, 1.0);
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
layout (location = 2) in float aDetail;
|
||||
|
||||
out vec3 FragPos;
|
||||
out vec3 Normal;
|
||||
out vec3 WorldPos;
|
||||
out float Detail;
|
||||
|
||||
uniform mat4 model;
|
||||
uniform mat4 view;
|
||||
@ -12,7 +15,9 @@ uniform mat4 projection;
|
||||
void main() {
|
||||
/* Pass position and normal vectors to the fragment shader in world space. */
|
||||
FragPos = vec3(model * vec4(aPos, 1.0));
|
||||
WorldPos = FragPos;
|
||||
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||
Detail = aDetail;
|
||||
|
||||
gl_Position = projection * view * vec4(FragPos, 1.0);
|
||||
}
|
||||
|
||||
@ -14,8 +14,10 @@ const int CHUNK_DATA_HEIGHT = CHUNK_HEIGHT + CHUNK_BORDER_SIZE * 2;
|
||||
|
||||
struct Chunk {
|
||||
std::vector<float> heightmap;
|
||||
std::vector<float> detailmap;
|
||||
|
||||
Chunk(void) : heightmap(CHUNK_DATA_WIDTH * CHUNK_DATA_HEIGHT) {}
|
||||
Chunk(void) : heightmap(CHUNK_DATA_WIDTH * CHUNK_DATA_HEIGHT),
|
||||
detailmap(CHUNK_DATA_WIDTH * CHUNK_DATA_HEIGHT) {}
|
||||
};
|
||||
|
||||
} /* namespace Game. */
|
||||
|
||||
@ -8,6 +8,7 @@ struct ChunkMessage {
|
||||
int chunk_x;
|
||||
int chunk_z;
|
||||
float heightmap[Game::CHUNK_DATA_WIDTH*Game::CHUNK_DATA_HEIGHT];
|
||||
float detailmap[Game::CHUNK_DATA_WIDTH*Game::CHUNK_DATA_HEIGHT];
|
||||
};
|
||||
|
||||
} /* namespace Network. */
|
||||
|
||||
@ -10,7 +10,7 @@ World::~World(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void World::add_chunk(int chunk_x, int chunk_z, const float* heightmap) {
|
||||
void World::add_chunk(int chunk_x, int chunk_z, const float* heightmap, const float* detailmap) {
|
||||
ChunkPos pos = {chunk_x, chunk_z};
|
||||
if(_chunk_meshes.count(pos)) {
|
||||
/* TODO: Chunk already exists, perhaps update it later.. */
|
||||
@ -19,6 +19,7 @@ void World::add_chunk(int chunk_x, int chunk_z, const float* heightmap) {
|
||||
|
||||
BettolaLib::Game::Chunk chunk;
|
||||
memcpy(chunk.heightmap.data(), heightmap, chunk.heightmap.size()*sizeof(float));
|
||||
memcpy(chunk.detailmap.data(), heightmap, chunk.detailmap.size()*sizeof(float));
|
||||
|
||||
_chunks[pos] = chunk;
|
||||
_chunk_meshes[pos] = new ChunkMesh(chunk_x, chunk_z, chunk);
|
||||
|
||||
@ -20,7 +20,7 @@ public:
|
||||
~World(void);
|
||||
|
||||
float get_height(float world_x, float world_z) const;
|
||||
void add_chunk(int chunk_x, int chunk_z, const float* heightmap);
|
||||
void add_chunk(int chunk_x, int chunk_z, const float* heightmap, const float* detailmap);
|
||||
const std::map<ChunkPos, ChunkMesh*>& get_chunk_meshes(void) const {
|
||||
return _chunk_meshes;
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ void GameClient::process_network_messages(void) {
|
||||
if(header.size == sizeof(BettolaLib::Network::ChunkMessage)) {
|
||||
BettolaLib::Network::ChunkMessage msg;
|
||||
_tcp_socket.recv(&msg, sizeof(msg));
|
||||
_world.add_chunk(msg.chunk_x, msg.chunk_z, msg.heightmap);
|
||||
_world.add_chunk(msg.chunk_x, msg.chunk_z, msg.heightmap, msg.detailmap);
|
||||
}
|
||||
} else {
|
||||
/* Discard message payloads we don't understand to prevent de-sync. */
|
||||
|
||||
@ -24,6 +24,10 @@ ChunkMesh::ChunkMesh(int chunk_x, int chunk_z, const BettolaLib::Game::Chunk& ch
|
||||
_vertices.push_back(normal.x);
|
||||
_vertices.push_back(normal.y);
|
||||
_vertices.push_back(normal.z);
|
||||
|
||||
/* Pack the detail noise into the 4th component of the vertex data. */
|
||||
float detail_noise = chunk.detailmap[data_z*BettolaLib::Game::CHUNK_DATA_WIDTH+data_x];
|
||||
_vertices.push_back(detail_noise);
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,13 +99,17 @@ void ChunkMesh::_setup_mesh(void) {
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size()*sizeof(unsigned int), _indices.data(), GL_STATIC_DRAW);
|
||||
|
||||
/* Position attrib. */
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
/* Normal attrib. */
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(3*sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
/* Detail noise attrib. */
|
||||
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 7*sizeof(float), (void*)(6*sizeof(float)));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
@ -53,47 +53,48 @@ bool Renderer::init(int screen_width, int screen_height) {
|
||||
|
||||
// Definitive, correct 3D cube vertices
|
||||
float vertices[] = {
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, -0.5f,
|
||||
0.5f, 0.5f, -0.5f,
|
||||
0.5f, 0.5f, -0.5f,
|
||||
-0.5f, 0.5f, -0.5f,
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
/* Positions. */ /* Normals. */
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
||||
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
||||
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
||||
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
||||
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
|
||||
|
||||
-0.5f, -0.5f, 0.5f,
|
||||
0.5f, -0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, 0.5f,
|
||||
-0.5f, -0.5f, 0.5f,
|
||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||
|
||||
-0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, -0.5f,
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
-0.5f, -0.5f, 0.5f,
|
||||
-0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
|
||||
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
|
||||
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
|
||||
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
|
||||
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
|
||||
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
|
||||
|
||||
0.5f, 0.5f, 0.5f,
|
||||
0.5f, 0.5f, -0.5f,
|
||||
0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
|
||||
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
|
||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
|
||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
|
||||
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
|
||||
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, -0.5f,
|
||||
0.5f, -0.5f, 0.5f,
|
||||
0.5f, -0.5f, 0.5f,
|
||||
-0.5f, -0.5f, 0.5f,
|
||||
-0.5f, -0.5f, -0.5f,
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
|
||||
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
|
||||
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
|
||||
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
|
||||
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
|
||||
|
||||
-0.5f, 0.5f, -0.5f,
|
||||
0.5f, 0.5f, -0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, 0.5f,
|
||||
-0.5f, 0.5f, -0.5f
|
||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
||||
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
|
||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
|
||||
};
|
||||
|
||||
glGenVertexArrays(1, &_vao);
|
||||
@ -101,8 +102,11 @@ bool Renderer::init(int screen_width, int screen_height) {
|
||||
glBindVertexArray(_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
|
||||
/* Position attribute. */
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
/* Normal attribute. */
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
@ -154,15 +158,16 @@ void Renderer::render(const Camera& camera, const Player& player,
|
||||
|
||||
/* Render world. */
|
||||
/* Set lighting uniforms for terrain. */
|
||||
_shader.set_vec3("objectColor", { 0.4f, 0.6f, 0.2f}); /* Green. */
|
||||
_shader.set_vec3("lightColor", { 1.0f, 1.0f, 1.0f});
|
||||
_shader.set_vec3("lightDir", {-0.5f, -1.0f, -0.5f}); /* From above and to the side. */
|
||||
|
||||
_shader.set_bool("u_IsTerrain", true);
|
||||
for(auto const& [pos, mesh] : world.get_chunk_meshes()) {
|
||||
BettolaMath::Mat4 model;
|
||||
_shader.set_mat4("model", model);
|
||||
mesh->draw();
|
||||
}
|
||||
_shader.set_bool("u_IsTerrain", false);
|
||||
|
||||
/* Draw the local player's cube. */
|
||||
_shader.set_vec3("objectColor", {0.2f, 0.5f, 0.8f}); /* Player colour. */
|
||||
|
||||
@ -13,6 +13,7 @@ public:
|
||||
void use(void);
|
||||
|
||||
void set_mat4(const std::string& name, const BettolaMath::Mat4& matrix) const;
|
||||
void set_bool(const std::string& name, bool value) const;
|
||||
void set_vec3(const std::string& name, const BettolaMath::Vec3& value) const;
|
||||
unsigned int get_id(void) const { return _program_id; }
|
||||
private:
|
||||
|
||||
@ -10,3 +10,7 @@ void Shader::set_mat4(const std::string& name, const BettolaMath::Mat4& matrix)
|
||||
void Shader::set_vec3(const std::string& name, const BettolaMath::Vec3& value) const {
|
||||
glUniform3f(glGetUniformLocation(_program_id, name.c_str()), value.x, value.y, value.z);
|
||||
}
|
||||
|
||||
void Shader::set_bool(const std::string& name, bool value) const {
|
||||
glUniform1i(glGetUniformLocation(_program_id, name.c_str()), (int)value);
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ void Game::_send_chunks_around(Player* player, int center_x, int center_z) {
|
||||
msg.chunk_x = x;
|
||||
msg.chunk_z = z;
|
||||
memcpy(msg.heightmap, chunk.heightmap.data(), chunk.heightmap.size() * sizeof(float));
|
||||
memcpy(msg.detailmap, chunk.detailmap.data(), chunk.detailmap.size() * sizeof(float));
|
||||
|
||||
player->get_socket().send(&header, sizeof(header));
|
||||
player->get_socket().send(&msg, sizeof(msg));
|
||||
|
||||
@ -14,6 +14,12 @@ World::World(void) {
|
||||
_noise.SetFractalOctaves(5);
|
||||
_noise.SetFractalLacunarity(2.0f);
|
||||
_noise.SetFractalGain(0.5);
|
||||
|
||||
/* Use a different seed for the detail noise. */
|
||||
_detail_noise.SetSeed(std::chrono::high_resolution_clock::now().time_since_epoch().count()+1);
|
||||
|
||||
_detail_noise.SetNoiseType(FastNoiseLite::NoiseType_Perlin);
|
||||
_detail_noise.SetFrequency(0.2f); /* Higher frequency for smaller details. */
|
||||
}
|
||||
|
||||
BettolaLib::Game::Chunk& World::get_chunk(int x, int z) {
|
||||
@ -40,6 +46,7 @@ void World::_generate_chunk(BettolaLib::Game::Chunk& chunk, int chunk_x, int chu
|
||||
|
||||
/* generate noise value. */
|
||||
chunk.heightmap[z * BettolaLib::Game::CHUNK_DATA_WIDTH + x] = fabsf(_noise.GetNoise(world_x, world_z));
|
||||
chunk.detailmap[z * BettolaLib::Game::CHUNK_DATA_WIDTH + x] = _detail_noise.GetNoise(world_x, world_z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ private:
|
||||
void _generate_chunk(BettolaLib::Game::Chunk& chunk, int chunk_x, int chunk_z);
|
||||
|
||||
FastNoiseLite _noise;
|
||||
FastNoiseLite _detail_noise;
|
||||
std::map<ChunkPos, BettolaLib::Game::Chunk> _chunks;
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user