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