diff --git a/CMakeLists.txt b/CMakeLists.txt index d41fb30..68904ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(vk_expe src/main.cpp src/utils.cpp src/Logger.cpp + src/Planet.cpp src/VkExpe.cpp src/VulkanTutorial.cpp ) diff --git a/src/Planet.cpp b/src/Planet.cpp new file mode 100644 index 0000000..87fb91a --- /dev/null +++ b/src/Planet.cpp @@ -0,0 +1,150 @@ + +#include +#include + +#include +#include + + +Vector3 lerp(Real factor, const Vector3& v0, const Vector3& v1) { + return (Real(1) - factor) * v0 + factor * v1; +} + + +Cell::Cell( + const Vector3& corner00, + const Vector3& corner01, + const Vector3& corner10, + const Vector3& corner11 +) + : m_corners{ corner00, corner01, corner10, corner11 } + , m_heightFactor(heightFactor(m_corners)) + , m_cells{ nullptr, nullptr, nullptr, nullptr } +{} + +Cell& Cell::cell(uint32_t cellIndex) { + assert(cellIndex < CellCount); + auto& cell = m_cells[cellIndex]; + if(!cell) + { + // TODO + } + return *cell; +} + +void Cell::writeMesh( + Vertex*& vertices, const Vertex* verticesEnd, + uint32_t*& indices, const uint32_t* indicesEnd, + uint32_t subdivCount +) const { + auto const sideEdgeCount = (1u << subdivCount); + auto const sideVertCount = sideEdgeCount + 1; + + auto const quadCount = sideEdgeCount * sideEdgeCount; + auto const triCount = 2 * quadCount; + auto const vertCount = sideVertCount * sideVertCount; + + assert(vertices + vertCount <= verticesEnd); + assert(indices + (3 * triCount) <= indicesEnd); + + auto const index = [sideVertCount](uint32_t x, uint32_t y) -> uint32_t { + return x + y * sideVertCount; + }; + auto const vertex = [vertices, &index](uint32_t x, uint32_t y) -> Vertex& { + return vertices[index(x, y)]; + }; + + Vector3 c00(0.0f, 0.0f, 1.0f); + Vector3 c01(1.0f, 0.0f, 1.0f); + Vector3 c10(0.0f, 1.0f, 1.0f); + Vector3 c11(1.0f, 1.0f, 1.0f); + + auto const color = [&c00, &c01, &c10, &c11, sideEdgeCount](uint32_t x, uint32_t y) -> Vector3 { + const auto c0 = lerp(Real(x) / Real(sideEdgeCount), c00, c01); + const auto c1 = lerp(Real(x) / Real(sideEdgeCount), c10, c11); + return lerp(Real(y) / Real(sideEdgeCount), c0, c1); + }; + + auto const setVertex = [&vertex, &color](uint32_t x, uint32_t y, const Vector3& pos) { + vertex(x, y) = Vertex { + pos, + color(x, y) + }; + }; + + setVertex( 0, 0, m_corners[0]); + setVertex(sideEdgeCount, 0, m_corners[1]); + setVertex( 0, sideEdgeCount, m_corners[2]); + setVertex(sideEdgeCount, sideEdgeCount, m_corners[3]); + + struct QuadCell { + uint32_t x0, x1, y0, y1; + }; + std::vector stack; + stack.reserve(quadCount / 4); + if(subdivCount > 0) { + stack.emplace_back(QuadCell { + 0, sideEdgeCount, + 0, sideEdgeCount, + }); + } + + while(!stack.empty()) { + const auto quadCell = stack.back(); + stack.pop_back(); + + auto const mx = (quadCell.x0 + quadCell.x1) / 2; + auto const my = (quadCell.y0 + quadCell.y1) / 2; + + auto const& v00 = vertex(quadCell.x0, quadCell.y0).position; + auto const& v01 = vertex(quadCell.x1, quadCell.y0).position; + auto const& v10 = vertex(quadCell.x0, quadCell.y1).position; + auto const& v11 = vertex(quadCell.x1, quadCell.y1).position; + + setVertex( mx, quadCell.y0, + (v00 + v01).normalized() + ); + setVertex(quadCell.x0, my, + (v00 + v10).normalized() + ); + setVertex(mx, my, + (v00 + v01 + v10 + v11).normalized() + ); + setVertex(quadCell.x1, my, + (v01 + v11).normalized() + ); + setVertex( mx, quadCell.y1, + (v10 + v11).normalized() + ); + + if(quadCell.x0 + 1 < mx) { + stack.emplace_back(QuadCell { mx, quadCell.x1, my, quadCell.y1 }); + stack.emplace_back(QuadCell { quadCell.x0, mx, my, quadCell.y1 }); + stack.emplace_back(QuadCell { mx, quadCell.x1, quadCell.y0, my }); + stack.emplace_back(QuadCell { quadCell.x0, mx, quadCell.y0, my }); + } + } + vertices += vertCount; + + for(uint32_t y = 0; y < sideEdgeCount; y += 1) { + for(uint32_t x = 0; x < sideEdgeCount; x += 1) { + const auto i00 = index(x, y); + const auto i01 = i00 + 1; + const auto i10 = i00 + sideVertCount; + const auto i11 = i10 + 1; + + *(indices++) = i00; + *(indices++) = i01; + *(indices++) = i10; + + *(indices++) = i10; + *(indices++) = i01; + *(indices++) = i11; + } + } +} + +Real Cell::heightFactor(Vector3 corners[CornerCount]) { + Vector3 c = (corners[0] + corners[1] + corners[2] + corners[3]).normalized(); + return Real(1) / corners[0].dot(c); +} diff --git a/src/Planet.h b/src/Planet.h new file mode 100644 index 0000000..8dabb3f --- /dev/null +++ b/src/Planet.h @@ -0,0 +1,78 @@ +#pragma once + +#include + +#include + + +using Real = float; +using Vector3 = Eigen::Matrix; + +class Cell; +using CellUP = std::unique_ptr; + + +struct Vertex { + Vector3 position; + Vector3 color; +}; + + +Vector3 lerp(Real factor, const Vector3& v0, const Vector3& v1); + + +class Cell { +public: + static constexpr uint32_t CornerCount = 4; + static constexpr uint32_t CellCount = 4; + +public: + Cell( + const Vector3& corner00, + const Vector3& corner01, + const Vector3& corner10, + const Vector3& corner11 + ); + Cell(const Cell&) = delete; + Cell(Cell&&) = default; + ~Cell() = default; + + Cell& operator=(const Cell&) = delete; + Cell& operator=(Cell&&) = default; + + Cell& cell(uint32_t cellIndex); + + void writeMesh( + Vertex*& vertices, const Vertex* verticesEnd, + uint32_t*& indices, const uint32_t* indicesEnd, + uint32_t subdivCount = 4 + ) const; + +private: + static Real heightFactor(Vector3 corners[CornerCount]); + +private: + Vector3 m_corners[CornerCount]; + Real m_heightFactor; + CellUP m_cells[CellCount]; +}; + + +class Planet { +public: + static constexpr uint32_t CellCount = 6; + +public: + Planet(); + Planet(const Planet&) = delete; + Planet(Planet&&) = default; + ~Planet() = default; + + Planet& operator=(const Planet&) = delete; + Planet& operator=(Planet&&) = default; + + Cell& cell(uint32_t cellIndex); + +private: + CellUP m_cells[CellCount]; +}; diff --git a/src/VulkanTutorial.cpp b/src/VulkanTutorial.cpp index 63fd517..bc3d8f9 100644 --- a/src/VulkanTutorial.cpp +++ b/src/VulkanTutorial.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -15,7 +16,7 @@ #include -VkVertexInputBindingDescription Vertex::binding_description() { +VkVertexInputBindingDescription vertex_binding_description() { return { .binding = 0, .stride = sizeof(Vertex), @@ -23,7 +24,7 @@ VkVertexInputBindingDescription Vertex::binding_description() { }; } -std::array Vertex::attributes_description() { +std::array vertex_attributes_description() { return { VkVertexInputAttributeDescription { .location = 0, @@ -41,7 +42,7 @@ std::array Vertex::attributes_description( } -const std::vector vertices = { +std::vector vertices = { {{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}}, {{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}}, {{-0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}}, @@ -53,7 +54,7 @@ const std::vector vertices = { {{0.5f, 0.5f, 0.5f}, {0.2f, 0.2f, 0.2f}}, }; -const std::vector indices = { +std::vector indices = { 0, 1, 2, 2, 1, 3, @@ -84,6 +85,50 @@ VulkanTutorial::VulkanTutorial() { std::bind(&VulkanTutorial::create_swapchain_objects, this, std::placeholders::_1)); m_swapchain.register_destruction_callback( std::bind(&VulkanTutorial::destroy_swapchain_objects, this)); + + auto const subdivCount = 2; + auto const sideEdgeCount = (1u << subdivCount); + auto const sideVertCount = sideEdgeCount + 1; + auto const quadCount = sideEdgeCount * sideEdgeCount; + auto const indexCount = 6 * quadCount; + auto const vertCount = sideVertCount * sideVertCount; + + vertices.assign(vertCount, Vertex{ + Vector3::Constant(std::numeric_limits::quiet_NaN()), + Vector3::Zero() + }); + indices.assign(indexCount, UINT32_MAX); + + Cell cell( + Vector3(-1.0f, -1.0f, 1.0f).normalized(), + Vector3( 1.0f, -1.0f, 1.0f).normalized(), + Vector3(-1.0f, -1.0f, -1.0f).normalized(), + Vector3( 1.0f, -1.0f, -1.0f).normalized() + ); + + auto vertex = &*vertices.begin(); + const auto verticesEnd = &*vertices.end(); + auto index = &*indices.begin(); + const auto indicesEnd = &*indices.end(); + cell.writeMesh( + vertex, verticesEnd, + index, indicesEnd, + subdivCount + ); + + logger.info() << "Vertices:"; + for(auto v = &*vertices.begin(); v < vertex; v += 1) + logger.debug() << (v - &*vertices.begin()) << ": " + << v->position.transpose() << " - " + << v->color.transpose(); + + logger.info() << "Indices:"; + for(auto i = &*indices.begin(); i < index; i += 6) + logger.debug() << (i - &*indices.begin()) << ": " + << i[0] << ", " << i[1] << ", " << i[2] << " - " + << i[3] << ", " << i[4] << ", " << i[5]; + + // abort(); } VulkanTutorial::~VulkanTutorial() { @@ -375,9 +420,9 @@ void VulkanTutorial::create_graphic_pipeline() { }; const VkVertexInputBindingDescription vertex_bindings[] = { - Vertex::binding_description(), + vertex_binding_description(), }; - const auto vertex_attributes = Vertex::attributes_description(); + const auto vertex_attributes = vertex_attributes_description(); VkPipelineVertexInputStateCreateInfo vertex_info { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, @@ -420,6 +465,7 @@ void VulkanTutorial::create_graphic_pipeline() { .depthClampEnable = VK_FALSE, .rasterizerDiscardEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, + // .cullMode = VK_CULL_MODE_NONE, .cullMode = VK_CULL_MODE_BACK_BIT, .frontFace = VK_FRONT_FACE_CLOCKWISE, .depthBiasEnable = VK_FALSE, @@ -778,7 +824,7 @@ void VulkanTutorial::create_command_buffers() { command_buffer, m_index_buffer, 0, - VK_INDEX_TYPE_UINT16 + VK_INDEX_TYPE_UINT32 ); vkCmdDrawIndexed( diff --git a/src/VulkanTutorial.h b/src/VulkanTutorial.h index 78d3bd5..a8f4498 100644 --- a/src/VulkanTutorial.h +++ b/src/VulkanTutorial.h @@ -10,13 +10,8 @@ #include -struct Vertex { - Eigen::Vector3f position; - Eigen::Vector3f color; - - static VkVertexInputBindingDescription binding_description(); - static std::array attributes_description(); -}; +VkVertexInputBindingDescription vertex_binding_description(); +std::array vertex_attributes_description(); class VulkanTutorial {