[ChunkBuilder] Real ambient occlusion added.
Credits goes to this awesome article: https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/
This commit is contained in:
parent
63286f4747
commit
30e893db69
@ -36,6 +36,8 @@ extern int GUI_SCALE; // FIXME
|
||||
|
||||
namespace Config {
|
||||
extern bool isSmoothLightingEnabled;
|
||||
extern bool isAmbientOcclusionEnabled;
|
||||
extern bool isWireframeModeEnabled;
|
||||
}
|
||||
|
||||
#endif // CONFIG_HPP_
|
||||
|
@ -79,8 +79,6 @@ class Chunk : public gk::NonCopyable {
|
||||
private:
|
||||
void updateNeighbours(int x, int y, int z);
|
||||
|
||||
// void drawOutlines(RenderTarget &target, RenderStates states) const;
|
||||
|
||||
s32 m_x;
|
||||
s32 m_y;
|
||||
s32 m_z;
|
||||
|
@ -33,6 +33,8 @@ class ChunkBuilder {
|
||||
private:
|
||||
void addFace(u8 x, u8 y, u8 z, u8 i, const Chunk &chunk, const Block *block, const Block *surroundingBlock);
|
||||
|
||||
u8 getAmbientOcclusion(u8 x, u8 y, u8 z, u8 i, u8 j, const Chunk &chunk);
|
||||
|
||||
enum class Light {
|
||||
Sun,
|
||||
Torch
|
||||
|
@ -1,12 +1,13 @@
|
||||
#version 120
|
||||
|
||||
varying vec4 v_coord3d;
|
||||
varying vec2 v_lightValue;
|
||||
varying float v_ambientOcclusion;
|
||||
|
||||
varying float v_blockFace;
|
||||
varying float v_blockID;
|
||||
varying float v_dist;
|
||||
|
||||
varying vec4 v_coord3d;
|
||||
varying vec2 v_lightValue;
|
||||
|
||||
uniform int u_renderDistance;
|
||||
|
||||
// Get current pixel color
|
||||
@ -59,6 +60,8 @@ void main() {
|
||||
// color = vec4(0, 0, v_lightValue.x / 16.0, 1);
|
||||
}
|
||||
|
||||
color.rgb *= v_ambientOcclusion;
|
||||
|
||||
color = fog(color, v_dist, u_renderDistance - 32, u_renderDistance);
|
||||
|
||||
gl_FragColor = color;
|
||||
|
@ -6,12 +6,14 @@ attribute vec3 normal;
|
||||
attribute vec2 texCoord;
|
||||
attribute vec2 lightValue;
|
||||
attribute float blockType;
|
||||
attribute float ambientOcclusion;
|
||||
|
||||
varying vec4 v_color;
|
||||
varying vec4 v_coord3d;
|
||||
varying vec4 v_normal;
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_lightValue;
|
||||
varying float v_ambientOcclusion;
|
||||
|
||||
varying float v_blockFace;
|
||||
varying float v_blockID;
|
||||
@ -42,13 +44,20 @@ void main() {
|
||||
v_coord3d = u_modelMatrix * vec4(finalPos, 1.0);
|
||||
v_normal = vec4(normal, 1.0);
|
||||
|
||||
v_blockFace = coord3d.w;
|
||||
v_blockID = blockType;
|
||||
|
||||
v_color = color;
|
||||
v_texCoord = texCoord;
|
||||
v_lightValue = lightValue;
|
||||
|
||||
if (ambientOcclusion != 5) {
|
||||
const float aovalues[] = float[](0.5, 0.75, 0.9, 1.0);
|
||||
v_ambientOcclusion = aovalues[int(ambientOcclusion)];
|
||||
} else {
|
||||
v_ambientOcclusion = 1.0;
|
||||
}
|
||||
|
||||
v_blockFace = coord3d.w;
|
||||
v_blockID = blockType;
|
||||
|
||||
// Distance from eye
|
||||
v_dist = length(u_viewMatrix * v_coord3d);
|
||||
|
||||
|
@ -16,4 +16,6 @@
|
||||
int GUI_SCALE = 3; // FIXME
|
||||
|
||||
bool Config::isSmoothLightingEnabled = true;
|
||||
bool Config::isAmbientOcclusionEnabled = true;
|
||||
bool Config::isWireframeModeEnabled = false;
|
||||
|
||||
|
@ -74,15 +74,27 @@ void SettingsMenuState::addGraphicsButtons() {
|
||||
World::isReloadRequested = true;
|
||||
});
|
||||
|
||||
m_menuWidget.addButton(0, 2, "GUI Scale: " + std::to_string(GUI_SCALE), [] (TextButton &button) {
|
||||
m_menuWidget.addButton(0, 2, std::string("Ambient Occlusion: ") + (Config::isAmbientOcclusionEnabled ? "ON" : "OFF"), [] (TextButton &button) {
|
||||
Config::isAmbientOcclusionEnabled = !Config::isAmbientOcclusionEnabled;
|
||||
button.setText(std::string("Ambient Occlusion: ") + (Config::isAmbientOcclusionEnabled ? "ON" : "OFF"));
|
||||
World::isReloadRequested = true;
|
||||
});
|
||||
|
||||
m_menuWidget.addButton(0, 3, std::string("Wireframe Mode: ") + (Config::isWireframeModeEnabled ? "ON" : "OFF"), [] (TextButton &button) {
|
||||
Config::isWireframeModeEnabled = !Config::isWireframeModeEnabled;
|
||||
button.setText(std::string("Wireframe Mode: ") + (Config::isWireframeModeEnabled ? "ON" : "OFF"));
|
||||
World::isReloadRequested = true;
|
||||
});
|
||||
|
||||
m_menuWidget.addButton(0, 4, "GUI Scale: " + std::to_string(GUI_SCALE), [] (TextButton &button) {
|
||||
GUI_SCALE = 1 + (GUI_SCALE + 1) % 3;
|
||||
button.setText("GUI Scale: " + std::to_string(GUI_SCALE));
|
||||
// FIXME: Fix decrease bug
|
||||
// Reload menus with new scaling
|
||||
});
|
||||
|
||||
m_menuWidget.addButton(0, 3, "Fullscreen: OFF", [] (TextButton &) {}).setEnabled(false);
|
||||
m_menuWidget.addButton(0, 4, "Use VSync: OFF", [] (TextButton &) {}).setEnabled(false);
|
||||
m_menuWidget.addButton(0, 5, "Fullscreen: OFF", [] (TextButton &) {}).setEnabled(false);
|
||||
m_menuWidget.addButton(0, 6, "Use VSync: OFF", [] (TextButton &) {}).setEnabled(false);
|
||||
|
||||
m_menuWidget.addButton(0, 7, "Done", [this] (TextButton &) {
|
||||
m_menuWidget.reset(1, 8);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <gk/system/GameClock.hpp>
|
||||
|
||||
#include "Chunk.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "Registry.hpp"
|
||||
|
||||
Chunk::Chunk(s32 x, s32 y, s32 z, gk::Texture &texture) : m_texture(texture) {
|
||||
@ -181,16 +182,9 @@ void Chunk::drawLayer(gk::RenderTarget &target, gk::RenderStates states, u16 lay
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
target.draw(m_vbo.at(layer), GL_QUADS, 0, m_verticesCount.at(layer), states);
|
||||
|
||||
// drawOutlines(target, states);
|
||||
if(Config::isWireframeModeEnabled) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
// target.draw(m_vbo.at(layer), GL_QUADS, 0, m_verticesCount.at(layer), states);
|
||||
target.draw(m_vbo.at(layer), GL_TRIANGLES, 0, m_verticesCount.at(layer), states);
|
||||
if(Config::isWireframeModeEnabled) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
// void Chunk::drawOutlines(RenderTarget &target, RenderStates states) const {
|
||||
// states.texture = nullptr;
|
||||
//
|
||||
// for(u32 i = 0 ; i < m_verticesCount ; i += 4) {
|
||||
// target.draw(m_vbo, GL_LINE_LOOP, i, 4, states);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
@ -134,51 +134,112 @@ void ChunkBuilder::addFace(u8 x, u8 y, u8 z, u8 i, const Chunk &chunk, const Blo
|
||||
};
|
||||
|
||||
// Store vertex information
|
||||
gk::Vertex vertices[4];
|
||||
for(u8 j = 0 ; j < 4 ; j++) {
|
||||
gk::Vertex vertex;
|
||||
vertices[j].coord3d[0] = x + cubeCoords[i * 12 + j * 3] * boundingBox.width + boundingBox.x;
|
||||
vertices[j].coord3d[1] = y + cubeCoords[i * 12 + j * 3 + 1] * boundingBox.height + boundingBox.y;
|
||||
vertices[j].coord3d[2] = z + cubeCoords[i * 12 + j * 3 + 2] * boundingBox.depth + boundingBox.z;
|
||||
vertices[j].coord3d[3] = i;
|
||||
|
||||
vertex.coord3d[0] = x + cubeCoords[i * 12 + j * 3] * boundingBox.width + boundingBox.x;
|
||||
vertex.coord3d[1] = y + cubeCoords[i * 12 + j * 3 + 1] * boundingBox.height + boundingBox.y;
|
||||
vertex.coord3d[2] = z + cubeCoords[i * 12 + j * 3 + 2] * boundingBox.depth + boundingBox.z;
|
||||
vertex.coord3d[3] = i;
|
||||
vertices[j].normal[0] = normal.x;
|
||||
vertices[j].normal[1] = normal.y;
|
||||
vertices[j].normal[2] = normal.z;
|
||||
|
||||
vertex.normal[0] = normal.x;
|
||||
vertex.normal[1] = normal.y;
|
||||
vertex.normal[2] = normal.z;
|
||||
vertices[j].color[0] = 1.0;
|
||||
vertices[j].color[1] = 1.0;
|
||||
vertices[j].color[2] = 1.0;
|
||||
vertices[j].color[3] = 1.0;
|
||||
|
||||
vertex.color[0] = 1.0;
|
||||
vertex.color[1] = 1.0;
|
||||
vertex.color[2] = 1.0;
|
||||
vertex.color[3] = 1.0;
|
||||
|
||||
vertex.texCoord[0] = faceTexCoords[j * 2];
|
||||
vertex.texCoord[1] = faceTexCoords[j * 2 + 1];
|
||||
vertices[j].texCoord[0] = faceTexCoords[j * 2];
|
||||
vertices[j].texCoord[1] = faceTexCoords[j * 2 + 1];
|
||||
|
||||
// int sunlight = chunk.lightmap().getSunlight(x, y, z);
|
||||
// if ((i == 0 || i == 1 || i == 4 || i == 5) && sunlight > 2)
|
||||
// vertex.lightValue[0] = sunlight - 2;
|
||||
// vertices[j].lightValue[0] = sunlight - 2;
|
||||
// if (i == 4 && sunlight > 3)
|
||||
// vertex.lightValue[0] = sunlight - 3;
|
||||
// vertices[j].lightValue[0] = sunlight - 3;
|
||||
// else
|
||||
|
||||
if (Config::isSmoothLightingEnabled) {
|
||||
vertex.lightValue[0] = getLightForVertex(Light::Sun, x, y, z, i, j, chunk);
|
||||
vertex.lightValue[1] = getLightForVertex(Light::Torch, x, y, z, i, j, chunk);
|
||||
if (Config::isAmbientOcclusionEnabled)
|
||||
vertices[j].lightValue[0] = chunk.lightmap().getSunlight(x, y, z);
|
||||
else
|
||||
vertices[j].lightValue[0] = getLightForVertex(Light::Sun, x, y, z, i, j, chunk);
|
||||
|
||||
vertices[j].lightValue[1] = getLightForVertex(Light::Torch, x, y, z, i, j, chunk);
|
||||
}
|
||||
else {
|
||||
vertex.lightValue[0] = chunk.lightmap().getSunlight(x, y, z);
|
||||
vertex.lightValue[1] = chunk.lightmap().getTorchlight(x, y, z);
|
||||
vertices[j].lightValue[0] = chunk.lightmap().getSunlight(x, y, z);
|
||||
vertices[j].lightValue[1] = chunk.lightmap().getTorchlight(x, y, z);
|
||||
}
|
||||
|
||||
vertex.blockType = block->id();
|
||||
|
||||
if (block->id() == BlockType::Water)
|
||||
m_vertices[Layer::Liquid].emplace_back(vertex);
|
||||
else if (block->id() == BlockType::Leaves)
|
||||
m_vertices[Layer::Other].emplace_back(vertex);
|
||||
if (Config::isAmbientOcclusionEnabled)
|
||||
vertices[j].ambientOcclusion = getAmbientOcclusion(x, y, z, i, j, chunk);
|
||||
else
|
||||
m_vertices[Layer::Solid].emplace_back(vertex);
|
||||
vertices[j].ambientOcclusion = 5;
|
||||
|
||||
vertices[j].blockType = block->id();
|
||||
}
|
||||
|
||||
auto addVertex = [&](u8 j) {
|
||||
if (block->id() == BlockType::Water)
|
||||
m_vertices[Layer::Liquid].emplace_back(vertices[j]);
|
||||
else if (block->id() == BlockType::Leaves)
|
||||
m_vertices[Layer::Other].emplace_back(vertices[j]);
|
||||
else
|
||||
m_vertices[Layer::Solid].emplace_back(vertices[j]);
|
||||
};
|
||||
|
||||
if (vertices[0].ambientOcclusion + vertices[2].ambientOcclusion >
|
||||
vertices[1].ambientOcclusion + vertices[3].ambientOcclusion) {
|
||||
addVertex(0);
|
||||
addVertex(1);
|
||||
addVertex(3);
|
||||
addVertex(3);
|
||||
addVertex(1);
|
||||
addVertex(2);
|
||||
} else {
|
||||
addVertex(0);
|
||||
addVertex(1);
|
||||
addVertex(2);
|
||||
addVertex(2);
|
||||
addVertex(3);
|
||||
addVertex(0);
|
||||
}
|
||||
}
|
||||
|
||||
u8 ChunkBuilder::getAmbientOcclusion(u8 x, u8 y, u8 z, u8 i, u8 j, const Chunk &chunk) {
|
||||
// s16 offsetX = 0;
|
||||
s16 offsetX = (
|
||||
(i == 0) ||
|
||||
(i == 2 && (j == 0 || j == 3)) ||
|
||||
(i == 3 && (j == 0 || j == 3)) ||
|
||||
(i == 4 && (j == 1 || j == 2)) ||
|
||||
(i == 5 && (j == 0 || j == 3))) ? -1 : 1;
|
||||
|
||||
// s16 offsetZ = 0;
|
||||
s16 offsetZ = (
|
||||
(i == 4) ||
|
||||
(i == 0 && (j == 0 || j == 3)) ||
|
||||
(i == 1 && (j == 1 || j == 2)) ||
|
||||
(i == 2 && (j == 0 || j == 1)) ||
|
||||
(i == 3 && (j == 2 || j == 3))) ? -1 : 1;
|
||||
|
||||
s16 offsetY = (
|
||||
(i == 2) ||
|
||||
(i == 0 && (j == 0 || j == 1)) ||
|
||||
(i == 1 && (j == 0 || j == 1)) ||
|
||||
(i == 4 && (j == 0 || j == 1)) ||
|
||||
(i == 5 && (j == 0 || j == 1))) ? 0 : 1;
|
||||
|
||||
bool side1 = chunk.getBlock(x + offsetX, y + offsetY, z) != 0;
|
||||
bool side2 = chunk.getBlock(x, y + offsetY, z + offsetZ) != 0;
|
||||
bool corner = chunk.getBlock(x + offsetX, y + offsetY, z + offsetZ) != 0;
|
||||
|
||||
if (side1 && side2)
|
||||
return 0;
|
||||
|
||||
return 3 - (side1 + side2 + corner);
|
||||
}
|
||||
|
||||
float ChunkBuilder::getAverageLight(Light light, u8 x, u8 y, u8 z, s8 offsetX, s8 offsetY, s8 offsetZ, const Chunk &chunk) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user