Compare commits

...

2 Commits

Author SHA1 Message Date
6f4a8461a9 Simplified code. 2022-02-18 23:28:45 +01:00
803a3cf87e Mesh WIP. 2022-02-18 23:05:38 +01:00
4 changed files with 306 additions and 140 deletions

View File

@@ -6,11 +6,6 @@
#include <vector> #include <vector>
Vector3 lerp(Real factor, const Vector3& v0, const Vector3& v1) {
return (Real(1) - factor) * v0 + factor * v1;
}
Cell::Cell( Cell::Cell(
const Vector3& corner00, const Vector3& corner00,
const Vector3& corner01, const Vector3& corner01,
@@ -18,13 +13,13 @@ Cell::Cell(
const Vector3& corner11 const Vector3& corner11
) )
: m_corners{ corner00, corner01, corner10, corner11 } : m_corners{ corner00, corner01, corner10, corner11 }
, m_heightFactor(heightFactor(m_corners)) , m_height_factor(height_factor(m_corners))
, m_cells{ nullptr, nullptr, nullptr, nullptr } , m_cells{ nullptr, nullptr, nullptr, nullptr }
{} {}
Cell& Cell::cell(uint32_t cellIndex) { Cell& Cell::cell(uint32_t cell_index) {
assert(cellIndex < CellCount); assert(cell_index < CellCount);
auto& cell = m_cells[cellIndex]; auto& cell = m_cells[cell_index];
if(!cell) if(!cell)
{ {
// TODO // TODO
@@ -32,119 +27,166 @@ Cell& Cell::cell(uint32_t cellIndex) {
return *cell; return *cell;
} }
void Cell::writeMesh( size_t Cell::vertex_count(uint32_t subdiv_count) {
Vertex*& vertices, const Vertex* verticesEnd, auto const s2 = 1 << subdiv_count;
uint32_t*& indices, const uint32_t* indicesEnd, return s2 * s2 + 2 * s2 + 1;
uint32_t subdivCount }
size_t Cell::triangle_count(uint32_t subdiv_count) {
auto const s2 = 1 << subdiv_count;
return 2 * s2 * s2;
}
void Cell::build_mesh(
Vector3AV positions, TriangleAV triangles,
uint32_t subdiv_count, Index index_offset
) const { ) const {
auto const sideEdgeCount = (1u << subdivCount); auto const side_edge_count = (1u << subdiv_count);
auto const sideVertCount = sideEdgeCount + 1; auto const side_vert_count = side_edge_count + 1;
auto const quadCount = sideEdgeCount * sideEdgeCount; auto const quad_count = side_edge_count * side_edge_count;
auto const triCount = 2 * quadCount; auto const tri_count = 2 * quad_count;
auto const vertCount = sideVertCount * sideVertCount; auto const vert_count = side_vert_count * side_vert_count;
assert(vertices + vertCount <= verticesEnd); assert(positions.size() == vert_count);
assert(indices + (3 * triCount) <= indicesEnd); assert(triangles.size() == tri_count);
auto const index = [sideVertCount](uint32_t x, uint32_t y) -> uint32_t { auto const index = [side_vert_count](uint32_t x, uint32_t y) -> uint32_t {
return x + y * sideVertCount; return x + y * side_vert_count;
}; };
auto const vertex = [vertices, &index](uint32_t x, uint32_t y) -> Vertex& { auto const vertex = [&positions, &index](uint32_t x, uint32_t y) -> Vector3& {
return vertices[index(x, y)]; return positions[index(x, y)];
}; };
Vector3 c00(0.0f, 0.0f, 1.0f); vertex( 0, 0) = m_corners[0];
Vector3 c01(1.0f, 0.0f, 1.0f); vertex(side_edge_count, 0) = m_corners[1];
Vector3 c10(0.0f, 1.0f, 1.0f); vertex( 0, side_edge_count) = m_corners[2];
Vector3 c11(1.0f, 1.0f, 1.0f); vertex(side_edge_count, side_edge_count) = m_corners[3];
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 { struct QuadCell {
uint32_t x0, x1, y0, y1; uint32_t x0, x1, y0, y1;
}; };
std::vector<QuadCell> stack; std::vector<QuadCell> stack;
stack.reserve(quadCount / 4); stack.reserve(quad_count / 4);
if(subdivCount > 0) { if(subdiv_count > 0) {
stack.emplace_back(QuadCell { stack.emplace_back(QuadCell {
0, sideEdgeCount, 0, side_edge_count,
0, sideEdgeCount, 0, side_edge_count,
}); });
} }
while(!stack.empty()) { while(!stack.empty()) {
const auto quadCell = stack.back(); const auto quad_cell = stack.back();
stack.pop_back(); stack.pop_back();
auto const mx = (quadCell.x0 + quadCell.x1) / 2; auto const mx = (quad_cell.x0 + quad_cell.x1) / 2;
auto const my = (quadCell.y0 + quadCell.y1) / 2; auto const my = (quad_cell.y0 + quad_cell.y1) / 2;
auto const& v00 = vertex(quadCell.x0, quadCell.y0).position; auto const& v00 = vertex(quad_cell.x0, quad_cell.y0);
auto const& v01 = vertex(quadCell.x1, quadCell.y0).position; auto const& v01 = vertex(quad_cell.x1, quad_cell.y0);
auto const& v10 = vertex(quadCell.x0, quadCell.y1).position; auto const& v10 = vertex(quad_cell.x0, quad_cell.y1);
auto const& v11 = vertex(quadCell.x1, quadCell.y1).position; auto const& v11 = vertex(quad_cell.x1, quad_cell.y1);
setVertex( mx, quadCell.y0, vertex( mx, quad_cell.y0) =
(v00 + v01).normalized() (v00 + v01).normalized();
); vertex(quad_cell.x0, my) =
setVertex(quadCell.x0, my, (v00 + v10).normalized();
(v00 + v10).normalized() vertex(mx, my) =
); (v00 + v01 + v10 + v11).normalized();
setVertex(mx, my, vertex(quad_cell.x1, my) =
(v00 + v01 + v10 + v11).normalized() (v01 + v11).normalized();
); vertex( mx, quad_cell.y1) =
setVertex(quadCell.x1, my, (v10 + v11).normalized();
(v01 + v11).normalized()
);
setVertex( mx, quadCell.y1,
(v10 + v11).normalized()
);
if(quadCell.x0 + 1 < mx) { if(quad_cell.x0 + 1 < mx) {
stack.emplace_back(QuadCell { mx, quadCell.x1, my, quadCell.y1 }); stack.emplace_back(QuadCell { mx, quad_cell.x1, my, quad_cell.y1 });
stack.emplace_back(QuadCell { quadCell.x0, mx, my, quadCell.y1 }); stack.emplace_back(QuadCell { quad_cell.x0, mx, my, quad_cell.y1 });
stack.emplace_back(QuadCell { mx, quadCell.x1, quadCell.y0, my }); stack.emplace_back(QuadCell { mx, quad_cell.x1, quad_cell.y0, my });
stack.emplace_back(QuadCell { quadCell.x0, mx, quadCell.y0, my }); stack.emplace_back(QuadCell { quad_cell.x0, mx, quad_cell.y0, my });
} }
} }
vertices += vertCount;
for(uint32_t y = 0; y < sideEdgeCount; y += 1) { auto triangleIndex = 0;
for(uint32_t x = 0; x < sideEdgeCount; x += 1) { for(uint32_t y = 0; y < side_edge_count; y += 1) {
const auto i00 = index(x, y); for(uint32_t x = 0; x < side_edge_count; x += 1) {
const auto i00 = index_offset + index(x, y);
const auto i01 = i00 + 1; const auto i01 = i00 + 1;
const auto i10 = i00 + sideVertCount; const auto i10 = i00 + side_vert_count;
const auto i11 = i10 + 1; const auto i11 = i10 + 1;
*(indices++) = i00; triangles[triangleIndex++] = Triangle { i00, i01, i10 };
*(indices++) = i01; triangles[triangleIndex++] = Triangle { i10, i01, i11 };
*(indices++) = i10;
*(indices++) = i10;
*(indices++) = i01;
*(indices++) = i11;
} }
} }
} }
Real Cell::heightFactor(Vector3 corners[CornerCount]) { Real Cell::height_factor(Vector3 corners[CornerCount]) {
Vector3 c = (corners[0] + corners[1] + corners[2] + corners[3]).normalized(); Vector3 c = (corners[0] + corners[1] + corners[2] + corners[3]).normalized();
return Real(1) / corners[0].dot(c); return Real(1) / corners[0].dot(c);
} }
Planet::Planet()
: m_cells {
{
Vector3(-1.0, -1.0, -1.0).normalized(),
Vector3( 1.0, -1.0, -1.0).normalized(),
Vector3(-1.0, 1.0, -1.0).normalized(),
Vector3( 1.0, 1.0, -1.0).normalized(),
},
{
Vector3( 1.0, -1.0, -1.0).normalized(),
Vector3( 1.0, -1.0, 1.0).normalized(),
Vector3( 1.0, 1.0, -1.0).normalized(),
Vector3( 1.0, 1.0, 1.0).normalized(),
},
{
Vector3( 1.0, -1.0, 1.0).normalized(),
Vector3(-1.0, -1.0, 1.0).normalized(),
Vector3( 1.0, 1.0, 1.0).normalized(),
Vector3(-1.0, 1.0, 1.0).normalized(),
},
{
Vector3(-1.0, -1.0, 1.0).normalized(),
Vector3(-1.0, -1.0, -1.0).normalized(),
Vector3(-1.0, 1.0, 1.0).normalized(),
Vector3(-1.0, 1.0, -1.0).normalized(),
},
{
Vector3(-1.0, -1.0, 1.0).normalized(),
Vector3( 1.0, -1.0, 1.0).normalized(),
Vector3(-1.0, -1.0, -1.0).normalized(),
Vector3( 1.0, -1.0, -1.0).normalized(),
},
{
Vector3(-1.0, 1.0, -1.0).normalized(),
Vector3( 1.0, 1.0, -1.0).normalized(),
Vector3(-1.0, 1.0, 1.0).normalized(),
Vector3( 1.0, 1.0, 1.0).normalized(),
},
}
{}
void Planet::build_mesh(
Vector3AV positions, TriangleAV triangles,
uint32_t subdiv_count, Index index_offset
) const {
auto const vertex_count = Cell::vertex_count(subdiv_count);
auto const index_count = Cell::triangle_count(subdiv_count);
for(Index cell_index = 0; cell_index < CellCount; cell_index += 1) {
auto sub_positions = positions.slice(
cell_index * vertex_count, vertex_count
);
auto sub_triangles = triangles.slice(
cell_index * index_count, index_count
);
cell(cell_index).build_mesh(
sub_positions,
sub_triangles,
subdiv_count,
index_offset + cell_index * vertex_count
);
}
}

View File

@@ -1,13 +1,11 @@
#pragma once #pragma once
#include <Eigen/Dense> #include <core.h>
#include <memory> #include <memory>
#include <cassert>
using Real = float;
using Vector3 = Eigen::Matrix<Real, 3, 1>;
class Cell; class Cell;
using CellUP = std::unique_ptr<Cell>; using CellUP = std::unique_ptr<Cell>;
@@ -18,9 +16,6 @@ struct Vertex {
}; };
Vector3 lerp(Real factor, const Vector3& v0, const Vector3& v1);
class Cell { class Cell {
public: public:
static constexpr uint32_t CornerCount = 4; static constexpr uint32_t CornerCount = 4;
@@ -40,20 +35,22 @@ public:
Cell& operator=(const Cell&) = delete; Cell& operator=(const Cell&) = delete;
Cell& operator=(Cell&&) = default; Cell& operator=(Cell&&) = default;
Cell& cell(uint32_t cellIndex); Cell& cell(uint32_t cell_index);
void writeMesh( static size_t vertex_count(uint32_t subdiv_count);
Vertex*& vertices, const Vertex* verticesEnd, static size_t triangle_count(uint32_t subdiv_count);
uint32_t*& indices, const uint32_t* indicesEnd,
uint32_t subdivCount = 4 void build_mesh(
Vector3AV positions, TriangleAV triangles,
uint32_t subdiv_count=4, Index index_offset=0
) const; ) const;
private: private:
static Real heightFactor(Vector3 corners[CornerCount]); static Real height_factor(Vector3 corners[CornerCount]);
private: private:
Vector3 m_corners[CornerCount]; Vector3 m_corners[CornerCount];
Real m_heightFactor; Real m_height_factor;
CellUP m_cells[CellCount]; CellUP m_cells[CellCount];
}; };
@@ -71,8 +68,19 @@ public:
Planet& operator=(const Planet&) = delete; Planet& operator=(const Planet&) = delete;
Planet& operator=(Planet&&) = default; Planet& operator=(Planet&&) = default;
Cell& cell(uint32_t cellIndex); inline const Cell& cell(uint32_t cell_index) const {
assert(cell_index < CellCount);
return m_cells[cell_index];
}
inline Cell& cell(uint32_t cell_index) {
assert(cell_index < CellCount);
return m_cells[cell_index];
}
void build_mesh(Vector3AV positions, TriangleAV triangles,
uint32_t subdiv_count=4, Index index_offset=0) const;
private: private:
CellUP m_cells[CellCount]; Cell m_cells[CellCount];
}; };

View File

@@ -86,48 +86,55 @@ VulkanTutorial::VulkanTutorial() {
m_swapchain.register_destruction_callback( m_swapchain.register_destruction_callback(
std::bind(&VulkanTutorial::destroy_swapchain_objects, this)); std::bind(&VulkanTutorial::destroy_swapchain_objects, this));
auto const subdivCount = 2; auto const subdiv_count = 4;
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{ vertices.resize(6 * Cell::vertex_count(subdiv_count));
Vector3::Constant(std::numeric_limits<Real>::quiet_NaN()), indices.resize(6 * 3 * Cell::triangle_count(subdiv_count));
Vector3::Zero()
});
indices.assign(indexCount, UINT32_MAX);
Cell cell( // MeshView mesh(
Vector3(-1.0f, -1.0f, 1.0f).normalized(), // vertices.size(),
Vector3( 1.0f, -1.0f, 1.0f).normalized(), // reinterpret_cast<Byte*>(vertices.data()) + offsetof(Vertex, position),
Vector3(-1.0f, -1.0f, -1.0f).normalized(), // sizeof(Vertex),
Vector3( 1.0f, -1.0f, -1.0f).normalized() // nullptr,
// sizeof(Vertex),
// reinterpret_cast<Byte*>(vertices.data()) + offsetof(Vertex, color),
// sizeof(Vertex),
// indices.size(),
// reinterpret_cast<Byte*>(indices.data()),
// sizeof(Index)
// );
Vector3AV positions(
vertices.size(), vertices.data(),
sizeof(Vertex), offsetof(Vertex, position)
); );
auto vertex = &*vertices.begin(); Vector3AV colors(
const auto verticesEnd = &*vertices.end(); vertices.size(), vertices.data(),
auto index = &*indices.begin(); sizeof(Vertex), offsetof(Vertex, color)
const auto indicesEnd = &*indices.end();
cell.writeMesh(
vertex, verticesEnd,
index, indicesEnd,
subdivCount
); );
logger.info() << "Vertices:"; TriangleAV triangles(
for(auto v = &*vertices.begin(); v < vertex; v += 1) indices.size() / 3,
logger.debug() << (v - &*vertices.begin()) << ": " indices.data()
<< v->position.transpose() << " - " );
<< v->color.transpose();
logger.info() << "Indices:"; Planet planet;
for(auto i = &*indices.begin(); i < index; i += 6) planet.build_mesh(positions, triangles, subdiv_count);
logger.debug() << (i - &*indices.begin()) << ": "
<< i[0] << ", " << i[1] << ", " << i[2] << " - "
<< i[3] << ", " << i[4] << ", " << i[5];
for (size_t vertex_index = 0; vertex_index < vertices.size(); vertex_index += 1) {
colors[vertex_index] =
positions[vertex_index] / 2.0f + Vector3::Constant(0.5f);
}
// for(size_t vi = 0; vi < vertices.size(); vi += 1)
// logger.debug() << "v" << vi << ": "
// << vertices[vi].position.transpose();
// for(size_t ii = 0; 3 * ii < indices.size(); ii += 1)
// logger.debug() << "i" << ii << ": "
// << indices[3 * ii + 0] << ", "
// << indices[3 * ii + 1] << ", "
// << indices[3 * ii + 2];
// abort(); // abort();
} }

