diff --git a/Deer/Include/DeerCore/Voxel.h b/Deer/Include/DeerCore/Voxel.h new file mode 100644 index 0000000..b263624 --- /dev/null +++ b/Deer/Include/DeerCore/Voxel.h @@ -0,0 +1,92 @@ +#pragma once +#include "DeerCore/Tools/Memory.h" +#include "DeerCore/Tools/TypeDefs.h" + +#include +#include +#include + +#define CHUNK_VOXEL_SIZE 16 + +#ifdef DEER_RENDER +#include "DeerRender/Resource.h" +namespace Deer { + class VoxelBuilder; + class GPUMesh; +} // namespace Deer +#endif + +namespace Deer { + struct VoxelType { + std::string id; + }; + + struct Chunk { + Chunk() { + Voxel voxel = {.voxelTypeId = 0}; + voxels_list.push_back(voxel); + voxels_reference_map[voxel] = 0; + } + + struct Voxel { + uint32_t voxelTypeId; + + bool operator==(const Voxel& other) const noexcept { + return voxelTypeId == other.voxelTypeId; + } + }; + + struct VoxelHasher { + std::size_t operator()(const Voxel& v) const noexcept { + return std::hash{}(v.voxelTypeId); + } + }; + + std::vector voxels_list; + std::unordered_map voxels_reference_map; + uint16_t reference_matrix[CHUNK_VOXEL_SIZE][CHUNK_VOXEL_SIZE][CHUNK_VOXEL_SIZE]; + + uint16_t getOrCreateVoxelReference(const Voxel& voxel); + Voxel getVoxel(uint16_t voxelReference); + }; + + class VoxelEnvironment { + public: + VoxelEnvironment(); + + void modifyVoxel(uint32_t voxelId, int x, int y, int z); + uint32_t getVoxel(int x, int y, int z); + +#ifdef DEER_RENDER + public: + Resource buildChunk(int x, int y, int z); + Scope voxelBuilder; +#endif + private: + struct ChunkID { + int x, y, z; + + bool operator==(const ChunkID& other) const noexcept { + return x == other.x && + y == other.y && + z == other.z; + } + }; + + struct ChunkIDHasher { + std::size_t operator()(const ChunkID& c) const noexcept { + std::size_t h = 0; + h ^= std::hash{}(c.x) + 0x9e3779b9 + (h << 6) + (h >> 2); + h ^= std::hash{}(c.y) + 0x9e3779b9 + (h << 6) + (h >> 2); + h ^= std::hash{}(c.z) + 0x9e3779b9 + (h << 6) + (h >> 2); + return h; + } + }; + + Chunk* getOrCreateChunk(int x, int y, int z); + Chunk* tryGetChunk(int x, int y, int z); + + std::vector> chunk_list; + std::unordered_map chunk_map; + }; +} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerRender/Mesh.h b/Deer/Include/DeerRender/Mesh.h index aaf1674..ea1a0ab 100644 --- a/Deer/Include/DeerRender/Mesh.h +++ b/Deer/Include/DeerRender/Mesh.h @@ -24,6 +24,12 @@ namespace Deer { VertexUV(float _u, float _v) : u(_u), v(_v) {} }; + struct VertexLight { + uint8_t light; + + VertexLight() = default; + VertexLight(int8_t _u) : light(_u) {} + }; // Vertex normal is represented with a number fromn [-64,64], and then its // divided by 64 to know the decimal number struct VertexNormal { @@ -43,6 +49,7 @@ namespace Deer { vertexCount = count; } void createUVData() { vertexUVData = MakeScope(vertexCount); } + void createLightData() { vertexLightData = MakeScope(vertexCount); } void createIndices(uint32_t count) { indexData = MakeScope(count); indexCount = count; @@ -51,6 +58,7 @@ namespace Deer { inline VertexPosition* getVertexPosition() const { return vertexPositionsData.get(); } inline VertexNormal* getVertexNormal() const { return vertexNormalData.get(); } inline VertexUV* getVertexUV() const { return vertexUVData.get(); } + inline VertexLight* getVertexLight() const { return vertexLightData.get(); } inline uint32_t* getIndexData() const { return indexData.get(); } inline uint32_t getVertexCount() const { return vertexCount; } @@ -61,6 +69,7 @@ namespace Deer { Scope vertexPositionsData; Scope vertexNormalData; Scope vertexUVData; + Scope vertexLightData; uint32_t indexCount = 0; Scope indexData; diff --git a/Deer/Include/DeerRender/RenderPiperline.h b/Deer/Include/DeerRender/RenderPiperline.h deleted file mode 100644 index 8ab5d13..0000000 --- a/Deer/Include/DeerRender/RenderPiperline.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "DeerRender/EntityEnviroment.h" -#include "DeerRender/Render/FrameBuffer.h" -#include "DeerRender/Tools/Memory.h" - -namespace Deer { - class RenderPiperline { - public: - RenderPiperline(RenderPiperline&) = delete; - RenderPiperline(PiperlineOptions); - - void render(const EntityEnvironment&); - - private: - Scope resultImage; - PiperlineOptions options; - }; - - struct PiperlineOptions { - int width = 100; - int height = 100; - }; -} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerRender/Voxel.h b/Deer/Include/DeerRender/Voxel.h new file mode 100644 index 0000000..9a6bfb0 --- /dev/null +++ b/Deer/Include/DeerRender/Voxel.h @@ -0,0 +1,78 @@ +#pragma once +#include "DeerCore/Voxel.h" + +#include "DeerRender/Mesh.h" +#include "glm/glm.hpp" + +#include +#include + +namespace Deer { + struct VoxelVertex { + VoxelVertex() = default; + VoxelVertex(glm::vec3 _position) : position(_position) {} + + glm::vec3 position; + }; + + struct VoxelFaceData { + // Basic construction + std::vector vertices; + std::vector triangles; + + std::array, 4> connections; + std::array edges; + }; + + class VoxelBuilder { + public: + Resource buildChunk(int x, int y, int z); + + VoxelBuilder(VoxelEnvironment* env) : environment(env) {} + + private: + struct VoxelData { + int16_t vertexIndexFace[6] = {-1, -1, -1, -1, -1, -1}; + }; + + struct VertexData { + glm::vec3 position; + glm::vec3 normal; + float extrussion; + float light; + }; + + private: + void addFace(VoxelFaceData& data, glm::vec3 origin, glm::vec3 up, glm::vec3 right); + void calculateNormals(); + + void buildVertices(); + void buildFaceVertices(int x, int y, int z, int face); + + void buildConnections(); + void buildAxisConnections(int x, int y, int z); + void connectVertices(VoxelFaceData& face1, int edgeIndex1, int face1VertexOffset, VoxelFaceData& face2, int edgeIndex2, int face2VertexOffset); + + void buildMarchingCubesCorners(); + void buildMarchingVoxel(int x, int y, int z, uint8_t marchingCubeId); + int getVertexIdCorner(int x, int y, int z, int edge); + + VoxelData& getVoxelData(int x, int y, int z); + void clearVoxelData(); + + bool hasBlock(int x, int y, int z); + float calculateVertexSunLight(int x, int y, int z); + + std::vector vertices; + std::vector indices; + + int voxelXOffset; + int voxelYOffset; + int voxelZOffset; + + VoxelEnvironment* environment; + VoxelData voxelData[CHUNK_VOXEL_SIZE + 2][CHUNK_VOXEL_SIZE + 2][CHUNK_VOXEL_SIZE + 2]; + + friend VoxelEnvironment; + }; +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerCore/Voxel/Chunk.cpp b/Deer/src/DeerCore/Voxel/Chunk.cpp new file mode 100644 index 0000000..966064f --- /dev/null +++ b/Deer/src/DeerCore/Voxel/Chunk.cpp @@ -0,0 +1,16 @@ +#include "DeerCore/Voxel.h" + +namespace Deer { + uint16_t Chunk::getOrCreateVoxelReference(const Voxel& voxel) { + if (voxels_reference_map.contains(voxel)) + return voxels_reference_map[voxel]; + + voxels_list.push_back(voxel); + voxels_reference_map[voxel] = voxels_list.size() - 1; + return voxels_list.size() - 1; + } + + Chunk::Voxel Chunk::getVoxel(uint16_t voxelReference) { + return voxels_list[voxelReference]; + } +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerCore/Voxel/VoxelEnvironment.cpp b/Deer/src/DeerCore/Voxel/VoxelEnvironment.cpp new file mode 100644 index 0000000..489dc3c --- /dev/null +++ b/Deer/src/DeerCore/Voxel/VoxelEnvironment.cpp @@ -0,0 +1,91 @@ +#include "DeerCore/Voxel.h" + +namespace Deer { + namespace Voxel { + int getChunk(int id) { + int chunk = id / CHUNK_VOXEL_SIZE; + + // Fix truncation toward zero for negatives + if (id < 0 && id % CHUNK_VOXEL_SIZE != 0) + --chunk; + + return chunk; + } + + int getBlock(int id) { + int block = id % CHUNK_VOXEL_SIZE; + + // Make remainder positive + if (block < 0) + block += CHUNK_VOXEL_SIZE; + + return block; + } + } // namespace Voxel + + Chunk* VoxelEnvironment::getOrCreateChunk(int x, int y, int z) { + ChunkID chunkId = { + .x = Voxel::getChunk(x), + .y = Voxel::getChunk(y), + .z = Voxel::getChunk(z)}; + + if (chunk_map.contains(chunkId)) + return chunk_map[chunkId]; + + // Should do stuff but we relax for the moment + chunk_list.push_back(MakeScope()); + Chunk* chunk = chunk_list.back().get(); + chunk_map[chunkId] = chunk; + + for (int x = 0; x < CHUNK_VOXEL_SIZE; x++) { + for (int y = 0; y < CHUNK_VOXEL_SIZE; y++) { + for (int z = 0; z < CHUNK_VOXEL_SIZE; z++) { + chunk->reference_matrix[x][y][z] = 0; + } + } + } + + return chunk; + } + + Chunk* VoxelEnvironment::tryGetChunk(int x, int y, int z) { + ChunkID chunkId = { + .x = Voxel::getChunk(x), + .y = Voxel::getChunk(y), + .z = Voxel::getChunk(z)}; + + if (chunk_map.contains(chunkId)) + return chunk_map[chunkId]; + + return nullptr; + } + + void VoxelEnvironment::modifyVoxel(uint32_t voxelId, int x, int y, int z) { + Chunk* chunk = getOrCreateChunk(x, y, z); + + Chunk::Voxel voxel = {.voxelTypeId = voxelId}; + + uint16_t voxelRef = chunk->getOrCreateVoxelReference(voxel); + + int posX = Voxel::getBlock(x); + int posY = Voxel::getBlock(y); + int posZ = Voxel::getBlock(z); + + chunk->reference_matrix[posX][posY][posZ] = voxelRef; + } + + uint32_t VoxelEnvironment::getVoxel(int x, int y, int z) { + Chunk* chunk = tryGetChunk(x, y, z); + + if (!chunk) + return 0; + + int posX = Voxel::getBlock(x); + int posY = Voxel::getBlock(y); + int posZ = Voxel::getBlock(z); + + uint16_t voxelRef = chunk->reference_matrix[posX][posY][posZ]; + return chunk->getVoxel(voxelRef).voxelTypeId; + } + +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Mesh/MeshResource.cpp b/Deer/src/DeerRender/Mesh/MeshResource.cpp index c606855..fc641e4 100644 --- a/Deer/src/DeerRender/Mesh/MeshResource.cpp +++ b/Deer/src/DeerRender/Mesh/MeshResource.cpp @@ -34,7 +34,15 @@ namespace Deer { vertexNormalBuffer->setLayout(normalLayout); vertexArray->addVertexBuffer(vertexNormalBuffer); - if (data.getVertexPosition()) { + if (data.getVertexLight()) { + BufferLayout lightLayout({{"v_Light", DataType::Unsigned_Byte, ShaderDataType::FloatingPoint}}, sizeof(VertexLight)); + Ref vertexLightBuffer = VertexBuffer::create(data.getVertexLight(), data.getVertexCount() * sizeof(VertexLight)); + vertexLightBuffer->bind(); + vertexLightBuffer->setLayout(lightLayout); + vertexArray->addVertexBuffer(vertexLightBuffer); + } + + if (data.getVertexUV()) { BufferLayout uvLayout({{"v_UV", DataType::Float2, ShaderDataType::FloatingPoint}}, sizeof(VertexUV)); Ref vertexUVBuffer = VertexBuffer::create(data.getVertexUV(), data.getVertexCount() * sizeof(VertexUV)); vertexUVBuffer->bind(); diff --git a/Deer/src/DeerRender/Voxel/VoxelBuilder.cpp b/Deer/src/DeerRender/Voxel/VoxelBuilder.cpp new file mode 100644 index 0000000..9a1a0b3 --- /dev/null +++ b/Deer/src/DeerRender/Voxel/VoxelBuilder.cpp @@ -0,0 +1,428 @@ +#include "DeerCore/Log.h" +#include "DeerRender/Voxel.h" +#include "DeerRender/Voxel/VoxelData.h" +#include + +namespace Deer { + + VoxelFaceData testFaceData = { + .vertices = { + VoxelVertex(glm::vec3(0.1f, 0.90f, 0.1f)), // 0 + VoxelVertex(glm::vec3(0.5f, 0.90f, 0.1f)), // 1 + VoxelVertex(glm::vec3(0.9f, 0.90f, 0.1f)), // 2 + VoxelVertex(glm::vec3(0.1f, 0.6f, 0.2f)), // 3 + VoxelVertex(glm::vec3(0.5f, 0.35f, 0.2f)), // 4 + VoxelVertex(glm::vec3(0.9f, 0.6f, 0.2f)), // 5 + VoxelVertex(glm::vec3(0.1f, 0.55f, 0)), // 3 + VoxelVertex(glm::vec3(0.5f, 0.3f, 0)), // 4 + VoxelVertex(glm::vec3(0.9f, 0.55f, 0)), // 5 + VoxelVertex(glm::vec3(0.1f, 0.1f, 0)), // 6 + VoxelVertex(glm::vec3(0.5f, 0.1f, 0)), // 7 + VoxelVertex(glm::vec3(0.9f, 0.1f, 0)), // 8 + }, + .triangles = {0, 1, 3, 3, 1, 4, 5, 1, 2, 1, 5, 4, 3, 4, 7, 3, 7, 6, 5, 8, 4, 4, 8, 7, 6, 7, 9, 7, 10, 9, 8, 11, 7, 7, 11, 10}, + .connections = { + std::vector{9, 6, 3, 0}, // [0] + std::vector{2, 5, 8, 11}, // [1] + std::vector{11, 10, 9}, // [2] + std::vector{0, 1, 2} // [3] + }, + .edges = {9, 11, 0, 2}}; + + VoxelFaceData flatFaceData = { + .vertices = { + VoxelVertex(glm::vec3(0.3f, 0.3f, 0)), + VoxelVertex(glm::vec3(0.7f, 0.3f, 0)), + VoxelVertex(glm::vec3(0.3f, 0.7f, 0)), + VoxelVertex(glm::vec3(0.7f, 0.7f, 0)), + }, + .triangles = {0, 2, 1, 1, 2, 3}, + .connections = { + std::vector{0, 2}, // [0] + std::vector{3, 1}, // [1] + std::vector{1, 0}, // [2] + std::vector{2, 3} // [3] + }, + .edges = {0, 1, 2, 3}}; + /* + VoxelFaceData testFaceData = { + .vertices = { + VoxelVertex(glm::vec2(0.1f, 0.95f)), // 0 + VoxelVertex(glm::vec2(0.4f, 0.8f)), // 1 + VoxelVertex(glm::vec2(0.9f, 0.95f)), // 2 + VoxelVertex(glm::vec2(0.2f, 0.5f)), // 3 + VoxelVertex(glm::vec2(0.5f, 0.6f)), // 4 + VoxelVertex(glm::vec2(0.8f, 0.4f)), // 5 + VoxelVertex(glm::vec2(0.1f, 0.1f)), // 6 + VoxelVertex(glm::vec2(0.6f, 0.1f)), // 7 + VoxelVertex(glm::vec2(0.9f, 0.1f)), // 8 + }, + .triangles = {0, 1, 3, 1, 4, 3, 1, 2, 5, 1, 5, 4, 6, 3, 4, 6, 4, 7, 4, 5, 7, 7, 5, 8}, + .connections = { + std::vector{6, 3, 0}, // [0] + std::vector{2, 5, 8}, // [1] + std::vector{8, 7, 6}, // [2] + std::vector{0, 1, 2} // [3] + }, + .edges = {6, 8, 0, 2}}; + + VoxelFaceData testFaceData = { + .vertices = { + VoxelVertex(glm::vec2(0.1f, 0.1f)), + VoxelVertex(glm::vec2(0.9f, 0.1f)), + VoxelVertex(glm::vec2(0.1f, 0.9f)), + VoxelVertex(glm::vec2(0.9f, 0.9f)), + }, + .triangles = {0, 2, 1, 1, 2, 3}, + .connections = { + std::vector{0, 2}, // [0] + std::vector{3, 1}, // [1] + std::vector{1, 0}, // [2] + std::vector{2, 3} // [3] + }, + .edges = {0, 1, 2, 3}}; + */ + + void VoxelBuilder::calculateNormals() { + for (uint32_t indexId = 0; indexId < indices.size(); indexId += 3) { + glm::vec3 startIndex = vertices[indices[indexId + 0]].position; + glm::vec3 direction1 = vertices[indices[indexId + 1]].position - startIndex; + glm::vec3 direction2 = vertices[indices[indexId + 2]].position - startIndex; + + glm::vec3 normal = glm::cross(direction1, direction2); + vertices[indices[indexId + 0]].normal += normal; + vertices[indices[indexId + 1]].normal += normal; + vertices[indices[indexId + 2]].normal += normal; + } + } + + Resource VoxelBuilder::buildChunk(int x, int y, int z) { + voxelXOffset = x; + voxelYOffset = y; + voxelZOffset = z; + + vertices.clear(); + indices.clear(); + clearVoxelData(); + + buildVertices(); + buildConnections(); + buildMarchingCubesCorners(); + + calculateNormals(); + + for (size_t i = 0; i < vertices.size(); i++) { + float randomValue = (float)(rand() % 1000) / 10000.0f - 0.05f; + randomValue = 0; + glm::vec3 normal = glm::normalize(vertices[i].normal); + vertices[i].position += normal * randomValue + normal * vertices[i].extrussion; + } + + calculateNormals(); + + MeshData meshData; + meshData.createVertices(vertices.size()); + meshData.createIndices(indices.size()); + meshData.createLightData(); + + DEER_CORE_TRACE("{} , {}", meshData.getVertexCount(), meshData.getIndexCount()); + for (size_t i = 0; i < meshData.getVertexCount(); i++) { + meshData.getVertexPosition()[i].x = vertices[i].position.x; + meshData.getVertexPosition()[i].y = vertices[i].position.y; + meshData.getVertexPosition()[i].z = vertices[i].position.z; + + glm::vec3 normal = glm::normalize(vertices[i].normal); + meshData.getVertexNormal()[i].x = (uint8_t)(normal.x * 64); + meshData.getVertexNormal()[i].y = (uint8_t)(normal.y * 64); + meshData.getVertexNormal()[i].z = (uint8_t)(normal.z * 64); + + meshData.getVertexLight()[i].light = (uint8_t)(vertices[i].light * 255.0f); + } + + for (size_t i = 0; i < meshData.getIndexCount(); i++) { + meshData.getIndexData()[i] = indices[i]; + } + + return ResourceManager::loadResourceFromData(meshData, "tmp&&"); + } + + VoxelBuilder::VoxelData& VoxelBuilder::getVoxelData(int x, int y, int z) { + return voxelData[x + 1][y + 1][z + 1]; + } + + void VoxelBuilder::clearVoxelData() { + for (int x = 0; x < CHUNK_VOXEL_SIZE + 2; x++) { + for (int y = 0; y < CHUNK_VOXEL_SIZE + 2; y++) { + for (int z = 0; z < CHUNK_VOXEL_SIZE + 2; z++) { + voxelData[x][y][z] = VoxelData(); + } + } + } + } + + bool VoxelBuilder::hasBlock(int x, int y, int z) { + uint32_t voxelId = environment->getVoxel(x, y, z); + return voxelId > 0; + } + + float VoxelBuilder::calculateVertexSunLight(int x, int y, int z) { + float acumulatedLight = 0; + for (int i = 0; i < 8; i++) { + if (!hasBlock(x + Voxel::voxelCheckOrder[i][0], + y + Voxel::voxelCheckOrder[i][1], + z + Voxel::voxelCheckOrder[i][2])) + acumulatedLight += 1.0f / 4.0f; + } + if (acumulatedLight < 1) + return acumulatedLight; + return 1; + } + + void VoxelBuilder::buildVertices() { + for (int x = 0; x < CHUNK_VOXEL_SIZE; x++) { + for (int y = 0; y < CHUNK_VOXEL_SIZE; y++) { + for (int z = 0; z < CHUNK_VOXEL_SIZE; z++) { + if (!hasBlock(x, y, z)) + continue; + + for (int i = 0; i < 6; i++) { + if (!hasBlock( + x + Voxel::faceNeighborOffset[i][0], + y + Voxel::faceNeighborOffset[i][1], + z + Voxel::faceNeighborOffset[i][2])) { + buildFaceVertices(x, y, z, i); + } + } + } + } + } + } + + void VoxelBuilder::buildFaceVertices(int x, int y, int z, int face) { + uint32_t startIndex = vertices.size(); + getVoxelData(x, y, z).vertexIndexFace[face] = startIndex; + + VoxelFaceData* faceData = &testFaceData; + if (face == 2 || face == 3) + faceData = &flatFaceData; + + float cornersLight[4]; + cornersLight[0] = calculateVertexSunLight(x + Voxel::faceOriginVectorInt[face][0], + y + Voxel::faceOriginVectorInt[face][1], + z + Voxel::faceOriginVectorInt[face][2]); + cornersLight[1] = calculateVertexSunLight(x + Voxel::faceOriginVectorInt[face][0] + Voxel::faceRightVector[face][0], + y + Voxel::faceOriginVectorInt[face][1] + Voxel::faceRightVector[face][1], + z + Voxel::faceOriginVectorInt[face][2] + Voxel::faceRightVector[face][2]); + cornersLight[2] = calculateVertexSunLight(x + Voxel::faceOriginVectorInt[face][0] + Voxel::faceUpVectorInt[face][0], + y + Voxel::faceOriginVectorInt[face][1] + Voxel::faceUpVectorInt[face][1], + z + Voxel::faceOriginVectorInt[face][2] + Voxel::faceUpVectorInt[face][2]); + cornersLight[3] = calculateVertexSunLight(x + Voxel::faceOriginVectorInt[face][0] + Voxel::faceUpVectorInt[face][0] + Voxel::faceRightVector[face][0], + y + Voxel::faceOriginVectorInt[face][1] + Voxel::faceUpVectorInt[face][1] + Voxel::faceRightVector[face][1], + z + Voxel::faceOriginVectorInt[face][2] + Voxel::faceUpVectorInt[face][2] + Voxel::faceRightVector[face][2]); + + for (VoxelVertex& voxelVertex : faceData->vertices) { + glm::vec3 vertexPosition = glm::vec3(x, y, z) + Voxel::faceOriginVector[face]; + glm::vec3 up = Voxel::faceUpVector[face]; + glm::vec3 right = Voxel::faceRightVector[face]; + + vertexPosition += up * voxelVertex.position.y; + vertexPosition += right * voxelVertex.position.x; + + glm::vec3 perpendicular = glm::cross(up, right); + + float topLight = Voxel::lerp(voxelVertex.position.x, cornersLight[3], cornersLight[2]); + float bottomLight = Voxel::lerp(voxelVertex.position.x, cornersLight[1], cornersLight[0]); + + vertices.push_back({}); + VertexData& vv = vertices.back(); + vv.position = vertexPosition; + vv.extrussion = voxelVertex.position.z; + vv.light = Voxel::lerp(voxelVertex.position.y, topLight, bottomLight); + } + + for (uint32_t index : faceData->triangles) { + indices.push_back(index + startIndex); + } + } + + // This function goes foreach edge, from (0, 0, 0) to (33, 33, 33) then check each edge + void VoxelBuilder::buildConnections() { + for (int x = 0; x < CHUNK_VOXEL_SIZE + 1; x++) { + for (int y = 0; y < CHUNK_VOXEL_SIZE + 1; y++) { + for (int z = 0; z < CHUNK_VOXEL_SIZE + 1; z++) { + buildAxisConnections(x, y, z); + } + } + } + } + + void VoxelBuilder::buildAxisConnections(int x, int y, int z) { + for (int axis = 0; axis < AXIS_NUMBER; axis++) { + uint8_t edgeCheckBitmask = 0; + for (int edge = 0; edge < EDGE_PER_AXIS; edge++) { + uint8_t currentEdgeBitmask = 1 << edge; + if (edgeCheckBitmask & currentEdgeBitmask) + continue; + + Voxel::VoxelEdge& voxelEdge = Voxel::edgesPerAxis[axis][edge]; + VoxelData& voxel = getVoxelData(x + voxelEdge.voxelOffset[0], + y + voxelEdge.voxelOffset[1], + z + voxelEdge.voxelOffset[2]); + bool existsFace = voxel.vertexIndexFace[voxelEdge.faceIndex] >= 0; + + edgeCheckBitmask |= currentEdgeBitmask; + if (!existsFace) + continue; + + int edgeCheckIndex = edge; + for (int safeCheck = 0; safeCheck < EDGE_PER_AXIS - 1; safeCheck++) { + edgeCheckIndex += voxelEdge.isClockwiseOrder ? 1 : -1; + + if (edgeCheckIndex >= EDGE_PER_AXIS) + edgeCheckIndex -= EDGE_PER_AXIS; + + if (edgeCheckIndex < 0) + edgeCheckIndex += EDGE_PER_AXIS; + + uint8_t nextEdgeBitmask = 1 << edgeCheckIndex; + if (nextEdgeBitmask & edgeCheckBitmask) + continue; + + edgeCheckBitmask |= nextEdgeBitmask; + + Voxel::VoxelEdge& nextVoxelEdge = Voxel::edgesPerAxis[axis][edgeCheckIndex]; + VoxelData& nextVoxel = getVoxelData(x + nextVoxelEdge.voxelOffset[0], + y + nextVoxelEdge.voxelOffset[1], + z + nextVoxelEdge.voxelOffset[2]); + + bool nextEdgeExist = nextVoxel.vertexIndexFace[nextVoxelEdge.faceIndex] >= 0; + if (nextEdgeExist) { + + VoxelFaceData* faceData1 = &testFaceData; + if (voxelEdge.faceIndex == 2 || voxelEdge.faceIndex == 3) + faceData1 = &flatFaceData; + + VoxelFaceData* faceData2 = &testFaceData; + if (nextVoxelEdge.faceIndex == 2 || nextVoxelEdge.faceIndex == 3) + faceData2 = &flatFaceData; + + connectVertices(*faceData1, voxelEdge.edgeIndex, voxel.vertexIndexFace[voxelEdge.faceIndex], + *faceData2, nextVoxelEdge.edgeIndex, nextVoxel.vertexIndexFace[nextVoxelEdge.faceIndex]); + break; + } + } + } + } + } + + void VoxelBuilder::connectVertices(VoxelFaceData& face1, int edgeIndex1, int face1VertexOffset, VoxelFaceData& face2, int edgeIndex2, int face2VertexOffset) { + int edge1Index = 0; + int edge2Index = face2.connections[edgeIndex2].size() - 1; + + int triangleCount = 0; + while (edge1Index < face1.connections[edgeIndex1].size() - 1 || edge2Index > 0) { + triangleCount++; + if (edge1Index == face1.connections[edgeIndex1].size() - 1) { + indices.push_back(face1VertexOffset + face1.connections[edgeIndex1][edge1Index]); + indices.push_back(face2VertexOffset + face2.connections[edgeIndex2][edge2Index]); + indices.push_back(face2VertexOffset + face2.connections[edgeIndex2][edge2Index - 1]); + + edge2Index--; + } else if (edge2Index == 0) { + indices.push_back(face2VertexOffset + face2.connections[edgeIndex2][edge2Index]); + indices.push_back(face1VertexOffset + face1.connections[edgeIndex1][edge1Index + 1]); + indices.push_back(face1VertexOffset + face1.connections[edgeIndex1][edge1Index]); + + edge1Index++; + } else { + glm::vec3 firstEdgeVertex = vertices[face1.connections[edgeIndex1][edge1Index] + face1VertexOffset].position; + glm::vec3 secondEdgeVertex = vertices[face2.connections[edgeIndex2][edge2Index] + face2VertexOffset].position; + + glm::vec3 midPoint = (firstEdgeVertex + secondEdgeVertex) * 0.5f; + + glm::vec3 FED = vertices[face1.connections[edgeIndex1][edge1Index + 1] + face1VertexOffset].position - midPoint; + glm::vec3 SED = vertices[face2.connections[edgeIndex2][edge2Index - 1] + face2VertexOffset].position - midPoint; + + float firstDistanceNext = FED.x * FED.x + FED.y * FED.y + FED.z * FED.z; + float secondDistanceNext = SED.x * SED.x + SED.y * SED.y + SED.z * SED.z; + + if (firstDistanceNext > secondDistanceNext) { + indices.push_back(face1VertexOffset + face1.connections[edgeIndex1][edge1Index]); + indices.push_back(face2VertexOffset + face2.connections[edgeIndex2][edge2Index]); + indices.push_back(face2VertexOffset + face2.connections[edgeIndex2][edge2Index - 1]); + + edge2Index--; + } else { + indices.push_back(face1VertexOffset + face1.connections[edgeIndex1][edge1Index]); + indices.push_back(face2VertexOffset + face2.connections[edgeIndex2][edge2Index]); + indices.push_back(face1VertexOffset + face1.connections[edgeIndex1][edge1Index + 1]); + + edge1Index++; + } + } + } + } + + void VoxelBuilder::buildMarchingCubesCorners() { + for (int x = 0; x < CHUNK_VOXEL_SIZE + 1; x++) { + for (int y = 0; y < CHUNK_VOXEL_SIZE + 1; y++) { + for (int z = 0; z < CHUNK_VOXEL_SIZE + 1; z++) { + uint8_t marchingCubeId = 0; + for (int side = 0; side < CUBE_SIDES; side++) { + bool hasVoxel = hasBlock(x + Voxel::voxelCheckOrder[side][0], + y + Voxel::voxelCheckOrder[side][1], + z + Voxel::voxelCheckOrder[side][2]); + + if (hasVoxel) + marchingCubeId |= 1 << side; + } + + if (marchingCubeId == 0) + continue; + + buildMarchingVoxel(x, y, z, marchingCubeId); + } + } + } + } + + void VoxelBuilder::buildMarchingVoxel(int x, int y, int z, uint8_t marchingCubeId) { + for (int safeStop = 0; safeStop < 16; safeStop += 3) { + int nextMarchingCubesedgeIndex = Voxel::marchingCubesTriTable[marchingCubeId][safeStop]; + if (nextMarchingCubesedgeIndex == -1) + return; + + int vertices[3] = { + getVertexIdCorner(x, y, z, nextMarchingCubesedgeIndex), + getVertexIdCorner(x, y, z, Voxel::marchingCubesTriTable[marchingCubeId][safeStop + 1]), + getVertexIdCorner(x, y, z, Voxel::marchingCubesTriTable[marchingCubeId][safeStop + 2]), + }; + + if (vertices[0] != -1 && vertices[1] != -1 && vertices[2] != -1) { + indices.push_back(vertices[0]); + indices.push_back(vertices[1]); + indices.push_back(vertices[2]); + } + } + } + + int VoxelBuilder::getVertexIdCorner(int x, int y, int z, int edge) { + for (int i = 0; i < 2; i++) { + Voxel::VoxelCorner& option = Voxel::marchingCubesEdgeCornerPairs[edge][i]; + + VoxelData& _voxelData = getVoxelData(x + option.voxelOffset[0], + y + option.voxelOffset[1], + z + option.voxelOffset[2]); + + VoxelFaceData* faceData = &testFaceData; + if (option.faceIndex == 2 || option.faceIndex == 3) + faceData = &flatFaceData; + + int voxelDataFaceOffset = _voxelData.vertexIndexFace[option.faceIndex]; + if (voxelDataFaceOffset >= 0) + return faceData->edges[option.localCornerIndex] + voxelDataFaceOffset; + } + + return -1; + } +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxel/VoxelData.h b/Deer/src/DeerRender/Voxel/VoxelData.h new file mode 100644 index 0000000..182030d --- /dev/null +++ b/Deer/src/DeerRender/Voxel/VoxelData.h @@ -0,0 +1,50 @@ +#pragma once +#include "glm/glm.hpp" + +#define EDGE_PER_AXIS 8 +#define AXIS_NUMBER 3 +#define CUBE_SIDES 8 + +namespace Deer { + namespace Voxel { + // Represents an edge of a voxel along a specific axis + struct VoxelEdge { + int voxelOffset[3]; + int faceIndex; + int edgeIndex; + bool isClockwiseOrder; + }; + + struct VoxelCorner { + int voxelOffset[3]; + int faceIndex; + int localCornerIndex; + }; + + inline float lerp(float v, float a, float b) { + return b + (a - b) * v; + } + + // Direction vectors for checking neighboring voxels along each face + extern int faceNeighborOffset[6][3]; + + // Local "up" vector for each face of the voxel + extern glm::vec3 faceUpVector[6]; + extern int faceUpVectorInt[6][3]; + + // Local "right" vector for each face of the voxel + extern glm::vec3 faceRightVector[6]; + extern int faceRightVectorInt[6][3]; + + // Offset to the voxel face position relative to voxel center + extern glm::vec3 faceOriginVector[6]; + extern int faceOriginVectorInt[6][3]; + + extern VoxelEdge edgesPerAxis[AXIS_NUMBER][EDGE_PER_AXIS]; + extern int marchingCubesTriTable[256][16]; + + extern VoxelCorner marchingCubesEdgeCornerPairs[12][2]; + + extern int voxelCheckOrder[CUBE_SIDES][3]; + } // namespace Voxel +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxel/VoxelEnvironment.cpp b/Deer/src/DeerRender/Voxel/VoxelEnvironment.cpp new file mode 100644 index 0000000..7c9d352 --- /dev/null +++ b/Deer/src/DeerRender/Voxel/VoxelEnvironment.cpp @@ -0,0 +1,7 @@ +#include "DeerRender/Voxel.h" + +namespace Deer { + VoxelEnvironment::VoxelEnvironment() { + voxelBuilder = MakeScope(this); + } +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Voxel/VoxelGenerationData.cpp b/Deer/src/DeerRender/Voxel/VoxelGenerationData.cpp new file mode 100644 index 0000000..d628fe3 --- /dev/null +++ b/Deer/src/DeerRender/Voxel/VoxelGenerationData.cpp @@ -0,0 +1,534 @@ +#include "DeerRender/Voxel/VoxelData.h" + +namespace Deer { + namespace Voxel { + // Direction vectors for checking neighboring voxels along each face + int faceNeighborOffset[6][3] = { + {-1, 0, 0}, // Left + {1, 0, 0}, // Right + {0, -1, 0}, // Bottom + {0, 1, 0}, // Top + {0, 0, -1}, // Back + {0, 0, 1} // Front + }; + + // Local "up" vector for each face of the voxel + glm::vec3 faceUpVector[6] = { + glm::vec3(0, 1, 0), // Left + glm::vec3(0, 1, 0), // Right + glm::vec3(0, 0, -1), // Bottom + glm::vec3(0, 0, 1), // Top + glm::vec3(0, 1, 0), // Back + glm::vec3(0, 1, 0) // Front + }; + int faceUpVectorInt[6][3] = { + {0, 1, 0}, + {0, 1, 0}, // Right + {0, 0, -1}, // Bottom + {0, 0, 1}, // Top + {0, 1, 0}, // Back + {0, 1, 0} // Front + }; + + // Local "right" vector for each face of the voxel + glm::vec3 faceRightVector[6] = { + glm::vec3(0, 0, -1), // Left + glm::vec3(0, 0, 1), // Right + glm::vec3(1, 0, 0), // Bottom + glm::vec3(1, 0, 0), // Top + glm::vec3(1, 0, 0), // Back + glm::vec3(-1, 0, 0) // Front + }; + int faceRightVectorInt[6][3] = { + {0, 0, -1}, // Left + {0, 0, 1}, // Right + {1, 0, 0}, // Bottom + {1, 0, 0}, // Top + {1, 0, 0}, // Back + {-1, 0, 0} // Front + }; + + // Offset to the voxel face position relative to voxel center + glm::vec3 faceOriginVector[6] = { + glm::vec3(-0.5f, -0.5f, 0.5f), // Left + glm::vec3(0.5f, -0.5f, -0.5f), // Right + glm::vec3(-0.5f, -0.5f, 0.5f), // Bottom + glm::vec3(-0.5f, 0.5f, -0.5f), // Top + glm::vec3(-0.5f, -0.5f, -0.5f), // Back + glm::vec3(0.5f, -0.5f, 0.5f) // Front + }; + + extern int faceOriginVectorInt[6][3] = { + {0, 0, 1}, // Left + {1, 0, 0}, // Right + {0, 0, 1}, // Bottom + {0, 1, 0}, // Top + {0, 0, 0}, // Back + {1, 0, 1} // Front + }; + + int voxelCheckOrder[CUBE_SIDES][3]{ + {-1, -1, -1}, + {0, -1, -1}, + {-1, 0, -1}, + {0, 0, -1}, + {-1, -1, 0}, + {0, -1, 0}, + {-1, 0, 0}, + {0, 0, 0}}; + + // For each MC case, a list of triangles, specified as triples of edge indices, terminated by -1 + int marchingCubesTriTable[256][16] = { + {-1}, + {0, 3, 8, -1}, + {0, 9, 1, -1}, + {3, 8, 1, 1, 8, 9, -1}, + {2, 11, 3, -1}, + {8, 0, 11, 11, 0, 2, -1}, + {3, 2, 11, 1, 0, 9, -1}, + {11, 1, 2, 11, 9, 1, 11, 8, 9, -1}, + {1, 10, 2, -1}, + {0, 3, 8, 2, 1, 10, -1}, + {10, 2, 9, 9, 2, 0, -1}, + {8, 2, 3, 8, 10, 2, 8, 9, 10, -1}, + {11, 3, 10, 10, 3, 1, -1}, + {10, 0, 1, 10, 8, 0, 10, 11, 8, -1}, + {9, 3, 0, 9, 11, 3, 9, 10, 11, -1}, + {8, 9, 11, 11, 9, 10, -1}, + {4, 8, 7, -1}, + {7, 4, 3, 3, 4, 0, -1}, + {4, 8, 7, 0, 9, 1, -1}, + {1, 4, 9, 1, 7, 4, 1, 3, 7, -1}, + {8, 7, 4, 11, 3, 2, -1}, + {4, 11, 7, 4, 2, 11, 4, 0, 2, -1}, + {0, 9, 1, 8, 7, 4, 11, 3, 2, -1}, + {7, 4, 11, 11, 4, 2, 2, 4, 9, 2, 9, 1, -1}, + {4, 8, 7, 2, 1, 10, -1}, + {7, 4, 3, 3, 4, 0, 10, 2, 1, -1}, + {10, 2, 9, 9, 2, 0, 7, 4, 8, -1}, + {10, 2, 3, 10, 3, 4, 3, 7, 4, 9, 10, 4, -1}, + {1, 10, 3, 3, 10, 11, 4, 8, 7, -1}, + {10, 11, 1, 11, 7, 4, 1, 11, 4, 1, 4, 0, -1}, + {7, 4, 8, 9, 3, 0, 9, 11, 3, 9, 10, 11, -1}, + {7, 4, 11, 4, 9, 11, 9, 10, 11, -1}, + {9, 4, 5, -1}, + {9, 4, 5, 8, 0, 3, -1}, + {4, 5, 0, 0, 5, 1, -1}, + {5, 8, 4, 5, 3, 8, 5, 1, 3, -1}, + {9, 4, 5, 11, 3, 2, -1}, + {2, 11, 0, 0, 11, 8, 5, 9, 4, -1}, + {4, 5, 0, 0, 5, 1, 11, 3, 2, -1}, + {5, 1, 4, 1, 2, 11, 4, 1, 11, 4, 11, 8, -1}, + {1, 10, 2, 5, 9, 4, -1}, + {9, 4, 5, 0, 3, 8, 2, 1, 10, -1}, + {2, 5, 10, 2, 4, 5, 2, 0, 4, -1}, + {10, 2, 5, 5, 2, 4, 4, 2, 3, 4, 3, 8, -1}, + {11, 3, 10, 10, 3, 1, 4, 5, 9, -1}, + {4, 5, 9, 10, 0, 1, 10, 8, 0, 10, 11, 8, -1}, + {11, 3, 0, 11, 0, 5, 0, 4, 5, 10, 11, 5, -1}, + {4, 5, 8, 5, 10, 8, 10, 11, 8, -1}, + {8, 7, 9, 9, 7, 5, -1}, + {3, 9, 0, 3, 5, 9, 3, 7, 5, -1}, + {7, 0, 8, 7, 1, 0, 7, 5, 1, -1}, + {7, 5, 3, 3, 5, 1, -1}, + {5, 9, 7, 7, 9, 8, 2, 11, 3, -1}, + {2, 11, 7, 2, 7, 9, 7, 5, 9, 0, 2, 9, -1}, + {2, 11, 3, 7, 0, 8, 7, 1, 0, 7, 5, 1, -1}, + {2, 11, 1, 11, 7, 1, 7, 5, 1, -1}, + {8, 7, 9, 9, 7, 5, 2, 1, 10, -1}, + {10, 2, 1, 3, 9, 0, 3, 5, 9, 3, 7, 5, -1}, + {7, 5, 8, 5, 10, 2, 8, 5, 2, 8, 2, 0, -1}, + {10, 2, 5, 2, 3, 5, 3, 7, 5, -1}, + {8, 7, 5, 8, 5, 9, 11, 3, 10, 3, 1, 10, -1}, + {5, 11, 7, 10, 11, 5, 1, 9, 0, -1}, + {11, 5, 10, 7, 5, 11, 8, 3, 0, -1}, + {5, 11, 7, 10, 11, 5, -1}, + {6, 7, 11, -1}, + {7, 11, 6, 3, 8, 0, -1}, + {6, 7, 11, 0, 9, 1, -1}, + {9, 1, 8, 8, 1, 3, 6, 7, 11, -1}, + {3, 2, 7, 7, 2, 6, -1}, + {0, 7, 8, 0, 6, 7, 0, 2, 6, -1}, + {6, 7, 2, 2, 7, 3, 9, 1, 0, -1}, + {6, 7, 8, 6, 8, 1, 8, 9, 1, 2, 6, 1, -1}, + {11, 6, 7, 10, 2, 1, -1}, + {3, 8, 0, 11, 6, 7, 10, 2, 1, -1}, + {0, 9, 2, 2, 9, 10, 7, 11, 6, -1}, + {6, 7, 11, 8, 2, 3, 8, 10, 2, 8, 9, 10, -1}, + {7, 10, 6, 7, 1, 10, 7, 3, 1, -1}, + {8, 0, 7, 7, 0, 6, 6, 0, 1, 6, 1, 10, -1}, + {7, 3, 6, 3, 0, 9, 6, 3, 9, 6, 9, 10, -1}, + {6, 7, 10, 7, 8, 10, 8, 9, 10, -1}, + {11, 6, 8, 8, 6, 4, -1}, + {6, 3, 11, 6, 0, 3, 6, 4, 0, -1}, + {11, 6, 8, 8, 6, 4, 1, 0, 9, -1}, + {1, 3, 9, 3, 11, 6, 9, 3, 6, 9, 6, 4, -1}, + {2, 8, 3, 2, 4, 8, 2, 6, 4, -1}, + {4, 0, 6, 6, 0, 2, -1}, + {9, 1, 0, 2, 8, 3, 2, 4, 8, 2, 6, 4, -1}, + {9, 1, 4, 1, 2, 4, 2, 6, 4, -1}, + {4, 8, 6, 6, 8, 11, 1, 10, 2, -1}, + {1, 10, 2, 6, 3, 11, 6, 0, 3, 6, 4, 0, -1}, + {11, 6, 4, 11, 4, 8, 10, 2, 9, 2, 0, 9, -1}, + {10, 4, 9, 6, 4, 10, 11, 2, 3, -1}, + {4, 8, 3, 4, 3, 10, 3, 1, 10, 6, 4, 10, -1}, + {1, 10, 0, 10, 6, 0, 6, 4, 0, -1}, + {4, 10, 6, 9, 10, 4, 0, 8, 3, -1}, + {4, 10, 6, 9, 10, 4, -1}, + {6, 7, 11, 4, 5, 9, -1}, + {4, 5, 9, 7, 11, 6, 3, 8, 0, -1}, + {1, 0, 5, 5, 0, 4, 11, 6, 7, -1}, + {11, 6, 7, 5, 8, 4, 5, 3, 8, 5, 1, 3, -1}, + {3, 2, 7, 7, 2, 6, 9, 4, 5, -1}, + {5, 9, 4, 0, 7, 8, 0, 6, 7, 0, 2, 6, -1}, + {3, 2, 6, 3, 6, 7, 1, 0, 5, 0, 4, 5, -1}, + {6, 1, 2, 5, 1, 6, 4, 7, 8, -1}, + {10, 2, 1, 6, 7, 11, 4, 5, 9, -1}, + {0, 3, 8, 4, 5, 9, 11, 6, 7, 10, 2, 1, -1}, + {7, 11, 6, 2, 5, 10, 2, 4, 5, 2, 0, 4, -1}, + {8, 4, 7, 5, 10, 6, 3, 11, 2, -1}, + {9, 4, 5, 7, 10, 6, 7, 1, 10, 7, 3, 1, -1}, + {10, 6, 5, 7, 8, 4, 1, 9, 0, -1}, + {4, 3, 0, 7, 3, 4, 6, 5, 10, -1}, + {10, 6, 5, 8, 4, 7, -1}, + {9, 6, 5, 9, 11, 6, 9, 8, 11, -1}, + {11, 6, 3, 3, 6, 0, 0, 6, 5, 0, 5, 9, -1}, + {11, 6, 5, 11, 5, 0, 5, 1, 0, 8, 11, 0, -1}, + {11, 6, 3, 6, 5, 3, 5, 1, 3, -1}, + {9, 8, 5, 8, 3, 2, 5, 8, 2, 5, 2, 6, -1}, + {5, 9, 6, 9, 0, 6, 0, 2, 6, -1}, + {1, 6, 5, 2, 6, 1, 3, 0, 8, -1}, + {1, 6, 5, 2, 6, 1, -1}, + {2, 1, 10, 9, 6, 5, 9, 11, 6, 9, 8, 11, -1}, + {9, 0, 1, 3, 11, 2, 5, 10, 6, -1}, + {11, 0, 8, 2, 0, 11, 10, 6, 5, -1}, + {3, 11, 2, 5, 10, 6, 2, 11, 6, 6, 10, 2, -1}, + {1, 8, 3, 9, 8, 1, 5, 10, 6, -1}, + {6, 5, 10, 0, 1, 9, -1}, + {8, 3, 0, 5, 10, 6, -1}, + {6, 5, 10, -1}, + {10, 5, 6, -1}, + {0, 3, 8, 6, 10, 5, -1}, + {10, 5, 6, 9, 1, 0, -1}, + {3, 8, 1, 1, 8, 9, 6, 10, 5, -1}, + {2, 11, 3, 6, 10, 5, -1}, + {8, 0, 11, 11, 0, 2, 5, 6, 10, -1}, + {1, 0, 9, 2, 11, 3, 6, 10, 5, -1}, + {5, 6, 10, 11, 1, 2, 11, 9, 1, 11, 8, 9, -1}, + {5, 6, 1, 1, 6, 2, -1}, + {5, 6, 1, 1, 6, 2, 8, 0, 3, -1}, + {6, 9, 5, 6, 0, 9, 6, 2, 0, -1}, + {6, 2, 5, 2, 3, 8, 5, 2, 8, 5, 8, 9, -1}, + {3, 6, 11, 3, 5, 6, 3, 1, 5, -1}, + {8, 0, 1, 8, 1, 6, 1, 5, 6, 11, 8, 6, -1}, + {11, 3, 6, 6, 3, 5, 5, 3, 0, 5, 0, 9, -1}, + {5, 6, 9, 6, 11, 9, 11, 8, 9, -1}, + {5, 6, 10, 7, 4, 8, -1}, + {0, 3, 4, 4, 3, 7, 10, 5, 6, -1}, + {5, 6, 10, 4, 8, 7, 0, 9, 1, -1}, + {6, 10, 5, 1, 4, 9, 1, 7, 4, 1, 3, 7, -1}, + {7, 4, 8, 6, 10, 5, 2, 11, 3, -1}, + {10, 5, 6, 4, 11, 7, 4, 2, 11, 4, 0, 2, -1}, + {4, 8, 7, 6, 10, 5, 3, 2, 11, 1, 0, 9, -1}, + {1, 2, 10, 11, 7, 6, 9, 5, 4, -1}, + {2, 1, 6, 6, 1, 5, 8, 7, 4, -1}, + {0, 3, 7, 0, 7, 4, 2, 1, 6, 1, 5, 6, -1}, + {8, 7, 4, 6, 9, 5, 6, 0, 9, 6, 2, 0, -1}, + {7, 2, 3, 6, 2, 7, 5, 4, 9, -1}, + {4, 8, 7, 3, 6, 11, 3, 5, 6, 3, 1, 5, -1}, + {5, 0, 1, 4, 0, 5, 7, 6, 11, -1}, + {9, 5, 4, 6, 11, 7, 0, 8, 3, -1}, + {11, 7, 6, 9, 5, 4, -1}, + {6, 10, 4, 4, 10, 9, -1}, + {6, 10, 4, 4, 10, 9, 3, 8, 0, -1}, + {0, 10, 1, 0, 6, 10, 0, 4, 6, -1}, + {6, 10, 1, 6, 1, 8, 1, 3, 8, 4, 6, 8, -1}, + {9, 4, 10, 10, 4, 6, 3, 2, 11, -1}, + {2, 11, 8, 2, 8, 0, 6, 10, 4, 10, 9, 4, -1}, + {11, 3, 2, 0, 10, 1, 0, 6, 10, 0, 4, 6, -1}, + {6, 8, 4, 11, 8, 6, 2, 10, 1, -1}, + {4, 1, 9, 4, 2, 1, 4, 6, 2, -1}, + {3, 8, 0, 4, 1, 9, 4, 2, 1, 4, 6, 2, -1}, + {6, 2, 4, 4, 2, 0, -1}, + {3, 8, 2, 8, 4, 2, 4, 6, 2, -1}, + {4, 6, 9, 6, 11, 3, 9, 6, 3, 9, 3, 1, -1}, + {8, 6, 11, 4, 6, 8, 9, 0, 1, -1}, + {11, 3, 6, 3, 0, 6, 0, 4, 6, -1}, + {8, 6, 11, 4, 6, 8, -1}, + {10, 7, 6, 10, 8, 7, 10, 9, 8, -1}, + {3, 7, 0, 7, 6, 10, 0, 7, 10, 0, 10, 9, -1}, + {6, 10, 7, 7, 10, 8, 8, 10, 1, 8, 1, 0, -1}, + {6, 10, 7, 10, 1, 7, 1, 3, 7, -1}, + {3, 2, 11, 10, 7, 6, 10, 8, 7, 10, 9, 8, -1}, + {2, 9, 0, 10, 9, 2, 6, 11, 7, -1}, + {0, 8, 3, 7, 6, 11, 1, 2, 10, -1}, + {7, 6, 11, 1, 2, 10, 11, 6, 2, 2, 6, 10, -1}, + {2, 1, 9, 2, 9, 7, 9, 8, 7, 6, 2, 7, -1}, + {2, 7, 6, 3, 7, 2, 0, 1, 9, -1}, + {8, 7, 0, 7, 6, 0, 6, 2, 0, -1}, + {7, 2, 3, 6, 2, 7, -1}, + {8, 1, 9, 3, 1, 8, 11, 7, 6, -1}, + {11, 7, 6, 1, 9, 0, -1}, + {6, 11, 7, 0, 8, 3, -1}, + {11, 7, 6, -1}, + {7, 11, 5, 5, 11, 10, -1}, + {10, 5, 11, 11, 5, 7, 0, 3, 8, -1}, + {7, 11, 5, 5, 11, 10, 0, 9, 1, -1}, + {7, 11, 10, 7, 10, 5, 3, 8, 1, 8, 9, 1, -1}, + {5, 2, 10, 5, 3, 2, 5, 7, 3, -1}, + {5, 7, 10, 7, 8, 0, 10, 7, 0, 10, 0, 2, -1}, + {0, 9, 1, 5, 2, 10, 5, 3, 2, 5, 7, 3, -1}, + {9, 7, 8, 5, 7, 9, 10, 1, 2, -1}, + {1, 11, 2, 1, 7, 11, 1, 5, 7, -1}, + {8, 0, 3, 1, 11, 2, 1, 7, 11, 1, 5, 7, -1}, + {7, 11, 2, 7, 2, 9, 2, 0, 9, 5, 7, 9, -1}, + {7, 9, 5, 8, 9, 7, 3, 11, 2, -1}, + {3, 1, 7, 7, 1, 5, -1}, + {8, 0, 7, 0, 1, 7, 1, 5, 7, -1}, + {0, 9, 3, 9, 5, 3, 5, 7, 3, -1}, + {9, 7, 8, 5, 7, 9, -1}, + {8, 5, 4, 8, 10, 5, 8, 11, 10, -1}, + {0, 3, 11, 0, 11, 5, 11, 10, 5, 4, 0, 5, -1}, + {1, 0, 9, 8, 5, 4, 8, 10, 5, 8, 11, 10, -1}, + {10, 3, 11, 1, 3, 10, 9, 5, 4, -1}, + {3, 2, 8, 8, 2, 4, 4, 2, 10, 4, 10, 5, -1}, + {10, 5, 2, 5, 4, 2, 4, 0, 2, -1}, + {5, 4, 9, 8, 3, 0, 10, 1, 2, -1}, + {2, 10, 1, 4, 9, 5, -1}, + {8, 11, 4, 11, 2, 1, 4, 11, 1, 4, 1, 5, -1}, + {0, 5, 4, 1, 5, 0, 2, 3, 11, -1}, + {0, 11, 2, 8, 11, 0, 4, 9, 5, -1}, + {5, 4, 9, 2, 3, 11, -1}, + {4, 8, 5, 8, 3, 5, 3, 1, 5, -1}, + {0, 5, 4, 1, 5, 0, -1}, + {5, 4, 9, 3, 0, 8, -1}, + {5, 4, 9, -1}, + {11, 4, 7, 11, 9, 4, 11, 10, 9, -1}, + {0, 3, 8, 11, 4, 7, 11, 9, 4, 11, 10, 9, -1}, + {11, 10, 7, 10, 1, 0, 7, 10, 0, 7, 0, 4, -1}, + {3, 10, 1, 11, 10, 3, 7, 8, 4, -1}, + {3, 2, 10, 3, 10, 4, 10, 9, 4, 7, 3, 4, -1}, + {9, 2, 10, 0, 2, 9, 8, 4, 7, -1}, + {3, 4, 7, 0, 4, 3, 1, 2, 10, -1}, + {7, 8, 4, 10, 1, 2, -1}, + {7, 11, 4, 4, 11, 9, 9, 11, 2, 9, 2, 1, -1}, + {1, 9, 0, 4, 7, 8, 2, 3, 11, -1}, + {7, 11, 4, 11, 2, 4, 2, 0, 4, -1}, + {4, 7, 8, 2, 3, 11, -1}, + {9, 4, 1, 4, 7, 1, 7, 3, 1, -1}, + {7, 8, 4, 1, 9, 0, -1}, + {3, 4, 7, 0, 4, 3, -1}, + {7, 8, 4, -1}, + {11, 10, 8, 8, 10, 9, -1}, + {0, 3, 9, 3, 11, 9, 11, 10, 9, -1}, + {1, 0, 10, 0, 8, 10, 8, 11, 10, -1}, + {10, 3, 11, 1, 3, 10, -1}, + {3, 2, 8, 2, 10, 8, 10, 9, 8, -1}, + {9, 2, 10, 0, 2, 9, -1}, + {8, 3, 0, 10, 1, 2, -1}, + {2, 10, 1, -1}, + {2, 1, 11, 1, 9, 11, 9, 8, 11, -1}, + {11, 2, 3, 9, 0, 1, -1}, + {11, 0, 8, 2, 0, 11, -1}, + {3, 11, 2, -1}, + {1, 8, 3, 9, 8, 1, -1}, + {1, 9, 0, -1}, + {8, 3, 0, -1}, + {-1}, + }; + + extern VoxelCorner marchingCubesEdgeCornerPairs[12][2] = { + {// 0 + {.voxelOffset = {-1, -1, -1}, + .faceIndex = 1, + .localCornerIndex = 3}, + {.voxelOffset = {0, -1, -1}, + .faceIndex = 0, + .localCornerIndex = 2}}, + {// 1 + {.voxelOffset = {0, -1, -1}, + .faceIndex = 3, + .localCornerIndex = 2}, + {.voxelOffset = {0, 0, -1}, + .faceIndex = 2, + .localCornerIndex = 0}}, + {// 2 + {.voxelOffset = {0, 0, -1}, + .faceIndex = 0, + .localCornerIndex = 0}, + {.voxelOffset = {-1, 0, -1}, + .faceIndex = 1, + .localCornerIndex = 1}}, + {// 3 + {.voxelOffset = {-1, 0, -1}, + .faceIndex = 2, + .localCornerIndex = 1}, + {.voxelOffset = {-1, -1, -1}, + .faceIndex = 3, + .localCornerIndex = 3}}, + {// 4 + {.voxelOffset = {-1, -1, 0}, + .faceIndex = 1, + .localCornerIndex = 2}, + {.voxelOffset = {0, -1, 0}, + .faceIndex = 0, + .localCornerIndex = 3}}, + {// 5 + {.voxelOffset = {0, -1, 0}, + .faceIndex = 3, + .localCornerIndex = 0}, + {.voxelOffset = {0, 0, 0}, + .faceIndex = 2, + .localCornerIndex = 2}}, + {// 6 + {.voxelOffset = {0, 0, 0}, + .faceIndex = 0, + .localCornerIndex = 1}, + {.voxelOffset = {-1, 0, 0}, + .faceIndex = 1, + .localCornerIndex = 0}}, + {// 7 + {.voxelOffset = {-1, 0, 0}, + .faceIndex = 2, + .localCornerIndex = 3}, + {.voxelOffset = {-1, -1, 0}, + .faceIndex = 3, + .localCornerIndex = 1}}, + {// 8 + {.voxelOffset = {-1, -1, -1}, + .faceIndex = 5, + .localCornerIndex = 2}, + {.voxelOffset = {-1, -1, 0}, + .faceIndex = 4, + .localCornerIndex = 3}}, + {// 9 + {.voxelOffset = {0, -1, -1}, + .faceIndex = 5, + .localCornerIndex = 3}, + {.voxelOffset = {0, -1, 0}, + .faceIndex = 4, + .localCornerIndex = 2}}, + {// 10 + {.voxelOffset = {0, 0, -1}, + .faceIndex = 5, + .localCornerIndex = 1}, + {.voxelOffset = {0, 0, 0}, + .faceIndex = 4, + .localCornerIndex = 0}}, + {// 11 + {.voxelOffset = {-1, 0, -1}, + .faceIndex = 5, + .localCornerIndex = 0}, + {.voxelOffset = {-1, 0, 0}, + .faceIndex = 4, + .localCornerIndex = 1}}}; + + // Represents the 8 edges along each of the 3 axes for a voxel, axis : (X, Y, Z) + VoxelEdge edgesPerAxis[AXIS_NUMBER][EDGE_PER_AXIS] = { + { + {.voxelOffset = {0, 0, 0}, + .isClockwiseOrder = true, + .faceIndex = 4, + .edgeIndex = 2}, + {.voxelOffset = {0, 0, 0}, + .isClockwiseOrder = false, + .faceIndex = 2, + .edgeIndex = 3}, + + {.voxelOffset = {0, -1, 0}, + .isClockwiseOrder = true, + .faceIndex = 3, + .edgeIndex = 2}, + {.voxelOffset = {0, -1, 0}, + .isClockwiseOrder = false, + .faceIndex = 4, + .edgeIndex = 3}, + + {.voxelOffset = {0, -1, -1}, + .isClockwiseOrder = true, + .faceIndex = 5, + .edgeIndex = 3}, + {.voxelOffset = {0, -1, -1}, + .isClockwiseOrder = false, + .faceIndex = 3, + .edgeIndex = 3}, + + {.voxelOffset = {0, 0, -1}, + .isClockwiseOrder = true, + .faceIndex = 2, + .edgeIndex = 2}, + {.voxelOffset = {0, 0, -1}, + .isClockwiseOrder = false, + .faceIndex = 5, + .edgeIndex = 2}, + }, // X axis + { + {.voxelOffset = {0, 0, 0}, + .isClockwiseOrder = true, + .faceIndex = 0, + .edgeIndex = 1}, + {.voxelOffset = {0, 0, 0}, + .isClockwiseOrder = false, + .faceIndex = 4, + .edgeIndex = 0}, + {.voxelOffset = {0, 0, -1}, + .isClockwiseOrder = true, + .faceIndex = 5, + .edgeIndex = 1}, + {.voxelOffset = {0, 0, -1}, + .isClockwiseOrder = false, + .faceIndex = 0, + .edgeIndex = 0}, + {.voxelOffset = {-1, 0, -1}, + .isClockwiseOrder = true, + .faceIndex = 1, + .edgeIndex = 1}, + {.voxelOffset = {-1, 0, -1}, + .isClockwiseOrder = false, + .faceIndex = 5, + .edgeIndex = 0}, + {.voxelOffset = {-1, 0, 0}, + .isClockwiseOrder = true, + .faceIndex = 4, + .edgeIndex = 1}, + {.voxelOffset = {-1, 0, 0}, + .isClockwiseOrder = false, + .faceIndex = 1, + .edgeIndex = 0}}, // Y axis + { + {.voxelOffset = {0, 0, 0}, + .isClockwiseOrder = true, + .faceIndex = 0, + .edgeIndex = 2}, + {.voxelOffset = {0, 0, 0}, + .isClockwiseOrder = false, + .faceIndex = 2, + .edgeIndex = 0}, + {.voxelOffset = {0, -1, 0}, + .isClockwiseOrder = true, + .faceIndex = 3, + .edgeIndex = 0}, + {.voxelOffset = {0, -1, 0}, + .isClockwiseOrder = false, + .faceIndex = 0, + .edgeIndex = 3}, + {.voxelOffset = {-1, -1, 0}, + .isClockwiseOrder = true, + .faceIndex = 1, + .edgeIndex = 3}, + {.voxelOffset = {-1, -1, 0}, + .isClockwiseOrder = false, + .faceIndex = 3, + .edgeIndex = 1}, + {.voxelOffset = {-1, 0, 0}, + .isClockwiseOrder = true, + .faceIndex = 2, + .edgeIndex = 1}, + {.voxelOffset = {-1, 0, 0}, + .isClockwiseOrder = false, + .faceIndex = 1, + .edgeIndex = 2}, + } // Z axis + }; + } // namespace Voxel +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/World/World.cpp b/Deer/src/DeerRender/World/World.cpp index bfd8818..23aff19 100755 --- a/Deer/src/DeerRender/World/World.cpp +++ b/Deer/src/DeerRender/World/World.cpp @@ -40,7 +40,7 @@ namespace Deer { if (targetRenderTime > 0 && accumulatedRenderTime >= targetRenderTime) { renderDeltaTime = accumulatedRenderTime; worldSettings.renderCallback(*this); - accumulatedRenderTime = 0; + accumulatedRenderTime -= targetRenderTime; } std::this_thread::sleep_for(std::chrono::microseconds(1)); diff --git a/DeerStudio/src/DeerStudio/DeerStudio.cpp b/DeerStudio/src/DeerStudio/DeerStudio.cpp index 9367d3e..ac5a8c1 100644 --- a/DeerStudio/src/DeerStudio/DeerStudio.cpp +++ b/DeerStudio/src/DeerStudio/DeerStudio.cpp @@ -8,6 +8,8 @@ #include "DeerRender/World.h" // TMP +#include "DeerCore/EntityEnviroment.h" +#include "DeerRender/Voxel.h" #include "DeerStudio/Fonts.h" #include "DeerStudio/Style.h" // TMP @@ -17,6 +19,7 @@ namespace Deer { namespace DeerStudio { World* world; + VoxelEnvironment env; void onUpdate(); void onRender(); @@ -46,6 +49,53 @@ namespace Deer { while (world) { StudioPanel::setWorld(world); + + Entity& entity = world->entityEnvironment->createEntity(); + MeshComponent& mesh = entity.addComponent(); + ShaderComponent& shader = entity.addComponent(); + + /* + env.modifyVoxel(1, 0, 1, 0); + env.modifyVoxel(1, 1, 2, 0); + + env.modifyVoxel(1, 5, 1, 1); + env.modifyVoxel(1, 5, 2, 2); + env.modifyVoxel(1, 5, 1, 3); + + env.modifyVoxel(1, 15, 1, 15); + env.modifyVoxel(1, 14, 1, 16); + + env.modifyVoxel(1, 5, 1, 8); + env.modifyVoxel(1, 5, 1, 9); + env.modifyVoxel(1, 5, 2, 9); + env.modifyVoxel(1, 6, 1, 9); + + env.modifyVoxel(1, 0, 1, 5); + env.modifyVoxel(1, 1, 2, 6); + + env.modifyVoxel(1, 4, 1, 5); + + env.modifyVoxel(1, 9, 1, 9); + env.modifyVoxel(1, 10, 1, 10); +*/ + for (int x = 0; x < 20; x++) + for (int y = 0; y < 20; y++) + env.modifyVoxel(1, x, 0, y); + + env.modifyVoxel(1, 5, 1, 5); + env.modifyVoxel(1, 5, 2, 5); + env.modifyVoxel(1, 4, 2, 5); + env.modifyVoxel(1, 4, 2, 4); + + env.modifyVoxel(1, 7, 1, 5); + env.modifyVoxel(1, 6, 1, 5); + env.modifyVoxel(1, 6, 1, 4); + + DEER_CORE_INFO("{}", env.getVoxel(0, 0, 0)); + + shader.shader = Builtin::simpleShader(); + mesh.mesh = env.voxelBuilder->buildChunk(0, 0, 0); + world->execute(); } diff --git a/DeerStudio/src/DeerStudio/PannelMenuBarManagment.cpp b/DeerStudio/src/DeerStudio/PannelMenuBarManagment.cpp deleted file mode 100644 index c9350b5..0000000 --- a/DeerStudio/src/DeerStudio/PannelMenuBarManagment.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "DeerStudio/DeerStudio.h" - -#include "imgui.h" - -namespace Deer { - namespace DeerStudio { - void onPanelMenuBar() { - } - - } // namespace DeerStudio -} // namespace Deer \ No newline at end of file diff --git a/Editor/Scripts/Viewport/Viewport.as b/Editor/Scripts/Viewport/Viewport.as index 6c78c9f..2bf51ed 100644 --- a/Editor/Scripts/Viewport/Viewport.as +++ b/Editor/Scripts/Viewport/Viewport.as @@ -5,10 +5,22 @@ class ViewportPanel : Panel { float pitch = 0; float yaw = 0; + int frameCounter = 0; + float deltaAcomulated = 0; + float latestFrameRate; + void onImGui() { if (!frameBuffer.isValid()) return; + frameCounter++; + deltaAcomulated += World::getRenderDeltaTime(); + if (frameCounter == 50) { + latestFrameRate = 50 / deltaAcomulated; + frameCounter = 0; + deltaAcomulated = 0; + } + float vel = World::getRenderDeltaTime() * 3; if (ImGui::isKeyDown(key::LeftShift)) @@ -104,7 +116,7 @@ class ViewportPanel : Panel { } ImGui::simplePopup("ViewportCameraProps", SimpleFunction(this.viewportCameraProps)); - ImGui::textColor(0, 0.5f, 0,"" + ceil(1 / World::getRenderDeltaTime())); + ImGui::textColor(0, 0.5f, 0,"" + latestFrameRate); } void viewportCameraProps() { diff --git a/Editor/Scripts/VoxelEditor/VoxelEditor.as b/Editor/Scripts/VoxelEditor/VoxelEditor.as new file mode 100644 index 0000000..b172ce2 --- /dev/null +++ b/Editor/Scripts/VoxelEditor/VoxelEditor.as @@ -0,0 +1,12 @@ +class VoxelEditor : Panel { + FrameBuffer editorBuffer; + + void onInit() { + editorBuffer = Resource::createFrameBuffer("VoxelEditor", 620, 620); + } + + void onImGui() { + editorBuffer.clearRGBA(60, 120, 100, 255); + ImGui::drawFrameBufferCentered(editorBuffer, 620, 620); + } +} diff --git a/Resources/normal.glsl b/Resources/normal.glsl new file mode 100644 index 0000000..6f282db --- /dev/null +++ b/Resources/normal.glsl @@ -0,0 +1,83 @@ +#type vertex +#version 410 core + +// Vertex attributes +layout(location = 0) in vec3 v_position; +layout(location = 1) in vec3 v_normal; +layout(location = 2) in vec2 v_UV; + +// Outputs to fragment shader +out vec3 normalWS; +out vec3 normalVS; +out vec3 positionVS; + +// Uniforms +uniform mat4 u_worldMatrix; +uniform mat4 u_viewMatrix; + +void main() +{ + gl_Position = u_viewMatrix * u_worldMatrix * vec4(v_position, 1.0); + positionVS = gl_Position.xyz; + + mat3 normalMatrix = transpose(inverse(mat3(u_worldMatrix))); + normalWS = normalize(normalMatrix * v_normal); + + mat3 normalMatrixView = transpose(inverse(mat3(u_viewMatrix * u_worldMatrix))); + normalVS = normalize(normalMatrixView * v_normal); + +} + +#type fragment +#version 410 core + +// Fragment outputs +layout(location = 0) out vec4 fragColor; +layout(location = 1) out int objectID; + +// Inputs from vertex shader +in vec3 normalWS; +in vec3 normalVS; +in vec3 positionVS; + +// Uniforms +uniform int u_objectID; + +void main() +{ + // Directional light + vec3 lightDir = normalize(vec3(1.0, 7.0, 3.0)); + + // Base light intensity + float light = clamp(dot(normalize(normalWS), lightDir) * 0.8 + 0.2, 0.0, 1.0); + + // Gradient from purple (dark) to cyan (lit) + vec3 gradientColor = mix( + vec3(0.9412, 0.4471, 0.7137), + vec3(1.0, 0.9725, 0.5255), + light + ); + + // Rim/fresnel effect + float rim = 0.5 - dot(normalize(normalWS), normalize(lightDir)) * 0.5; + float rimValue = rim * rim * rim * rim; + vec3 rimColor = vec3(1.0, 0.8, 0.5) * (rim * rim * rim * rim); + + vec3 mixedColor = mix( + gradientColor, + vec3(1, 1, 1) , + rimValue + ); + + //float fresnel = dot(, vec3(0, 0, -1)); + //fresnel = fresnel * fresnel; + + float fresnel = 1 + dot(normalize(positionVS), normalize(normalVS)); + fresnel = fresnel * fresnel * fresnel * fresnel; + + // Combine everything + fragColor = vec4(normalize(normalWS) * 0.5 + vec3(0.5, 0.5, 0.5), 1.0); + + // Object ID output + objectID = u_objectID; +} \ No newline at end of file diff --git a/Resources/shad.glsl b/Resources/shad.glsl new file mode 100644 index 0000000..df82e81 --- /dev/null +++ b/Resources/shad.glsl @@ -0,0 +1,87 @@ +#type vertex +#version 410 core + +// Vertex attributes +layout(location = 0) in vec3 v_position; +layout(location = 1) in vec3 v_normal; +layout(location = 2) in float v_light; + +// Outputs to fragment shader +out vec3 normalWS; +out vec3 normalVS; +out vec3 positionVS; +out float shadow; + +// Uniforms +uniform mat4 u_worldMatrix; +uniform mat4 u_viewMatrix; + +void main() +{ + gl_Position = u_viewMatrix * u_worldMatrix * vec4(v_position, 1.0); + positionVS = gl_Position.xyz; + + mat3 normalMatrix = transpose(inverse(mat3(u_worldMatrix))); + normalWS = normalize(normalMatrix * v_normal); + + mat3 normalMatrixView = transpose(inverse(mat3(u_viewMatrix * u_worldMatrix))); + normalVS = normalize(normalMatrixView * v_normal); + + shadow = v_light; +} + +#type fragment +#version 410 core + +// Fragment outputs +layout(location = 0) out vec4 fragColor; +layout(location = 1) out int objectID; + +// Inputs from vertex shader +in vec3 normalWS; +in vec3 normalVS; +in vec3 positionVS; +in float shadow; + +// Uniforms +uniform int u_objectID; + +void main() +{ + // Directional light + vec3 lightDir = normalize(vec3(1.0, 7.0, 3.0)); + + // Base light intensity + float light = clamp(dot(normalize(normalWS), lightDir) * 0.8 + 0.2, 0.0, 1.0); + + // Gradient from purple (dark) to cyan (lit) + vec3 gradientColor = mix( + vec3(0.9412, 0.4471, 0.7137), + vec3(1.0, 0.9725, 0.5255), + light + ); + + // Rim/fresnel effect + float rim = 0.5 - dot(normalize(normalWS), normalize(lightDir)) * 0.5; + float rimValue = rim * rim * rim * rim; + vec3 rimColor = vec3(1.0, 0.8, 0.5) * (rim * rim * rim * rim); + + vec3 mixedColor = mix( + gradientColor, + vec3(1, 1, 1) , + rimValue + ); + + //float fresnel = dot(, vec3(0, 0, -1)); + //fresnel = fresnel * fresnel; + + float fresnel = 1 + dot(normalize(positionVS), normalize(normalVS)); + fresnel = fresnel * fresnel * fresnel * fresnel; + + // Combine everything + fragColor = vec4(normalize(normalWS) * 0.5 + vec3(0.5, 0.5, 0.5), 1.0); + fragColor = vec4(shadow / 255, shadow / 255, shadow / 255, 1); + + // Object ID output + objectID = u_objectID; +} \ No newline at end of file diff --git a/imgui.ini b/imgui.ini index 8a47787..298518e 100644 --- a/imgui.ini +++ b/imgui.ini @@ -10,34 +10,40 @@ Collapsed=0 [Window][ViewportPanel] Pos=561,26 -Size=1500,853 +Size=1348,870 Collapsed=0 DockId=0x00000005,0 [Window][PropertiesPanel] -Pos=2063,26 -Size=497,853 +Pos=1911,26 +Size=649,870 Collapsed=0 DockId=0x00000006,0 [Window][ResourceExplorer] -Pos=0,881 -Size=2560,490 +Pos=0,898 +Size=2560,473 Collapsed=0 DockId=0x00000004,0 [Window][TreePanel] Pos=0,26 -Size=559,853 +Size=559,870 Collapsed=0 DockId=0x00000001,0 +[Window][VoxelEditor] +Pos=1911,26 +Size=649,870 +Collapsed=0 +DockId=0x00000006,1 + [Docking][Data] DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,26 Size=2560,1345 Split=Y - DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=1920,493 Split=X + DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=1920,870 Split=X DockNode ID=0x00000001 Parent=0x00000003 SizeRef=559,985 Selected=0x16E3C1E7 DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1359,985 Split=X - DockNode ID=0x00000005 Parent=0x00000002 SizeRef=1500,493 CentralNode=1 Selected=0x0F5FFC8C - DockNode ID=0x00000006 Parent=0x00000002 SizeRef=497,493 Selected=0x9876A79B - DockNode ID=0x00000004 Parent=0x0AC2E849 SizeRef=1920,490 Selected=0x018A0F9B + DockNode ID=0x00000005 Parent=0x00000002 SizeRef=1348,493 CentralNode=1 Selected=0x0F5FFC8C + DockNode ID=0x00000006 Parent=0x00000002 SizeRef=649,493 Selected=0x9876A79B + DockNode ID=0x00000004 Parent=0x0AC2E849 SizeRef=1920,473 Selected=0x018A0F9B