#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); } } } }