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