109
src/core.h Normal file
View File

@@ -0,0 +1,109 @@
#pragma once
#include <Eigen/Dense>
#include <type_traits>
using Byte = unsigned char;
using Index = uint32_t;
using Real = float;
using Vector3 = Eigen::Matrix<Real, 3, 1>;
using Triangle = Eigen::Array<Index, 3, 1>;
template<typename Scalar, typename Derived0, typename Derived1>
auto lerp(
Scalar factor,
const Eigen::MatrixBase<Derived0>& m0,
const Eigen::MatrixBase<Derived1>& m1
) -> std::enable_if_t<
Derived0::RowsAtCompileTime == Derived1::RowsAtCompileTime &&
Derived0::ColsAtCompileTime == Derived1::ColsAtCompileTime,
Eigen::Matrix<
std::common_type_t<
Scalar,
typename Derived0::Scalar,
typename Derived1::Scalar
>,
Derived0::RowsAtCompileTime,
Derived0::ColsAtCompileTime
>
> {
return (Scalar(1) - factor) * m0 + factor * m1;
}
template<typename T>
class ArrayView {
public:
ArrayView() = default;
ArrayView(const ArrayView&) = default;
ArrayView(ArrayView&&) = default;
~ArrayView() = default;
template<typename U>
ArrayView(Index size, U* data, Index stride=sizeof(T), Index byte_offset=0)
: m_data(reinterpret_cast<Byte*>(data) + byte_offset)
, m_size(size)
, m_stride(stride)
{
assert(m_data != nullptr || m_size == 0);
}
explicit ArrayView(std::vector<T>& vector)
: m_data(vector.data())
, m_data(vector.size())
{}
ArrayView& operator=(const ArrayView&) = default;
ArrayView& operator=(ArrayView&&) = default;
explicit operator bool() const {
return m_size != 0;
}
Index size() const {
return m_size;
}
Index stride() const {
return m_stride;
}
const T* data() const {
return m_data;
}
T* data() {
return m_data;
}
const T& operator[](Index index) const {
assert(index < m_size);
return *reinterpret_cast<T*>(m_data + index * m_stride);
}
T& operator[](Index index) {
return const_cast<T&>(const_cast<const ArrayView&>(*this)[index]);
}
ArrayView slice(Index start, Index count, Index step=1) {
assert(step > 0);
assert(start + count * step <= m_size);
return ArrayView(
count,
m_data + start * m_stride,
m_stride * step
);
}
private:
Byte* m_data = nullptr;
Index m_size = 0;
Index m_stride = sizeof(T);
};
using Vector3AV = ArrayView<Vector3>;
using TriangleAV = ArrayView<Triangle>;