[Chunk] First attempt to lighting.

This commit is contained in:
Quentin Bazin 2018-06-25 00:05:21 +02:00
parent 72c7948e74
commit 09ba9c84d3
9 changed files with 203 additions and 11 deletions

View File

@ -17,10 +17,11 @@
#include "OpenGL.hpp"
struct Vertex {
GLfloat coord3d[4] = {0, 0, 0, 1};
GLfloat color[4] = {0, 0, 0, 1};
GLfloat normal[3] = {0, 0, 0};
GLfloat texCoord[2] = {0, 0};
GLfloat coord3d[4] = {0, 0, 0, 1};
GLfloat color[4] = {0, 0, 0, 1};
GLfloat normal[3] = {0, 0, 0};
GLfloat texCoord[2] = {0, 0};
GLfloat lightValue[2] = {-1, -1};
};
#endif // VERTEX_HPP_

View File

@ -26,6 +26,23 @@
#include "Texture.hpp"
#include "VertexBuffer.hpp"
#include <queue>
struct LightNode {
LightNode(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
int x;
int y;
int z;
};
struct LightRemovalNode {
LightRemovalNode(int _x, int _y, int _z, int _value) : x(_x), y(_y), z(_z), value(_value) {}
int x;
int y;
int z;
int value;
};
class Chunk : public NonCopyable, public IDrawable {
public:
Chunk(s32 x, s32 y, s32 z, Texture &texture);
@ -35,6 +52,11 @@ class Chunk : public NonCopyable, public IDrawable {
u32 getBlock(int x, int y, int z) const;
void setBlock(int x, int y, int z, u32 id);
void addLight(Chunk &chunk, int x, int y, int z, int val);
void removeLight(Chunk &chunk, int x, int y, int z);
void updateLights(Chunk &chunk);
s32 x() const { return m_x; }
s32 y() const { return m_y; }
s32 z() const { return m_z; }
@ -65,6 +87,12 @@ class Chunk : public NonCopyable, public IDrawable {
void setGenerated(bool isGenerated) { m_isGenerated = isGenerated; }
void setInitialized(bool isInitialized) { m_isInitialized = isInitialized; }
int getSunlight(int x, int y, int z) const;
void setSunlight(int x, int y, int z, int val);
int getTorchlight(int x, int y, int z) const;
void setTorchlight(int x, int y, int z, int val);
private:
void draw(RenderTarget &target, RenderStates states) const override;
void drawOutlines(RenderTarget &target, RenderStates states) const;
@ -79,6 +107,12 @@ class Chunk : public NonCopyable, public IDrawable {
using DataArray = u32[Chunk::width][Chunk::height][Chunk::depth];
DataArray m_data;
using LightMapArray = u8[Chunk::width][Chunk::height][Chunk::depth];
LightMapArray m_lightMap;
std::queue<LightNode> m_lightBfsQueue;
std::queue<LightRemovalNode> m_lightRemovalBfsQueue;
std::queue<LightNode> m_sunlightBfsQueue;
ChunkBuilder m_builder;
VertexBuffer m_vbo;

View File

@ -28,7 +28,7 @@ class ChunkBuilder {
std::size_t buildChunk(const Chunk &chunk, const VertexBuffer &vbo);
private:
void addFace(u8 x, u8 y, u8 z, u8 i, const Block *block, const Block *surroundingBlock);
void addFace(u8 x, u8 y, u8 z, u8 i, const Chunk &chunk, const Block *block, const Block *surroundingBlock);
std::vector<Vertex> m_vertices;
};

View File

@ -4,11 +4,13 @@ attribute vec4 color;
attribute vec4 coord3d;
attribute vec3 normal;
attribute vec2 texCoord;
attribute vec2 lightValue;
varying vec4 v_color;
varying vec4 v_coord3d;
varying vec4 v_normal;
varying vec2 v_texCoord;
varying vec2 v_lightValue;
uniform mat4 u_modelMatrix;
uniform mat4 u_projectionMatrix;
@ -19,9 +21,10 @@ void main() {
v_normal = vec4(normal, 1.0);
v_color = color;
v_texCoord = texCoord;
v_lightValue = lightValue;
// Get rid of unused 'normal' attribute warning
v_coord3d = v_coord3d + v_normal * 0.00000000000000000001;
// Get rid of unused 'normal'/'lightValue' attribute warning
v_coord3d = v_coord3d + v_normal * vec4(v_lightValue, 1.0, 1.0) * 0.00000000000000000001;
gl_Position = u_projectionMatrix * u_viewMatrix * v_coord3d;
}

View File

@ -3,6 +3,9 @@
varying float v_blockID;
varying float v_dist;
varying vec4 v_coord3d;
varying vec2 v_lightValue;
uniform int u_renderDistance;
// Get current pixel color
@ -36,8 +39,11 @@ void main() {
// vec3 lightPosition = vec3(0.0, sin(time) * 40, cos(time) * 40);
// color *= light(vec3(1.0, 1.0, 1.0), vec4(lightPosition, 1.0), 0.5, 0.5);
if (v_blockID != -1)
color = light(color, vec3(1.0, 1.0, 1.0), vec4(0.0, 48.0, 0.0, 1.0), 0.5, 0.5);
if (v_lightValue.x != -1)
color = light(color, vec3(1.0, 1.0, 1.0), v_coord3d, v_lightValue.y / 14.0, 1.0);
/* if (v_blockID != -1) */
/* color = light(color, vec3(1.0, 1.0, 1.0), vec4(0.0, 48.0, 0.0, 1.0), 0.5, 0.5); */
color = fog(color, v_dist, u_renderDistance - 32, u_renderDistance);

View File

@ -4,11 +4,13 @@ attribute vec4 color;
attribute vec4 coord3d;
attribute vec3 normal;
attribute vec2 texCoord;
attribute vec2 lightValue;
varying vec4 v_color;
varying vec4 v_coord3d;
varying vec4 v_normal;
varying vec2 v_texCoord;
varying vec2 v_lightValue;
varying float v_blockID;
varying float v_dist;
@ -42,6 +44,7 @@ void main() {
v_color = color;
v_texCoord = texCoord;
v_lightValue = lightValue;
// Distance from eye
v_dist = length(u_viewMatrix * v_coord3d);

View File

@ -38,6 +38,7 @@ void RenderTarget::draw(const VertexBuffer &vertexBuffer, GLenum mode, std::size
states.shader->enableVertexAttribArray("coord3d");
states.shader->enableVertexAttribArray("normal");
states.shader->enableVertexAttribArray((states.texture) ? "texCoord" : "color");
states.shader->enableVertexAttribArray("lightValue");
// glVertexAttribPointer(states.shader->attrib("coord3d"), 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(states.shader->attrib("coord3d"), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, coord3d)));
@ -46,6 +47,7 @@ void RenderTarget::draw(const VertexBuffer &vertexBuffer, GLenum mode, std::size
glVertexAttribPointer(states.shader->attrib("texCoord"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, texCoord)));
else
glVertexAttribPointer(states.shader->attrib("color"), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, color)));
glVertexAttribPointer(states.shader->attrib("lightValue"), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<GLvoid *>(offsetof(Vertex, lightValue)));
if (states.texture)
@ -55,6 +57,7 @@ void RenderTarget::draw(const VertexBuffer &vertexBuffer, GLenum mode, std::size
Texture::bind(nullptr);
states.shader->disableVertexAttribArray("lightValue");
states.shader->disableVertexAttribArray((states.texture) ? "texCoord" : "color");
states.shader->disableVertexAttribArray("normal");
states.shader->disableVertexAttribArray("coord3d");

View File

@ -18,6 +18,9 @@ Chunk::Chunk(s32 x, s32 y, s32 z, Texture &texture) : m_texture(texture) {
m_x = x;
m_y = y;
m_z = z;
std::memset(m_data, 0, sizeof(m_data));
std::memset(m_lightMap, 0, sizeof(m_lightMap));
}
void Chunk::update(World &world) {
@ -67,6 +70,11 @@ void Chunk::setBlock(int x, int y, int z, u32 type) {
m_tickingBlocks.erase(it);
}
if (type == 2)
addLight(*this, x, y, z, 14);
else if (m_data[x][y][z] == 2)
removeLight(*this, x, y, z);
m_data[x][y][z] = type;
m_isChanged = true;
@ -79,6 +87,137 @@ void Chunk::setBlock(int x, int y, int z, u32 type) {
if(z == depth - 1 && back()) { back()->m_isChanged = true; }
}
void Chunk::addLight(Chunk &chunk, int x, int y, int z, int val) {
chunk.setTorchlight(x, y, z, val);
m_lightBfsQueue.emplace(x, y, z);
updateLights(chunk);
}
void Chunk::removeLight(Chunk &chunk, int x, int y, int z) {
m_lightRemovalBfsQueue.emplace(x, y, z, chunk.getTorchlight(x, y, z));
chunk.setTorchlight(x, y, z, 0);
updateLights(chunk);
}
void Chunk::updateLights(Chunk &chunk) {
while (!m_lightRemovalBfsQueue.empty()) {
LightRemovalNode node = m_lightRemovalBfsQueue.front();
m_lightRemovalBfsQueue.pop();
LightNode surroundingNodes[6] = {
{node.x - 1, node.y, node.z},
{node.x + 1, node.y, node.z},
{node.x, node.y - 1, node.z},
{node.x, node.y + 1, node.z},
{node.x, node.y, node.z - 1},
{node.x, node.y, node.z + 1},
};
for (const LightNode &surroundingNode : surroundingNodes) {
int level = chunk.getTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z);
if (level != 0 && level < node.value) {
chunk.setTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, 0);
m_lightRemovalBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z, level);
}
else if (level >= node.value) {
m_lightBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z);
}
}
}
while (!m_lightBfsQueue.empty()) {
LightNode node = m_lightBfsQueue.front();
m_lightBfsQueue.pop();
LightNode surroundingNodes[6] = {
{node.x - 1, node.y, node.z},
{node.x + 1, node.y, node.z},
{node.x, node.y - 1, node.z},
{node.x, node.y + 1, node.z},
{node.x, node.y, node.z - 1},
{node.x, node.y, node.z + 1},
};
int lightLevel = chunk.getTorchlight(node.x, node.y, node.z);
for (const LightNode &surroundingNode : surroundingNodes) {
if (/*!Registry::getInstance().getBlock(getBlock(surroundingNode.x, surroundingNode.y, surroundingNode.z)).isOpaque()
&& */ chunk.getTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z) + 2 <= lightLevel) {
chunk.setTorchlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, lightLevel - 1);
m_lightBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z);
}
}
}
while (!m_sunlightBfsQueue.empty()) {
LightNode node = m_sunlightBfsQueue.front();
m_sunlightBfsQueue.pop();
LightNode surroundingNodes[6] = {
{node.x - 1, node.y, node.z},
{node.x + 1, node.y, node.z},
{node.x, node.y - 1, node.z},
{node.x, node.y + 1, node.z},
{node.x, node.y, node.z - 1},
{node.x, node.y, node.z + 1},
};
int sunlightLevel = chunk.getSunlight(node.x, node.y, node.z);
for (const LightNode &surroundingNode : surroundingNodes) {
if (/*!Registry::getInstance().getBlock(getBlock(surroundingNode.x, surroundingNode.y, surroundingNode.z)).isOpaque()
&& */ chunk.getSunlight(surroundingNode.x, surroundingNode.y, surroundingNode.z) + 2 <= sunlightLevel) {
chunk.setSunlight(surroundingNode.x, surroundingNode.y, surroundingNode.z, sunlightLevel - 1);
m_sunlightBfsQueue.emplace(surroundingNode.x, surroundingNode.y, surroundingNode.z);
}
}
}
}
int Chunk::getSunlight(int x, int y, int z) const {
if(x < 0) return m_surroundingChunks[0] ? m_surroundingChunks[0]->getSunlight(x + Chunk::width, y, z) : 0;
if(x >= Chunk::width) return m_surroundingChunks[1] ? m_surroundingChunks[1]->getSunlight(x - Chunk::width, y, z) : 0;
if(y < 0) return m_surroundingChunks[4] ? m_surroundingChunks[4]->getSunlight(x, y + Chunk::height, z) : 0;
if(y >= Chunk::height) return m_surroundingChunks[5] ? m_surroundingChunks[5]->getSunlight(x, y - Chunk::height, z) : 0;
if(z < 0) return m_surroundingChunks[2] ? m_surroundingChunks[2]->getSunlight(x, y, z + Chunk::depth) : 0;
if(z >= Chunk::depth) return m_surroundingChunks[3] ? m_surroundingChunks[3]->getSunlight(x, y, z - Chunk::depth) : 0;
return (m_lightMap[x][y][z] >> 4) & 0xf;
}
void Chunk::setSunlight(int x, int y, int z, int val) {
if(x < 0) { if(m_surroundingChunks[0]) m_surroundingChunks[0]->setSunlight(x + Chunk::width, y, z, val); return; }
if(x >= Chunk::width) { if(m_surroundingChunks[1]) m_surroundingChunks[1]->setSunlight(x - Chunk::width, y, z, val); return; }
if(y < 0) { if(m_surroundingChunks[4]) m_surroundingChunks[4]->setSunlight(x, y + Chunk::height, z, val); return; }
if(y >= Chunk::height) { if(m_surroundingChunks[5]) m_surroundingChunks[5]->setSunlight(x, y - Chunk::height, z, val); return; }
if(z < 0) { if(m_surroundingChunks[2]) m_surroundingChunks[2]->setSunlight(x, y, z + Chunk::depth, val); return; }
if(z >= Chunk::depth) { if(m_surroundingChunks[3]) m_surroundingChunks[3]->setSunlight(x, y, z - Chunk::depth, val); return; }
m_lightMap[x][y][z] = (m_lightMap[x][y][z] & 0xf) | (val << 4);
m_isChanged = true;
}
int Chunk::getTorchlight(int x, int y, int z) const {
if(x < 0) return m_surroundingChunks[0] ? m_surroundingChunks[0]->getTorchlight(x + Chunk::width, y, z) : 0;
if(x >= Chunk::width) return m_surroundingChunks[1] ? m_surroundingChunks[1]->getTorchlight(x - Chunk::width, y, z) : 0;
if(y < 0) return m_surroundingChunks[4] ? m_surroundingChunks[4]->getTorchlight(x, y + Chunk::height, z) : 0;
if(y >= Chunk::height) return m_surroundingChunks[5] ? m_surroundingChunks[5]->getTorchlight(x, y - Chunk::height, z) : 0;
if(z < 0) return m_surroundingChunks[2] ? m_surroundingChunks[2]->getTorchlight(x, y, z + Chunk::depth) : 0;
if(z >= Chunk::depth) return m_surroundingChunks[3] ? m_surroundingChunks[3]->getTorchlight(x, y, z - Chunk::depth) : 0;
return m_lightMap[x][y][z] & 0xf;
}
void Chunk::setTorchlight(int x, int y, int z, int val) {
if(x < 0) { if(m_surroundingChunks[0]) m_surroundingChunks[0]->setTorchlight(x + Chunk::width, y, z, val); return; }
if(x >= Chunk::width) { if(m_surroundingChunks[1]) m_surroundingChunks[1]->setTorchlight(x - Chunk::width, y, z, val); return; }
if(y < 0) { if(m_surroundingChunks[4]) m_surroundingChunks[4]->setTorchlight(x, y + Chunk::height, z, val); return; }
if(y >= Chunk::height) { if(m_surroundingChunks[5]) m_surroundingChunks[5]->setTorchlight(x, y - Chunk::height, z, val); return; }
if(z < 0) { if(m_surroundingChunks[2]) m_surroundingChunks[2]->setTorchlight(x, y, z + Chunk::depth, val); return; }
if(z >= Chunk::depth) { if(m_surroundingChunks[3]) m_surroundingChunks[3]->setTorchlight(x, y, z - Chunk::depth, val); return; }
m_lightMap[x][y][z] = (m_lightMap[x][y][z] & 0xf0) | val;
m_isChanged = true;
}
void Chunk::draw(RenderTarget &target, RenderStates states) const {
if(m_verticesCount == 0) return;

View File

@ -72,7 +72,7 @@ std::size_t ChunkBuilder::buildChunk(const Chunk &chunk, const VertexBuffer &vbo
};
for(u8 i = 0 ; i < 6 ; i++) {
addFace(x, y, z, i, &block, surroundingBlocks[i]);
addFace(x, y, z, i, chunk, &block, surroundingBlocks[i]);
}
}
}
@ -89,7 +89,7 @@ std::size_t ChunkBuilder::buildChunk(const Chunk &chunk, const VertexBuffer &vbo
return verticesCount;
}
void ChunkBuilder::addFace(u8 x, u8 y, u8 z, u8 i, const Block *block, const Block *surroundingBlock) {
void ChunkBuilder::addFace(u8 x, u8 y, u8 z, u8 i, const Chunk &chunk, const Block *block, const Block *surroundingBlock) {
// Skip hidden faces
if(surroundingBlock && surroundingBlock->id()
&& (surroundingBlock->isOpaque() || (block->id() == surroundingBlock->id() && block->id() != 4)))
@ -141,6 +141,9 @@ void ChunkBuilder::addFace(u8 x, u8 y, u8 z, u8 i, const Block *block, const Blo
vertex.texCoord[0] = faceTexCoords[j * 2];
vertex.texCoord[1] = faceTexCoords[j * 2 + 1];
vertex.lightValue[0] = chunk.getSunlight(x, y, z);
vertex.lightValue[1] = chunk.getTorchlight(x, y, z);
m_vertices.emplace_back(vertex);
}
}