├── .gitignore ├── overview.png ├── numberings.png ├── demo ├── CMakeLists.txt └── main.cpp ├── lib ├── Triangulation.h ├── IO.h ├── CMakeLists.txt ├── Cube.h ├── DataStructs.h ├── IO.cpp ├── MeshReconstruction.h ├── MeshReconstruction.cpp ├── Cube.cpp └── Triangulation.cpp ├── CMakeLists.txt └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | html/ 3 | latex/ 4 | -------------------------------------------------------------------------------- /overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Magnus2/MeshReconstruction/HEAD/overview.png -------------------------------------------------------------------------------- /numberings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Magnus2/MeshReconstruction/HEAD/numberings.png -------------------------------------------------------------------------------- /demo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories("." ${PROJECT_SOURCE_DIR}/lib) 2 | add_executable(Demo main.cpp) 3 | target_link_libraries (Demo MeshReconstruction) -------------------------------------------------------------------------------- /lib/Triangulation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Cube.h" 3 | #include "DataStructs.h" 4 | 5 | namespace MeshReconstruction 6 | { 7 | void Triangulate( 8 | IntersectInfo const& intersect, 9 | Fun3v const& grad, 10 | Mesh& mesh); 11 | } -------------------------------------------------------------------------------- /lib/IO.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "DataStructs.h" 4 | 5 | namespace MeshReconstruction 6 | { 7 | /// Writes a mesh to a file in obj format. 8 | void WriteObjFile(Mesh const& mesh, std::string const& file); 9 | } -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(MeshReconstruction MeshReconstruction.h MeshReconstruction.cpp Cube.h Cube.cpp DataStructs.h IO.h IO.cpp Triangulation.h Triangulation.cpp) 2 | 3 | install(TARGETS MeshReconstruction 4 | RUNTIME DESTINATION bin 5 | LIBRARY DESTINATION lib 6 | ARCHIVE DESTINATION lib) 7 | 8 | install(DIRECTORY . 9 | DESTINATION . 10 | FILES_MATCHING PATTERN "*.h") -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | project (MeshReconstruction) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | # Parallel compilation. 8 | if(WIN32) 9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4250") 11 | endif() 12 | 13 | set(CMAKE_DEBUG_POSTFIX "d") 14 | 15 | add_subdirectory(lib) 16 | add_subdirectory(demo) -------------------------------------------------------------------------------- /demo/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace MeshReconstruction; 5 | 6 | int main() 7 | { 8 | auto sphereSdf = [](Vec3 const& pos) 9 | { 10 | auto const Radius = 1.0; 11 | return pos.Norm() - Radius; 12 | }; 13 | 14 | Rect3 domain; 15 | domain.min = { -1.1, -1.1, -1.1 }; 16 | domain.size = {2.2, 2.2, 2.2}; 17 | 18 | Vec3 cubeSize{ 0.05, 0.05, 0.05 }; 19 | 20 | auto mesh = MarchCube(sphereSdf, domain, cubeSize); 21 | WriteObjFile(mesh, "sphere.obj"); 22 | } -------------------------------------------------------------------------------- /lib/Cube.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "DataStructs.h" 3 | 4 | namespace MeshReconstruction 5 | { 6 | struct IntersectInfo 7 | { 8 | // 0 - 255 9 | int signConfig; 10 | 11 | // If it exists, vertex on edge i is stored at position i. 12 | // For edge numbering and location see numberings.png. 13 | std::array edgeVertIndices; 14 | }; 15 | 16 | class Cube 17 | { 18 | Vec3 pos[8]; 19 | double sdf[8]; 20 | 21 | Vec3 LerpVertex(double isoLevel, int i1, int i2) const; 22 | int SignConfig(double isoLevel) const; 23 | 24 | public: 25 | Cube(Rect3 const& space, Fun3s const& sdf); 26 | 27 | // Find the vertices where the surface intersects the cube. 28 | IntersectInfo Intersect(double isoLevel = 0) const; 29 | }; 30 | } -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # MeshReconstruction 2 | 3 | This is a small library that can reconstruct a triangle mesh from a signed distance function using the Marching Cubes algorithm and export it to a file in the obj format. 4 | 5 | The library is self-contained and has no dependencies. The library is fast due to precomputed lookup tables and a narrow-band approach which excludes a lot of marching cubes that are far away from the surface. 6 | 7 | The library requires C++14 and has been tested under Visual Studio 2017 and Windows 10 but should port to other systems without major problems. 8 | 9 | The library can be used under the terms of the MIT License. 10 | 11 |

12 | Overview 13 |

-------------------------------------------------------------------------------- /lib/DataStructs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace MeshReconstruction 7 | { 8 | struct Vec3 9 | { 10 | double x, y, z; 11 | 12 | Vec3 operator+(Vec3 const& o) const 13 | { 14 | return { x + o.x, y + o.y, z + o.z }; 15 | } 16 | 17 | Vec3 operator-(Vec3 const& o) const 18 | { 19 | return { x - o.x, y - o.y, z - o.z }; 20 | } 21 | 22 | Vec3 operator*(double c) const 23 | { 24 | return { c*x, c*y, c*z }; 25 | } 26 | 27 | double Norm() const 28 | { 29 | return sqrt(x*x + y*y + z*z); 30 | } 31 | 32 | Vec3 Normalized() const 33 | { 34 | auto n = Norm(); 35 | return { x / n, y / n, z / n }; 36 | } 37 | }; 38 | 39 | struct Rect3 40 | { 41 | Vec3 min; 42 | Vec3 size; 43 | }; 44 | 45 | using Triangle = std::array; 46 | 47 | struct Mesh 48 | { 49 | std::vector vertices; 50 | std::vector triangles; 51 | std::vector vertexNormals; 52 | }; 53 | 54 | using Fun3s = std::function; 55 | using Fun3v = std::function; 56 | } -------------------------------------------------------------------------------- /lib/IO.cpp: -------------------------------------------------------------------------------- 1 | #include "IO.h" 2 | using namespace std; 3 | 4 | void MeshReconstruction::WriteObjFile(Mesh const& mesh, string const& fileName) 5 | { 6 | // FILE faster than streams. 7 | 8 | FILE* file; 9 | auto status = fopen_s(&file, fileName.c_str(), "w"); 10 | if (status != 0) 11 | { 12 | throw runtime_error("Could not write obj file."); 13 | } 14 | 15 | // write stats 16 | fprintf(file, "# %d vertices, %d triangles\n\n", 17 | static_cast(mesh.vertices.size()), 18 | static_cast(mesh.triangles.size())); 19 | 20 | // vertices 21 | for (auto vi = 0; vi < mesh.vertices.size(); ++vi) 22 | { 23 | auto const& v = mesh.vertices.at(vi); 24 | fprintf(file, "v %f %f %f\n", v.x, v.y, v.z); 25 | } 26 | 27 | // vertex normals 28 | fprintf(file, "\n"); 29 | for (auto ni = 0; ni < mesh.vertices.size(); ++ni) 30 | { 31 | auto const& vn = mesh.vertexNormals.at(ni); 32 | fprintf(file, "vn %f %f %f\n", vn.x, vn.y, vn.z); 33 | } 34 | 35 | // triangles (1-based) 36 | fprintf(file, "\n"); 37 | for (auto ti = 0; ti < mesh.triangles.size(); ++ti) 38 | { 39 | auto const& t = mesh.triangles.at(ti); 40 | fprintf(file, "f %d//%d %d//%d %d//%d\n", 41 | t[0] + 1, t[0] + 1, 42 | t[1] + 1, t[1] + 1, 43 | t[2] + 1, t[2] + 1); 44 | } 45 | 46 | fclose(file); 47 | } -------------------------------------------------------------------------------- /lib/MeshReconstruction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "DataStructs.h" 3 | 4 | namespace MeshReconstruction 5 | { 6 | /// Reconstructs a triangle mesh from a given signed distance function using Marching Cubes. 7 | /// @param sdf The Signed Distance Function. 8 | /// @param domain Domain of reconstruction. 9 | /// @returns The reconstructed mesh. 10 | Mesh MarchCube( 11 | Fun3s const& sdf, 12 | Rect3 const& domain); 13 | 14 | /// Reconstructs a triangle mesh from a given signed distance function using Marching Cubes. 15 | /// @param sdf The Signed Distance Function. 16 | /// @param domain Domain of reconstruction. 17 | /// @param cubeSize Size of marching cubes. Smaller cubes yields meshes of higher resolution. 18 | /// @param isoLevel Level set of the SDF for which triangulation should be done. Changing this value moves the reconstructed surface. 19 | /// @param sdfGrad Gradient of the SDF which yields the vertex normals of the reconstructed mesh. If none is provided a numerical approximation is used. 20 | /// @returns The reconstructed mesh. 21 | Mesh MarchCube( 22 | Fun3s const& sdf, 23 | Rect3 const& domain, 24 | Vec3 const& cubeSize, 25 | double isoLevel = 0, 26 | Fun3v sdfGrad = nullptr); 27 | } -------------------------------------------------------------------------------- /lib/MeshReconstruction.cpp: -------------------------------------------------------------------------------- 1 | #include "MeshReconstruction.h" 2 | #include "Cube.h" 3 | #include "Triangulation.h" 4 | 5 | using namespace MeshReconstruction; 6 | using namespace std; 7 | 8 | // Adapted from here: http://paulbourke.net/geometry/polygonise/ 9 | 10 | namespace 11 | { 12 | Vec3 NumGrad(Fun3s const& f, Vec3 const& p) 13 | { 14 | auto const Eps = 1e-6; 15 | Vec3 epsX{ Eps, 0, 0 }, epsY{ 0, Eps, 0 }, epsZ{ 0, 0, Eps }; 16 | auto gx = (f(p + epsX) - f(p - epsX)) / 2; 17 | auto gy = (f(p + epsY) - f(p - epsY)) / 2; 18 | auto gz = (f(p + epsZ) - f(p - epsZ)) / 2; 19 | return { gx, gy, gz }; 20 | } 21 | } 22 | 23 | Mesh MeshReconstruction::MarchCube(Fun3s const& sdf, Rect3 const& domain) 24 | { 25 | auto const NumCubes = 50; 26 | auto cubeSize = domain.size * (1.0 / NumCubes); 27 | 28 | return MarchCube(sdf, domain, cubeSize); 29 | } 30 | 31 | Mesh MeshReconstruction::MarchCube( 32 | Fun3s const& sdf, 33 | Rect3 const& domain, 34 | Vec3 const& cubeSize, 35 | double isoLevel, 36 | Fun3v sdfGrad) 37 | { 38 | // Default value. 39 | sdfGrad = sdfGrad == nullptr 40 | ? [&sdf](Vec3 const& p) { return NumGrad(sdf, p); } 41 | : sdfGrad; 42 | 43 | auto const NumX = static_cast(ceil(domain.size.x / cubeSize.x)); 44 | auto const NumY = static_cast(ceil(domain.size.y / cubeSize.y)); 45 | auto const NumZ = static_cast(ceil(domain.size.z / cubeSize.z)); 46 | 47 | auto const HalfCubeDiag = cubeSize.Norm() / 2.0; 48 | auto const HalfCubeSize = cubeSize * 0.5; 49 | 50 | Mesh mesh; 51 | 52 | for (auto ix = 0; ix < NumX; ++ix) 53 | { 54 | auto x = domain.min.x + ix * cubeSize.x; 55 | 56 | for (auto iy = 0; iy < NumY; ++iy) 57 | { 58 | auto y = domain.min.y + iy * cubeSize.y; 59 | 60 | for (auto iz = 0; iz < NumZ; ++iz) 61 | { 62 | auto z = domain.min.z + iz * cubeSize.z; 63 | Vec3 min{ x, y, z }; 64 | 65 | // Process only if cube lies within narrow band around surface. 66 | auto cubeCenter = min + HalfCubeSize; 67 | auto dist = abs(sdf(cubeCenter) - isoLevel); 68 | if (dist > HalfCubeDiag) continue; 69 | 70 | Cube cube({ min, cubeSize }, sdf); 71 | auto intersect = cube.Intersect(isoLevel); 72 | Triangulate(intersect, sdfGrad, mesh); 73 | } 74 | } 75 | } 76 | 77 | return mesh; 78 | } 79 | -------------------------------------------------------------------------------- /lib/Cube.cpp: -------------------------------------------------------------------------------- 1 | #include "Cube.h" 2 | 3 | using namespace MeshReconstruction; 4 | 5 | namespace 6 | { 7 | // Cube has 8 vertices. Each vertex can have positive or negative sign. 8 | // 2^8 = 256 possible configurations mapped to intersected edges in each case. 9 | // The 12 edges are numbered as 1, 2, 4, ..., 2048 and are stored as a 12-bit bitstring for each configuration. 10 | const int signConfigToIntersectedEdges[256] = { 11 | 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 12 | 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 13 | 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 14 | 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 15 | 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 16 | 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 17 | 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 18 | 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 19 | 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 20 | 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 21 | 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 22 | 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 23 | 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 24 | 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 25 | 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 26 | 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 27 | 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 28 | 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 29 | 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 30 | 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 31 | 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 32 | 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 33 | 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 34 | 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 35 | 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 36 | 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 37 | 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 38 | 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 39 | 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 40 | 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 41 | 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 42 | 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 }; 43 | 44 | struct Edge 45 | { 46 | int edgeFlag : 12; // flag: 1, 2, 4, ... 2048 47 | int vert0; // 0-7 48 | int vert1; // 0-7 49 | }; 50 | 51 | const Edge edges[12] = 52 | { 53 | { 1, 0, 1 }, // edge 0 54 | { 2, 1, 2 }, // edge 1 55 | { 4, 2, 3 }, // ... 56 | { 8, 3, 0 }, 57 | { 16, 4, 5 }, 58 | { 32, 5, 6 }, 59 | { 64, 6, 7 }, 60 | { 128, 7, 4 }, 61 | { 256, 0, 4 }, 62 | { 512, 1, 5 }, 63 | { 1024, 2, 6 }, 64 | { 2048, 3, 7 } // edge 11 65 | }; 66 | } 67 | 68 | Vec3 Cube::LerpVertex(double isoLevel, int i1, int i2) const 69 | { 70 | auto const Eps = 1e-5; 71 | auto const v1 = sdf[i1]; 72 | auto const v2 = sdf[i2]; 73 | auto const& p1 = pos[i1]; 74 | auto const& p2 = pos[i2]; 75 | 76 | if (abs(isoLevel - v1) < Eps) return p1; 77 | if (abs(isoLevel - v2) < Eps) return p2; 78 | if (abs(v1 - v2) < Eps) return p1; 79 | 80 | auto mu = (isoLevel - v1) / (v2 - v1); 81 | return p1 + (p2 - p1)*mu; 82 | } 83 | 84 | Cube::Cube(Rect3 const& space, Fun3s const& sdf) 85 | { 86 | auto mx = space.min.x; 87 | auto my = space.min.y; 88 | auto mz = space.min.z; 89 | 90 | auto sx = space.size.x; 91 | auto sy = space.size.y; 92 | auto sz = space.size.z; 93 | 94 | pos[0] = space.min; 95 | pos[1] = { mx + sx, my, mz }; 96 | pos[2] = { mx + sx, my, mz + sz }; 97 | pos[3] = { mx, my, mz + sz }; 98 | pos[4] = { mx, my + sy, mz }; 99 | pos[5] = { mx + sx, my + sy, mz }; 100 | pos[6] = { mx + sx, my + sy, mz + sz }; 101 | pos[7] = { mx, my + sy, mz + sz }; 102 | 103 | for (auto i = 0; i < 8; ++i) 104 | { 105 | auto sd = sdf(pos[i]); 106 | if (sd == 0) sd += 1e-6; 107 | this->sdf[i] = sd; 108 | } 109 | } 110 | 111 | int Cube::SignConfig(double isoLevel) const 112 | { 113 | auto edgeIndex = 0; 114 | 115 | for (auto i = 0; i < 8; ++i) 116 | { 117 | if (sdf[i] < isoLevel) 118 | { 119 | edgeIndex |= 1 << i; 120 | } 121 | } 122 | 123 | return edgeIndex; 124 | } 125 | 126 | IntersectInfo Cube::Intersect(double iso) const 127 | { 128 | // idea: 129 | // from signs at 8 corners of cube a sign configuration (256 possible ones) is computed 130 | // this configuration can be used to index into a table that tells which of the 12 edges are intersected 131 | // find vertices adjacent to edges and interpolate cut vertex and store it in IntersectionInfo object 132 | 133 | IntersectInfo intersect; 134 | intersect.signConfig = SignConfig(iso); 135 | 136 | for (auto e = 0; e<12; ++e) 137 | { 138 | if (signConfigToIntersectedEdges[intersect.signConfig] & edges[e].edgeFlag) 139 | { 140 | auto v0 = edges[e].vert0; 141 | auto v1 = edges[e].vert1; 142 | auto vert = LerpVertex(iso, v0, v1); 143 | intersect.edgeVertIndices[e] = vert; 144 | } 145 | } 146 | 147 | return intersect; 148 | } 149 | -------------------------------------------------------------------------------- /lib/Triangulation.cpp: -------------------------------------------------------------------------------- 1 | #include "Triangulation.h" 2 | 3 | namespace 4 | { 5 | // Indices into vertex buffer (0 - 11). 6 | // Three successive entries make up one triangle. 7 | // -1 means unused. 8 | const int signConfigToTriangles[256][16] = 9 | { { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 10 | { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 11 | { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 12 | { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 13 | { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 14 | { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 15 | { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 16 | { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, 17 | { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 18 | { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 19 | { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 20 | { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, 21 | { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 22 | { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, 23 | { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, 24 | { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 25 | { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 26 | { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 27 | { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 28 | { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, 29 | { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 30 | { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 }, 31 | { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, 32 | { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, 33 | { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 34 | { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, 35 | { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, 36 | { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 }, 37 | { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, 38 | { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 }, 39 | { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, 40 | { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, 41 | { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 42 | { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 43 | { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 44 | { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, 45 | { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 46 | { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, 47 | { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, 48 | { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 }, 49 | { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 50 | { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, 51 | { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, 52 | { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 }, 53 | { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, 54 | { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 }, 55 | { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, 56 | { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, 57 | { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 58 | { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, 59 | { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, 60 | { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 61 | { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, 62 | { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 }, 63 | { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, 64 | { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, 65 | { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, 66 | { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, 67 | { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, 68 | { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, 69 | { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, 70 | { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 }, 71 | { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, 72 | { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 73 | { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 74 | { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 75 | { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 76 | { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, 77 | { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 78 | { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 }, 79 | { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, 80 | { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 }, 81 | { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 82 | { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, 83 | { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, 84 | { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 }, 85 | { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, 86 | { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, 87 | { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, 88 | { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, 89 | { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 90 | { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 }, 91 | { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, 92 | { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, 93 | { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, 94 | { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 }, 95 | { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, 96 | { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 }, 97 | { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, 98 | { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, 99 | { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, 100 | { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 }, 101 | { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, 102 | { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 }, 103 | { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, 104 | { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 }, 105 | { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 106 | { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 }, 107 | { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, 108 | { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, 109 | { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, 110 | { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 }, 111 | { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 112 | { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, 113 | { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, 114 | { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 }, 115 | { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, 116 | { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 }, 117 | { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, 118 | { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 }, 119 | { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, 120 | { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 121 | { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, 122 | { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 }, 123 | { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, 124 | { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, 125 | { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, 126 | { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 }, 127 | { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, 128 | { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 129 | { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, 130 | { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 }, 131 | { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, 132 | { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 }, 133 | { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, 134 | { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 135 | { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, 136 | { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 137 | { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 138 | { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 139 | { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 140 | { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, 141 | { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 142 | { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, 143 | { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, 144 | { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 }, 145 | { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 146 | { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, 147 | { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, 148 | { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 }, 149 | { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, 150 | { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 }, 151 | { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, 152 | { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, 153 | { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 154 | { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, 155 | { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, 156 | { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 }, 157 | { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, 158 | { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 }, 159 | { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, 160 | { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 }, 161 | { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, 162 | { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 163 | { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, 164 | { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, 165 | { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, 166 | { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, 167 | { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, 168 | { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 169 | { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 170 | { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, 171 | { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, 172 | { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 }, 173 | { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, 174 | { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 }, 175 | { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, 176 | { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 }, 177 | { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, 178 | { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 }, 179 | { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, 180 | { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 }, 181 | { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, 182 | { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 }, 183 | { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, 184 | { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 }, 185 | { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, 186 | { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 }, 187 | { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, 188 | { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, 189 | { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, 190 | { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 }, 191 | { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, 192 | { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 }, 193 | { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, 194 | { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, 195 | { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, 196 | { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 197 | { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, 198 | { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 }, 199 | { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 200 | { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 201 | { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 202 | { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 }, 203 | { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, 204 | { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 }, 205 | { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, 206 | { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 }, 207 | { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, 208 | { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 }, 209 | { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, 210 | { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 }, 211 | { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, 212 | { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 }, 213 | { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 214 | { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, 215 | { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, 216 | { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 217 | { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, 218 | { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 }, 219 | { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, 220 | { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 }, 221 | { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, 222 | { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 }, 223 | { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, 224 | { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 225 | { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, 226 | { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, 227 | { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, 228 | { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 }, 229 | { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, 230 | { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 231 | { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, 232 | { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 233 | { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, 234 | { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 }, 235 | { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, 236 | { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 }, 237 | { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, 238 | { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 }, 239 | { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, 240 | { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 }, 241 | { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, 242 | { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 }, 243 | { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, 244 | { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 245 | { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, 246 | { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 }, 247 | { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 248 | { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 249 | { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 250 | { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, 251 | { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, 252 | { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 253 | { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, 254 | { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 }, 255 | { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 256 | { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 257 | { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, 258 | { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 259 | { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, 260 | { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 261 | { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 262 | { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 263 | { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, 264 | { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }; 265 | } 266 | 267 | /// Given a grid cube and an isolevel the triangles (5 max) 268 | /// required to represent the isosurface in the cube are computed. 269 | void MeshReconstruction::Triangulate( 270 | IntersectInfo const& intersect, 271 | Fun3v const& grad, 272 | Mesh& mesh) 273 | { 274 | // Cube is entirely in/out of the surface. Generate no triangles. 275 | if (intersect.signConfig == 0 || intersect.signConfig == 255) return; 276 | 277 | auto const& tri = signConfigToTriangles[intersect.signConfig]; 278 | 279 | for (auto i = 0; tri[i] != -1; i += 3) 280 | { 281 | auto const& v0 = intersect.edgeVertIndices[tri[i]]; 282 | auto const& v1 = intersect.edgeVertIndices[tri[i + 1]]; 283 | auto const& v2 = intersect.edgeVertIndices[tri[i + 2]]; 284 | 285 | mesh.vertices.push_back(v0); 286 | mesh.vertices.push_back(v1); 287 | mesh.vertices.push_back(v2); 288 | 289 | auto normal0 = grad(v0).Normalized(); 290 | auto normal1 = grad(v1).Normalized(); 291 | auto normal2 = grad(v2).Normalized(); 292 | 293 | mesh.vertexNormals.push_back(normal0); 294 | mesh.vertexNormals.push_back(normal1); 295 | mesh.vertexNormals.push_back(normal2); 296 | 297 | auto last = static_cast(mesh.vertices.size() - 1); 298 | 299 | mesh.triangles.push_back({ last - 2, last - 1, last }); 300 | } 301 | } --------------------------------------------------------------------------------