|
| 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 | +} |
0 commit comments