Advertisement
Guest User

voxel polygonization

a guest
Aug 30th, 2011
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.98 KB | None | 0 0
  1. #define HINIBBLE(b) (((b) >> 4) & 0x0F)
  2. #define LONIBBLE(b) ((b) & 0x0F)
  3.  
  4. enum {
  5.     PRIMARY   = 0,
  6.     SECONDARY = 1
  7. };
  8.  
  9. struct vertex {
  10.     Vector3d pos[2]; // The primary and secondary positions of the vertex.
  11.     Vector3d normal; // The surface normal at the vertex.
  12.     u8 near;         // The proximity of the vertex to the six faces of the block.
  13. };
  14.  
  15. struct VolumeData
  16. {
  17.     VolumeData(const Vector3i & dim)
  18.         : size(dim)
  19.     {
  20.         offset << 0, 0, 0;
  21.         samples.resize(dim.x() * dim.y() * dim.z(), 0);
  22.     }
  23.  
  24.     VolumeData(const Vector3i & dim, const Vector3i & origin)
  25.         : size(dim)
  26.         , offset(origin)
  27.     {
  28.        
  29.         samples.resize(dim.x() * dim.y() * dim.z(), 0);
  30.     }
  31.  
  32.     inline i8 & operator[](const Vector3i & p)
  33.     {
  34.         const Vector3i v = p - offset;
  35.         return samples[v.x() + v.y() * size.x() + v.z() * (size.x() * size.y())];
  36.     }
  37.  
  38.     inline const i8 & operator[](const Vector3i & p) const
  39.     {
  40.         const Vector3i v = p - offset;
  41.         return samples[v.x() + v.y() * size.x() + v.z() * (size.x() * size.y())];
  42.     }
  43.  
  44.     const char * buf() const {
  45.         return &samples[0];
  46.     }
  47.  
  48.     const std::size_t bufsize() const {
  49.         return samples.size();
  50.     }
  51.  
  52. private:
  53.     std::vector<i8> samples;
  54.     Vector3i size;
  55.     Vector3i offset;
  56. };
  57.  
  58. const int BLOCK_WIDTH = 16;
  59.  
  60. struct regular_cell_cache {
  61.  
  62.     struct cell {
  63.         u8 caseIndex;
  64.         int verts[4];
  65.     };
  66.  
  67.     cell & get(int x, int y, int z) {
  68.         return cache[z&1][y * BLOCK_WIDTH + x];
  69.     }
  70.  
  71.     cell & get(const Vector3i & p) {
  72.         return get(p.x(), p.y(), p.z());
  73.     }
  74.  
  75. private:
  76.     cell cache[2][BLOCK_WIDTH * BLOCK_WIDTH];
  77. };
  78.  
  79. struct transition_cell_cache {
  80.  
  81.     struct cell {
  82.         int verts[10]; // The ten vertices that can be reused by other cells.
  83.     };
  84.  
  85.     cell & get(int x, int y) {
  86.         return cache[y&1][x];
  87.     }
  88. private:
  89.     cell cache[2][BLOCK_WIDTH];
  90. };
  91.  
  92. inline int sign(i8 x) {
  93.     return (x >> 7) & 1;
  94. }
  95.  
  96. inline const Vector3d interp(Vector3i v0, Vector3i v1, // Position of vertices
  97.                              Vector3i p0, Vector3i p1, // Position of sample points
  98.                              const VolumeData & samples, u8 lodIndex = 0)
  99. {
  100.     i8 s0 = samples[p0];
  101.     i8 s1 = samples[p1];
  102.  
  103.     i32 t = (s1 << 8) / (s1 - s0);
  104.     i32 u = 0x0100 - t;
  105.     const double s = 1.0 / 256.0;
  106.  
  107.     if ((t & 0x00ff) == 0)
  108.     {
  109.         // The generated vertex lies at one of the corners so there
  110.         // is no need to subdivide the interval.
  111.         if (t == 0) {
  112.             return v1.cast<double>();
  113.         }
  114.         return v0.cast<double>();
  115.     }
  116.     else
  117.     {
  118.         for (u8 i = 0; i < lodIndex; ++i)
  119.         {
  120.             const Vector3i vm = (v0 + v1) / 2;
  121.             const Vector3i pm = (p0 + p1) / 2;
  122.  
  123.             const u8 sm = samples[pm];
  124.  
  125.             // Determine which of the sub-intervals that contain
  126.             // the intersection with the isosurface.
  127.             if (sign(s0) != sign(sm)) {
  128.                 v1 = vm;
  129.                 p1 = pm;
  130.                 s1 = sm;
  131.             } else {
  132.                 v0 = vm;
  133.                 p0 = pm;
  134.                 s0 = sm;
  135.             }
  136.         }
  137.         t = (s1 << 8) / (s1 - s0);
  138.         u = 0x0100 - t;
  139.  
  140.         return (v0.cast<double>() * t) * s + (v1.cast<double>() * u) * s;
  141.     }
  142. }
  143.  
  144. inline const Vector3d interp(Vector3d v0, Vector3d v1, // Position of vertices
  145.                              Vector3i p0, Vector3i p1, // Position of sample points
  146.                              const VolumeData & samples, u8 lodIndex = 0)
  147. {
  148.     i8 s0 = samples[p0];
  149.     i8 s1 = samples[p1];
  150.  
  151.     i32 t = (s1 << 8) / (s1 - s0);
  152.     i32 u = 0x0100 - t;
  153.     const double s = 1.0 / 256.0;
  154.  
  155.     if ((t & 0x00ff) == 0)
  156.     {
  157.         // The generated vertex lies at one of the corners so there
  158.         // is no need to subdivide the interval.
  159.         if (t == 0) {
  160.             return v1.cast<double>();
  161.         }
  162.         return v0.cast<double>();
  163.     }
  164.     else
  165.     {
  166.         for (u8 i = 0; i < lodIndex; ++i)
  167.         {
  168.             const Vector3d vm = (v0 + v1) / 2;
  169.             const Vector3i pm = (p0 + p1) / 2;
  170.  
  171.             const u8 sm = samples[pm];
  172.  
  173.             // Determine which of the sub-intervals that contain
  174.             // the intersection with the isosurface.
  175.             if (sign(s0) != sign(sm)) {
  176.                 v1 = vm;
  177.                 p1 = pm;
  178.                 s1 = sm;
  179.             } else {
  180.                 v0 = vm;
  181.                 p0 = pm;
  182.                 s0 = sm;
  183.             }
  184.         }
  185.         t = (s1 << 8) / (s1 - s0);
  186.         u = 0x0100 - t;
  187.  
  188.         return v0 * t * s + v1 * u * s;
  189.     }
  190. }
  191.  
  192. inline Vector3d computeDelta(const Vector3d & v, int k, int s)
  193. {
  194.     const double p2k = pow(2.0, k);
  195.     const double wk  = pow(2.0, k - 2.0);
  196.     Vector3d delta(0,0,0);
  197.  
  198.     if (k < 1) {
  199.         return delta;
  200.     }
  201.  
  202.     for (int i = 0; i < 3; ++i)
  203.     {
  204.         const double x = v[i];
  205.  
  206.         if (x < p2k)
  207.         {
  208.             // The vertex is inside the minimum cell.
  209.             delta[i] = (1.0 - pow(2.0, -k) * x) * wk;
  210.         }
  211.         else if(x > (p2k * (s-1)))
  212.         {
  213.             // The vertex is inside the maximum cell.
  214.             delta[i] = ((p2k * s) - 1.0 - x) * wk;
  215.         }
  216.     }
  217.     return delta;
  218. }
  219.  
  220. inline Vector3d projectNormal(Vector3d N, const Vector3d & delta)
  221. {
  222.     Eigen::Matrix<double, 3, 3> mat;
  223.     mat << 1.0 -N.x() * N.x(),     -N.x() * N.y(),     -N.x() * N.z(),
  224.                -N.x() * N.y(), 1.0 -N.y() * N.y(),     -N.y() * N.z(),
  225.                -N.x() * N.z(),     -N.y() * N.z(), 1.0 -N.z() * N.z();
  226.     return mat * delta;
  227. }
  228.  
  229. inline Vector3i prevOffset(u8 dir)
  230. {
  231.     return Vector3i( -(dir & 1),
  232.                  -((dir >> 1) & 1),
  233.              -((dir >> 2) & 1));
  234. }
  235.  
  236. inline int polygonizeRegularCell(
  237.     const Vector3i & min,
  238.     const Vector3d & offset, // The minimum corner of the cell in object space.
  239.     const Vector3i xyz,
  240.     const VolumeData & samples,
  241.     u8 lodIndex,
  242.     double cellSize,
  243.     std::vector<vertex> & verts,
  244.     std::vector<int> & indices,
  245.     regular_cell_cache * cache)
  246. {
  247.     const int W = 19;
  248.     const i32 lodScale = 1 << lodIndex;
  249.     const i32 last     = 15 * lodScale;
  250.     const u8 directionMask = (xyz.x() > 0 ? 1 : 0) | ((xyz.y() > 0 ? 1 : 0) << 1) | ((xyz.z() > 0 ? 1 : 0) << 2);
  251.  
  252.     u8 near = 0;
  253.  
  254.     // Compute which of the six faces of the block that the vertex
  255.     // is near. (near is defined as being in boundary cell.)
  256.     for (int i = 0; i < 3; ++i)
  257.     {
  258.         if (min[i] ==    0) { near |= (1 << (i * 2 + 0)); /* Vertex close to negative face. */ }
  259.         if (min[i] == last) { near |= (1 << (i * 2 + 1)); /* Vertex close to positive face. */ }
  260.     }
  261.  
  262.     const Vector3i cornerPositions[] =
  263.     {
  264.         min + Vector3i(0,0,0) * lodScale,
  265.         min + Vector3i(1,0,0) * lodScale,
  266.         min + Vector3i(0,1,0) * lodScale,
  267.         min + Vector3i(1,1,0) * lodScale,
  268.  
  269.         min + Vector3i(0,0,1) * lodScale,
  270.         min + Vector3i(1,0,1) * lodScale,
  271.         min + Vector3i(0,1,1) * lodScale,
  272.         min + Vector3i(1,1,1) * lodScale
  273.     };
  274.  
  275.     const Vector3i dif = cornerPositions[7] - cornerPositions[0];
  276.  
  277.     // Retrieve sample values for all the corners.
  278.     const i8 cornerSamples[8] =
  279.     {
  280.         samples[cornerPositions[0]],
  281.         samples[cornerPositions[1]],
  282.         samples[cornerPositions[2]],
  283.         samples[cornerPositions[3]],
  284.         samples[cornerPositions[4]],
  285.         samples[cornerPositions[5]],
  286.         samples[cornerPositions[6]],
  287.         samples[cornerPositions[7]],
  288.     };
  289.  
  290.     Eigen::Vector3d cornerNormals[8];
  291.  
  292.     /* Determine the index into the edge table which
  293.     tells us which vertices are inside of the surface */
  294.     const u32 caseCode = ((cornerSamples[0] >> 7) & 0x01)
  295.                        | ((cornerSamples[1] >> 6) & 0x02)
  296.                        | ((cornerSamples[2] >> 5) & 0x04)
  297.                        | ((cornerSamples[3] >> 4) & 0x08)
  298.                        | ((cornerSamples[4] >> 3) & 0x10)
  299.                        | ((cornerSamples[5] >> 2) & 0x20)
  300.                        | ((cornerSamples[6] >> 1) & 0x40)
  301.                        | (cornerSamples[7] & 0x80);
  302.  
  303.     cache->get(xyz).caseIndex = caseCode;
  304.  
  305.     if ((caseCode ^ ((cornerSamples[7] >> 7) & 0xff)) == 0)
  306.         return 0;
  307.  
  308.     // Compute the normals at the cell corners using central difference.
  309.     for (int i = 0; i < 8; ++i)
  310.     {
  311.         const Vector3i p = cornerPositions[i];
  312.         const double nx = (samples[p + Vector3i::UnitX()] - samples[p - Vector3i::UnitX()]) * 0.5;
  313.         const double ny = (samples[p + Vector3i::UnitY()] - samples[p - Vector3i::UnitY()]) * 0.5;
  314.         const double nz = (samples[p + Vector3i::UnitZ()] - samples[p - Vector3i::UnitZ()]) * 0.5;
  315.  
  316.         cornerNormals[i] = Eigen::Vector3d(nx,ny,nz).normalized();
  317.     }
  318.  
  319.     const char c = regularCellClass[caseCode];
  320.     const RegularCellData & data = regularCellData[c];
  321.  
  322.     const u8 nt = (u8)data.GetTriangleCount();
  323.     const u8 nv = (u8)data.GetVertexCount();
  324.  
  325.     int localVertexMapping[12];
  326.  
  327.     vertex vert;
  328.     vert.near = near;
  329.  
  330.     // Generate all the vertex positions by interpolating along
  331.     // each of the edges that intersect the isosurface.
  332.     for (u8 i = 0; i < nv; ++i)
  333.     {
  334.         const u16 edgeCode = regularVertexData[caseCode][i];
  335.         // The low byte of each 16-bit code contains the corner
  336.         // indexes of the edge's endpoints in one nibble each.
  337.         const u8 v0 = HINIBBLE(edgeCode & 0xff);
  338.         const u8 v1 = LONIBBLE(edgeCode & 0xff);
  339.  
  340.         const Vector3i p0 = cornerPositions[v0];
  341.         const Vector3i p1 = cornerPositions[v1];
  342.         const Vector3d n0 = cornerNormals[v0];
  343.         const Vector3d n1 = cornerNormals[v1];
  344.  
  345.         const i32 d0 = samples[p0];
  346.         const i32 d1 = samples[p1];
  347.  
  348.         assert(v0 < v1);
  349.  
  350.         const i32 t = (d1 << 8) / (d1 - d0);
  351.         const i32 u = 0x0100 - t;
  352.         const double s = 1.0 / 256.0;
  353.  
  354.         const double t0 = t * s, t1 = u * s;
  355.  
  356.         if ((t & 0x00ff) != 0)
  357.         {
  358.             // Vertex lies in the interior of the edge.
  359.             const u8 dir = HINIBBLE(edgeCode >> 8); // The direction to the previous cell.
  360.             const u8 idx = LONIBBLE(edgeCode >> 8); // The vertex to generate or reuse for this edge (0-3)
  361.             const bool present = (dir & directionMask) == dir;
  362.  
  363.             if (present)
  364.             {
  365.                 const regular_cell_cache::cell & prev = cache->get(xyz + prevOffset(dir));
  366.                 // I don't think this can happen for non-corner vertices.
  367.                 if (prev.caseIndex == 0 || prev.caseIndex == 255) {
  368.                     localVertexMapping[i] = -1;
  369.                 }
  370.                 else {
  371.                     localVertexMapping[i] = prev.verts[idx];
  372.                 }
  373.             }
  374.  
  375.             if (!present || localVertexMapping[i] < 0)
  376.             {
  377.                 localVertexMapping[i]  = verts.size();
  378.                 // Compute the intersection between the edge and the isosurface
  379.                 // using the highest resolution sample data to get correct position.
  380.                 const Vector3d pi = interp(p0.cast<double>().eval(), p1.cast<double>().eval(), p0, p1, samples, lodIndex);
  381.  
  382.                 vert.pos[PRIMARY] = offset + pi;
  383.                 vert.normal = n0 * t0 + n1 * t1;
  384.                
  385.                 if (near)
  386.                 {
  387.                     const Vector3d delta = computeDelta(pi, lodIndex, 16);
  388.                     vert.pos[SECONDARY] = vert.pos[PRIMARY] + projectNormal(vert.normal, delta);
  389.                 }
  390.                 else {
  391.                     // The vertex is not in a boundary cell, so the
  392.                     // secondary position will never be used.
  393.                     vert.pos[SECONDARY] = Vector3d(1000,1000,1000); //vert.pos[PRIMARY];
  394.                 }
  395.                 verts.push_back(vert);
  396.  
  397.                 if ((dir & 8) != 0)
  398.                 {
  399.                     // Store the generated vertex so that other cells can reuse it.
  400.                     cache->get(xyz).verts[idx] = localVertexMapping[i];
  401.                 }
  402.             }
  403.         }
  404.         else if(t == 0 && v1 == 7)
  405.         {
  406.             // This cell owns the vertex, so it should be created.
  407.             localVertexMapping[i]  = verts.size();
  408.  
  409.             const Eigen::Vector3d pi = p0.cast<double>() * t0 + p1.cast<double>() * t1;
  410.  
  411.             vert.pos[PRIMARY] = offset + pi;
  412.             vert.normal = n0 * t0 + n1 * t1;
  413.                
  414.             if (near)
  415.             {
  416.                 const Vector3d delta = computeDelta(pi, lodIndex, 16);
  417.                 vert.pos[SECONDARY]  = vert.pos[PRIMARY] + projectNormal(vert.normal, delta);
  418.             }
  419.             else {
  420.                 // The vertex is not in a boundary cell, so the secondary
  421.                 // position will never be used.
  422.                 vert.pos[SECONDARY] = Vector3d(1000,1000,1000);
  423.             }
  424.             verts.push_back(vert);
  425.             cache->get(xyz).verts[0] = localVertexMapping[i];
  426.         }
  427.         else
  428.         {
  429.             // A 3-bit direction code leading to the proper cell can easily be obtained by
  430.             // inverting the 3-bit corner index (bitwise, by exclusive ORing with the number 7).
  431.             // The corner index depends on the value of t, t = 0 means that we're at the higher
  432.             // numbered endpoint.
  433.             const u8 dir = t == 0 ? (v1 ^ 7) : (v0 ^ 7);
  434.             const bool present = (dir & directionMask) == dir;
  435.  
  436.             if (present)
  437.             {
  438.                 const regular_cell_cache::cell & prev = cache->get(xyz + prevOffset(dir));
  439.                 // The previous cell might not have any geometry, and we
  440.                 // might therefore have to create a new vertex anyway.
  441.                 if (prev.caseIndex == 0 || prev.caseIndex == 255) {
  442.                     localVertexMapping[i] = -1;
  443.                 }
  444.                 else {
  445.                     localVertexMapping[i] = prev.verts[0];
  446.                 }
  447.             }
  448.  
  449.             if (!present || (localVertexMapping[i] < 0))
  450.             {
  451.                 localVertexMapping[i]  = verts.size();
  452.  
  453.                 const Eigen::Vector3d pi = p0.cast<double>() * t0 + p1.cast<double>() * t1;
  454.  
  455.                 vert.pos[PRIMARY] = offset + pi;
  456.                 vert.normal = n0 * t0 + n1 * t1;
  457.                
  458.                 if (near)
  459.                 {
  460.                     const Vector3d delta = computeDelta(pi, lodIndex, 16);
  461.                     vert.pos[SECONDARY] = vert.pos[PRIMARY] + projectNormal(vert.normal, delta);
  462.                 }
  463.                 else {
  464.                     // The vertex is not in a boundary cell, so the secondary
  465.                     // position will never be used.
  466.                     vert.pos[SECONDARY] = Vector3d(1000,1000,1000); //vert.pos[PRIMARY];
  467.                 }
  468.                 verts.push_back(vert);
  469.             }
  470.         }
  471.     }
  472.  
  473.     for (long t = 0; t < nt; ++t)
  474.     {
  475.         // TODO: Add check for zero-area triangles here.
  476.         for (int i = 0; i < 3; ++i)
  477.         {
  478.             indices.push_back(localVertexMapping[ data.vertexIndex[t * 3 + i] ]);
  479.         }
  480.     }
  481.  
  482.     return nt;
  483. }
  484.  
  485. inline int polygonizeTransitionCell(
  486.     const Vector3d & offset, // Offset of the cell in world space.
  487.     const Vector3i & origin, // Origin in sample space.
  488.     const Vector3i & localX,
  489.     const Vector3i & localY,
  490.     const Vector3i & localZ,
  491.     int x, int y,     // The x and y position of the cell within the block face.
  492.     float cellSize,   // The width of a cell in world scale.
  493.     u8 lodIndex,
  494.     u8 axis,          // The index of the axis corresponding to the z-axis.
  495.     u8 directionMask, // Used to determine which previous cells that are available.
  496.     const VolumeData & samples,
  497.     std::vector<vertex> & verts,
  498.     std::vector<int> & indices,
  499.     transition_cell_cache * cache)
  500. {
  501.     const int lodStep    = 1 << lodIndex;
  502.     const int sampleStep = 1 <<(lodIndex -1);
  503.     const i32 lodScale   = 1 << lodIndex;
  504.     const i32 last       = 16 * lodScale;
  505.  
  506.     u8 near = 0;
  507.     // Compute which of the six faces of the block that the vertex
  508.     // is near. (near is defined as being in boundary cell.)
  509.     for (int i = 0; i < 3; ++i)
  510.     {
  511.         if (origin[i] ==    0) { near |= (1 << (i * 2 + 0)); /* Vertex close to negative face. */ }
  512.         if (origin[i] == last) { near |= (1 << (i * 2 + 1)); /* Vertex close to positive face. */ }
  513.     }
  514.  
  515.     static const Vector3i coords[] = {
  516.         Vector3i(0,0,0), Vector3i(1,0,0), Vector3i(2,0,0), // High-res lower row
  517.         Vector3i(0,1,0), Vector3i(1,1,0), Vector3i(2,1,0), // High-res middle row
  518.         Vector3i(0,2,0), Vector3i(1,2,0), Vector3i(2,2,0), // High-res upper row
  519.  
  520.         Vector3i(0,0,2), Vector3i(2,0,2), // Low-res lower row
  521.         Vector3i(0,2,2), Vector3i(2,2,2)  // Low-res upper row
  522.     };
  523.  
  524.     Eigen::Matrix<int, 3, 3>  basis;
  525.  
  526.     basis.col(0) = localX * sampleStep;
  527.     basis.col(1) = localY * sampleStep;
  528.     basis.col(2) = localZ * sampleStep;
  529.  
  530.     // The positions of each voxel corner in local block space.
  531.     const Vector3i pos[] = {
  532.         origin + basis * coords[0x00], origin + basis * coords[0x01], origin + basis * coords[0x02],
  533.         origin + basis * coords[0x03], origin + basis * coords[0x04], origin + basis * coords[0x05],
  534.         origin + basis * coords[0x06], origin + basis * coords[0x07], origin + basis * coords[0x08],
  535.         origin + basis * coords[0x09], origin + basis * coords[0x0A],
  536.         origin + basis * coords[0x0B], origin + basis * coords[0x0C],
  537.     };
  538.  
  539.     Vector3d normals[13];
  540.  
  541.     // Compute the normals at the cell corners using central difference.
  542.     for (int i = 0; i < 9; ++i)
  543.     {
  544.         const Vector3i p = pos[i];
  545.         const double nx = (samples[p + Vector3i::UnitX()] - samples[p - Vector3i::UnitX()]) * 0.5;
  546.         const double ny = (samples[p + Vector3i::UnitY()] - samples[p - Vector3i::UnitY()]) * 0.5;
  547.         const double nz = (samples[p + Vector3i::UnitZ()] - samples[p - Vector3i::UnitZ()]) * 0.5;
  548.  
  549.         normals[i] = Eigen::Vector3d(nx,ny,nz).normalized();
  550.     }
  551.  
  552.     normals[0x9] = normals[0];
  553.     normals[0xA] = normals[2];
  554.     normals[0xB] = normals[6];
  555.     normals[0xC] = normals[8];
  556.  
  557.     const Vector3i samplePos[] = {
  558.         pos[0], pos[1], pos[2],
  559.         pos[3], pos[4], pos[5],
  560.         pos[6], pos[7], pos[8],
  561.         pos[0], pos[2],
  562.         pos[6], pos[8]
  563.     };
  564.  
  565.     const u32 caseCode = signBit(samples[pos[0]]) * 0x001 |
  566.                          signBit(samples[pos[1]]) * 0x002 |
  567.                          signBit(samples[pos[2]]) * 0x004 |
  568.                          signBit(samples[pos[5]]) * 0x008 |
  569.                          signBit(samples[pos[8]]) * 0x010 |
  570.                          signBit(samples[pos[7]]) * 0x020 |
  571.                          signBit(samples[pos[6]]) * 0x040 |
  572.                          signBit(samples[pos[3]]) * 0x080 |
  573.                          signBit(samples[pos[4]]) * 0x100;                     
  574.  
  575.     if (caseCode == 0 || caseCode == 511)
  576.         return 0;
  577.  
  578.     const u8 classIndex = transitionCellClass[caseCode]; // Equivalence class index.
  579.     const TransitionCellData & data = transitionCellData[classIndex & 0x7F];
  580.  
  581.     const bool inverse = (classIndex & 128) != 0;
  582.  
  583.     int localVertexMapping[12];
  584.  
  585.     const long nv = data.GetVertexCount();
  586.     const long nt = data.GetTriangleCount();
  587.  
  588.     assert(nv <= 12);
  589.     vertex vert;
  590.  
  591.     for (long i = 0; i < nv; ++i)
  592.     {
  593.         const u16 edgeCode = transitionVertexData[caseCode][i];
  594.         // The low byte of each 16-bit code contains the corner
  595.         // indexes of the edge's endpoints in one nibble each.
  596.         const u8 v0 = HINIBBLE(edgeCode);
  597.         const u8 v1 = LONIBBLE(edgeCode);
  598.         const bool lowside = (v0 > 8) && (v1 > 8);
  599.  
  600.         const i32 d0 = samples[samplePos[v0]];
  601.         const i32 d1 = samples[samplePos[v1]];
  602.  
  603.         const i32 t = (d1 << 8) / (d1 - d0);
  604.         const i32 u = 0x0100 - t;
  605.         const double s = 1.0 / 256.0;
  606.         const double t0 = t * s, t1 = u * s;
  607.  
  608.         const Vector3d n0 = normals[v0];
  609.         const Vector3d n1 = normals[v1];
  610.  
  611.         vert.near = near;
  612.         vert.normal = n0 * t0 + n1 * t1;
  613.  
  614.         if ((t & 0x00ff) != 0)
  615.         {
  616.             // Use the reuse information in transitionVertexData
  617.             const u8 dir = HINIBBLE(edgeCode >> 8);
  618.             const u8 idx = LONIBBLE(edgeCode >> 8);
  619.  
  620.             if ((dir & directionMask) == dir)
  621.             {
  622.                 // The previous cell is available. Retrieve the cached cell
  623.                 // from which to retrieve the reused vertex index from.
  624.                 const transition_cell_cache::cell & prev = cache->get(x - (dir & 1), y - ((dir >> 1) & 1));
  625.                 // Reuse the vertex index from the previous cell.
  626.                 localVertexMapping[i] = prev.verts[idx];
  627.             }
  628.             else
  629.             {
  630.                 // A vertex has to be created.
  631.                 const Vector3d p0 = pos[v0].cast<double>();
  632.                 const Vector3d p1 = pos[v1].cast<double>();
  633.  
  634.                 Vector3d pi = interp(p0, p1, samplePos[v0], samplePos[v1], samples, lowside ? lodIndex : lodIndex - 1);
  635.  
  636.                 if (lowside)
  637.                 {
  638.                     // Necessary to translate the intersection point to the
  639.                     // high-res side so that it is transformed the same way
  640.                     // as the vertices in the regular cell.
  641.                     pi[axis] = (double)origin[axis];
  642.            
  643.                     const Vector3d delta = computeDelta(pi, lodIndex, 16);
  644.                     const Vector3d proj = projectNormal(vert.normal, delta);
  645.  
  646.                     vert.pos[PRIMARY]   = Vector3d(1000,1000,1000);
  647.                     vert.pos[SECONDARY] = offset + pi + proj;
  648.                 }
  649.                 else
  650.                 {
  651.                     vert.near = 0; // Vertices on high-res side are never moved.
  652.                     vert.pos[PRIMARY]   = offset + pi;
  653.                     vert.pos[SECONDARY] = Vector3d(1000,1000,1000);
  654.                 }
  655.  
  656.                 localVertexMapping[i]  = verts.size();
  657.                 verts.push_back(vert);
  658.  
  659.                 if ((dir & 8) != 0)
  660.                 {
  661.                     // The vertex can be reused.
  662.                     cache->get(x,y).verts[idx] = localVertexMapping[i];
  663.                 }
  664.             }
  665.         }
  666.         else
  667.         {
  668.             // Try to reuse corner vertex from a preceding cell.
  669.             // Use the reuse information in transitionCornerData.
  670.             const u8 v = t == 0 ? v1 : v0;
  671.             const u8 cornerData = transitionCornerData[v];
  672.  
  673.             const u8 dir = HINIBBLE(cornerData); // High nibble contains direction code.
  674.             const u8 idx = LONIBBLE(cornerData); // Low nibble contains storage slot for vertex.
  675.  
  676.             if ((dir & directionMask) == dir)
  677.             {
  678.                 // The previous cell is available. Retrieve the cached cell
  679.                 // from which to retrieve the reused vertex index from.
  680.                 const transition_cell_cache::cell & prev = cache->get(x - (dir & 1), y - ((dir >> 1) & 1));
  681.                 localVertexMapping[i] = prev.verts[idx];
  682.             }
  683.             else
  684.             {
  685.                 // A vertex has to be created.
  686.                 Vector3d pi = pos[v].cast<double>();
  687.  
  688.                 if (v > 8)
  689.                 {
  690.                     // On low-resolution side.
  691.                     // Necessary to translate the intersection point to the
  692.                     // high-res side so that it is transformed the same way
  693.                     // as the vertices in the regular cell.
  694.                     pi[axis] = (double)origin[axis];
  695.            
  696.                     const Vector3d delta = computeDelta(pi, lodIndex, 16);
  697.                     const Vector3d proj = projectNormal(vert.normal, delta);
  698.  
  699.                     vert.pos[PRIMARY]   = Vector3d(1000,1000,1000);
  700.                     vert.pos[SECONDARY] = offset + pi + proj;
  701.                 }
  702.                 else
  703.                 {
  704.                     // On high-resolution side.
  705.                     vert.near = 0; // Vertices on high-res side are never moved.
  706.                     vert.pos[PRIMARY]   = offset + pi;
  707.                     vert.pos[SECONDARY] = Vector3d(1000,1000,1000);
  708.                 }
  709.                 localVertexMapping[i] = verts.size();
  710.                 cache->get(x,y).verts[idx] = localVertexMapping[i];
  711.                 verts.push_back(vert);
  712.             }
  713.         }
  714.     }
  715.  
  716.     for (long t = 0; t < nt; ++t)
  717.     {
  718.         const u8 * ptr = &data.vertexIndex[t * 3];
  719.  
  720.         if (inverse)
  721.         {
  722.             indices.push_back(localVertexMapping[ptr[2]]);
  723.             indices.push_back(localVertexMapping[ptr[1]]);
  724.             indices.push_back(localVertexMapping[ptr[0]]);
  725.  
  726.         }
  727.         else
  728.         {
  729.             indices.push_back(localVertexMapping[ptr[0]]);
  730.             indices.push_back(localVertexMapping[ptr[1]]);
  731.             indices.push_back(localVertexMapping[ptr[2]]);
  732.         }
  733.     }
  734.  
  735.     return nt;
  736. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement