DeerEngine/Deer/src/DeerRender/Voxels/VoxelWorld_AmbientLightPropagation.cpp

180 lines
5.6 KiB
C++
Executable File

#include "Deer/VoxelWorld.h"
#include "Deer/Voxels/Chunk.h"
#include "Deer/Application.h"
#include "Deer/Components.h"
#include "Deer/Voxels/VoxelWorldData.h"
#include "DeerRender/Render/Render.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Texture.h"
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#include "Deer/Log.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/matrix_inverse.hpp"
namespace Deer {
void VoxelWorld::bakeAmbientLight(int minX, int maxX, int minZ, int maxZ) {
int xPos = minX;
for (; xPos <= maxX; xPos++) {
int zPos = minZ;
for (; zPos <= maxZ; zPos++) {
LayerVoxel layer = readLayerVoxel(xPos, zPos);
uint16_t maxHeight = layer.height;
uint16_t minHeight = layer.ambient_light_height;
if (minHeight > layer.height)
minHeight = layer.height;
uint16_t maxHeightSorroundings = maxHeight;
for (int i = 0; i < 8; i++) {
int checkX = xPos + LAYER_CHECK_DIRS(X_AXIS, i);
int checkZ = zPos + LAYER_CHECK_DIRS(Y_AXIS, i);
LayerVoxel layer = readLayerVoxel(checkX, checkZ);
if (layer.height > maxHeightSorroundings)
maxHeightSorroundings = layer.height;
}
maxHeightSorroundings++;
if (maxHeightSorroundings >= CHUNK_SIZE_Y * worldProps.chunkSizeY)
maxHeightSorroundings = CHUNK_SIZE_Y * worldProps.chunkSizeY - 1;
ChunkID chunkID;
ChunkVoxelID chunkVoxelID;
// Depending if it's an edge we will add to queue to propagate the light
bool isPositionEdge =
(xPos == minX) || (xPos == maxX) ||
(zPos == minZ) || (zPos == maxZ);
if (xPos == 0 || zPos == 0 || xPos == CHUNK_SIZE_X * worldProps.chunkSizeX - 1
|| zPos == CHUNK_SIZE_Z * worldProps.chunkSizeZ - 1)
isPositionEdge = false;
// All light voxelsInfo under the max height must be put to 0 ambient light and above to 255
// I think this is optional
int yPos = minHeight;
if (!isPositionEdge) {
// Empty the ilumination
for (; yPos < maxHeight; yPos++) {
extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID);
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
VoxelLight& voxelLight = chunk.modLight(chunkVoxelID);
voxelLight.ambient_light = 0;
}
} else {
// Add to queue
for (; yPos < maxHeight; yPos++) {
extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID);
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
VoxelLight voxelLight = chunk.readLight(chunkVoxelID);
if (voxelLight.ambient_light > 0)
ambientLightPropagation.push(VoxelCordinates(xPos, yPos, zPos));
}
}
// Fill with light voxelsInfo and add queue to update light propagation
for (; yPos < maxHeightSorroundings; yPos++) {
extractChunkCordinates(xPos, yPos, zPos, chunkID, chunkVoxelID);
Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
VoxelLight& voxelLight = chunk.modLight(chunkVoxelID);
voxelLight.ambient_light = 255;
ambientLightPropagation.push(VoxelCordinates(xPos, yPos, zPos));
}
modLayerVoxel(xPos, zPos).ambient_light_height = CHUNK_SIZE_Y * worldProps.chunkSizeY;
}
}
//Resolve ambient light propagation
while (!ambientLightPropagation.empty()) {
resolveNextAmbientLightPropagation();
}
}
void VoxelWorld::bakeAmbientLightFromPoint(int x, int z) {
int minX = x - 16;
int maxX = x + 16;
int minZ = z - 16;
int maxZ = z + 16;
minX = (minX < 0) ? 0 : minX;
maxX = (maxX >= worldProps.chunkSizeX * CHUNK_SIZE_X) ? worldProps.chunkSizeX * CHUNK_SIZE_X - 1 : maxX;
minZ = (minZ < 0) ? 0 : minZ;
maxZ = (maxZ >= worldProps.chunkSizeZ * CHUNK_SIZE_Z) ? worldProps.chunkSizeZ * CHUNK_SIZE_Z - 1 : maxZ;
bakeAmbientLight(minX, maxX, minZ, maxZ);
}
void VoxelWorld::resolveNextAmbientLightPropagation() {
VoxelCordinates position = ambientLightPropagation.front();
ambientLightPropagation.pop();
LayerVoxel& layerVoxel = modLayerVoxel(position.x, position.z);
if (layerVoxel.ambient_light_height > position.y)
layerVoxel.ambient_light_height = position.y;
VoxelLight currentLight = readLight(position);
bool solidCheck[6] = { false };
// Check for every simple dir
for (int i = 0; i < 6; i++) {
VoxelCordinates next(
position.x + NORMAL_DIR(X_AXIS, i),
position.y + NORMAL_DIR(Y_AXIS, i),
position.z + NORMAL_DIR(Z_AXIS, i)
);
Voxel nextVoxel = readVoxel(next);
solidCheck[i] = nextVoxel.isVoxelType();
if (solidCheck[i])
continue;
VoxelLight& nextLight = modLight(next);
int nextLightMinValue = currentLight.ambient_light - LIGHT_PROPAGATION_SIMPLE_FALL;
if (nextLight.ambient_light < nextLightMinValue) {
nextLight.ambient_light = nextLightMinValue;
ambientLightPropagation.push(next);
}
}
return;
// TODO
// Check for every complex dir
for (int i = 0; i < 6; i++) {
int cDir0 = LIGHT_PROPAGATION_COMPLEX_DIR(0, i);
int cDir1 = LIGHT_PROPAGATION_COMPLEX_DIR(1, i);
if (solidCheck[cDir0] || solidCheck[cDir1])
continue;
VoxelCordinates next(
NORMAL_DIR(X_AXIS, cDir0) + NORMAL_DIR(X_AXIS, cDir1),
NORMAL_DIR(Y_AXIS, cDir0) + NORMAL_DIR(Y_AXIS, cDir1),
NORMAL_DIR(Z_AXIS, cDir0) + NORMAL_DIR(Z_AXIS, cDir1)
);
Voxel nextVoxel = readVoxel(next);
if (nextVoxel.isVoxelType())
continue;
VoxelLight& nextLight = modLight(next);
int nextLightMinValue = currentLight.ambient_light - LIGHT_PROPAGATION_COMPLEX_FALL;
if (nextLight.ambient_light < nextLightMinValue) {
nextLight.ambient_light = nextLightMinValue;
ambientLightPropagation.push(next);
}
}
}
}