Experimentation using Vulkan.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

230 lines
7.3 KiB

#include <Planet.h>
#include <Logger.h>
#include <cassert>
#include <vector>
Cell::Cell(
const Vector3& corner00,
const Vector3& corner01,
const Vector3& corner10,
const Vector3& corner11
)
: m_corners{ corner00, corner01, corner10, corner11 }
, m_height_factor(height_factor(m_corners))
, m_cells{ nullptr, nullptr, nullptr, nullptr }
{}
Cell& Cell::cell(uint32_t cell_index) {
assert(cell_index < CellCount);
auto& cell = m_cells[cell_index];
if(!cell)
{
// TODO
}
return *cell;
}
size_t Cell::vertex_count(uint32_t subdiv_count) {
auto const s2 = 1 << subdiv_count;
return s2 * s2 + 2 * s2 + 1;
}
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, Vector3AV positions2, Vector3AV normals, TriangleAV triangles,
uint32_t subdiv_count, Index index_offset
) const {
auto const side_edge_count = (1u << subdiv_count);
auto const side_vert_count = side_edge_count + 1;
auto const quad_count = side_edge_count * side_edge_count;
auto const tri_count = 2 * quad_count;
auto const vert_count = side_vert_count * side_vert_count;
assert(positions.size() == vert_count);
assert(triangles.size() == tri_count);
auto const index = [side_vert_count](uint32_t x, uint32_t y) -> uint32_t {
return x + y * side_vert_count;
};
auto const vertex = [&normals, &index](uint32_t x, uint32_t y) -> Vector3& {
return normals[index(x, y)];
};
vertex( 0, 0) = m_corners[0];
vertex(side_edge_count, 0) = m_corners[1];
vertex( 0, side_edge_count) = m_corners[2];
vertex(side_edge_count, side_edge_count) = m_corners[3];
struct QuadCell {
uint32_t x0, x1, y0, y1;
};
std::vector<QuadCell> stack;
stack.reserve(quad_count / 4);
if(subdiv_count > 0) {
stack.emplace_back(QuadCell {
0, side_edge_count,
0, side_edge_count,
});
}
while(!stack.empty()) {
const auto quad_cell = stack.back();
stack.pop_back();
auto const mx = (quad_cell.x0 + quad_cell.x1) / 2;
auto const my = (quad_cell.y0 + quad_cell.y1) / 2;
auto const& v00 = vertex(quad_cell.x0, quad_cell.y0);
auto const& v01 = vertex(quad_cell.x1, quad_cell.y0);
auto const& v10 = vertex(quad_cell.x0, quad_cell.y1);
auto const& v11 = vertex(quad_cell.x1, quad_cell.y1);
vertex( mx, quad_cell.y0) =
(v00 + v01).normalized();
vertex(quad_cell.x0, my) =
(v00 + v10).normalized();
vertex(mx, my) =
(v00 + v01 + v10 + v11).normalized();
vertex(quad_cell.x1, my) =
(v01 + v11).normalized();
vertex( mx, quad_cell.y1) =
(v10 + v11).normalized();
if(quad_cell.x0 + 1 < mx) {
stack.emplace_back(QuadCell { mx, quad_cell.x1, my, quad_cell.y1 });
stack.emplace_back(QuadCell { quad_cell.x0, mx, my, quad_cell.y1 });
stack.emplace_back(QuadCell { mx, quad_cell.x1, quad_cell.y0, my });
stack.emplace_back(QuadCell { quad_cell.x0, mx, quad_cell.y0, my });
}
}
for (Index index = 0; index < normals.size(); index += 1) {
positions[index] = normals[index];
}
int x_offset = (
m_corners[0][0] < m_corners[1][0] ||
m_corners[0][1] < m_corners[1][1] ||
m_corners[0][2] < m_corners[1][2]
)? -1: 1;
int y_offset = (
m_corners[0][0] < m_corners[2][0] ||
m_corners[0][1] < m_corners[2][1] ||
m_corners[0][2] < m_corners[2][2]
)? -1: 1;
for(Index y = 0; y < side_vert_count; y += 1) {
for(Index x = 0; x < side_vert_count; x += 1) {
Index x2 = x + (x & 0x01) * x_offset;
Index y2 = y + (y & 0x01) * y_offset;
positions2[index(x, y)] = positions[index(x2, y2)];
}
}
auto triangleIndex = 0;
bool flip = false; // (x_offset > 0) ^ (y_offset > 0);
for(Index y = 0; y < side_edge_count; y += 1) {
for(Index x = 0; x < side_edge_count; x += 1) {
const auto i00 = index_offset + index(x, y);
const auto i01 = i00 + 1;
const auto i10 = i00 + side_vert_count;
const auto i11 = i10 + 1;
if (flip) {
triangles[triangleIndex++] = Triangle { i00, i01, i11 };
triangles[triangleIndex++] = Triangle { i00, i11, i10 };
}
else {
triangles[triangleIndex++] = Triangle { i00, i01, i10 };
triangles[triangleIndex++] = Triangle { i10, i01, i11 };
}
}
}
}
Real Cell::height_factor(Vector3 corners[CornerCount]) {
Vector3 c = (corners[0] + corners[1] + corners[2] + corners[3]).normalized();
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, Vector3AV positions2, Vector3AV normals, 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_positions2 = positions2.slice(
cell_index * vertex_count, vertex_count
);
auto sub_normals = normals.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_positions2,
sub_normals,
sub_triangles,
subdiv_count,
index_offset + cell_index * vertex_count
);
}
}