Advertisement
_bm

SurfaceNets.cs

_bm
Jul 30th, 2016
551
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.23 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System;
  5.  
  6. public static class SurfaceNets{
  7.  
  8.     private static int[] buffer = new int[4096];
  9.     private static int[] cubeEdges = new int[24];
  10.     private static int[] edgeTable = new int[256];
  11.  
  12.     public static void Initialize()
  13.     {
  14.         //Precompute
  15.         var k = 0;
  16.         MonoBehaviour.print("Pre-compute");
  17.  
  18.         //Initialize Edge Table
  19.         for (var i = 0; i < 8; i++)
  20.         {
  21.             for (var j = 1; j <= 4; j <<= 1)
  22.             {
  23.                 var p = i ^ j;
  24.                 if (i <= p)
  25.                 {
  26.                     cubeEdges[k++] = i;
  27.                     cubeEdges[k++] = p;
  28.                 }
  29.             }
  30.         }
  31.  
  32.         //Initialize Intersection Table
  33.         for (var i = 0; i < 256; i++)
  34.         {
  35.             int em = 0;
  36.             for (var j = 0; j < 24; j += 2)
  37.             {
  38.                 var a = Convert.ToBoolean(i & (1 << cubeEdges[j]));
  39.                 var b = Convert.ToBoolean(i & (1 << cubeEdges[j + 1]));
  40.                 em |= a != b ? (1 << (j >> 1)) : 0;
  41.             }
  42.             edgeTable[i] = em;
  43.         }
  44.     }
  45.  
  46.     public static Mesh Compute(float[,,] voxels)
  47.     {
  48.         //Init
  49.         buffer = new int[4096];
  50.         Mesh mesh = new Mesh();
  51.         int width = voxels.GetUpperBound(0) + 1;
  52.         int height = voxels.GetUpperBound(1) + 1;
  53.         int depth = voxels.GetUpperBound(2) + 1;
  54.         var vertices = new List<Vector3>();
  55.         var faces = new List<int>();
  56.         var n = 0;
  57.         var pos = new int[3];
  58.         var R = new int[]{1, width + 1, (width + 1) * (height + 1)};
  59.         var grid = new float[8];
  60.         var bufferNumber = 1;
  61.  
  62.         //Resize Buffer
  63.         if (R[2] * 2 > buffer.Length)
  64.             buffer = new int[R[2] * 2];
  65.  
  66.         //March Over Voxels
  67.         Control.msg = "{starting surf nets} ";
  68.         for (pos[2] = 0; pos[2] < depth - 1; pos[2]++, bufferNumber ^= 1, R[2] = -R[2] )
  69.         {
  70.             //Buffer Pointer
  71.             var bufferIndex = 1 + (width + 1) * (1 + bufferNumber * (height + 1));
  72.  
  73.             for(pos[1] = 0; pos[1] < height - 1; pos[1]++, n++, bufferIndex += 2)
  74.             {
  75.                 for (pos[0] = 0; pos[0] < width - 1; pos[0]++, n++, bufferIndex++)
  76.                 {
  77.                     //8 field values around vertex, plus 8-bit mask
  78.                     var mask = 0;
  79.                     var g = 0;
  80.                     var index = n;
  81.                     for (var k = 0; k < 2; k++, index += width * (height - 2))
  82.                     {
  83.                         for (var j = 0; j < 2; j++, index += width - 2)
  84.                         {
  85.                             for (var i = 0; i < 2; i++, g++, index++)
  86.                             {
  87.                                 var p = voxels[index / (width * width), (index / depth) % height, index % depth];
  88.                                 grid[g] = p;
  89.                                 mask |= (p < 0) ? (1 << g) : 0;
  90.                             }
  91.                         }
  92.                     }
  93.  
  94.                     //Early Termination Check
  95.                     if (mask == 0 || mask == 0xff)
  96.                     {
  97.                         continue;
  98.                     }
  99.  
  100.                     //Sum Edge Intersections
  101.                     var edgeMask = edgeTable[mask];
  102.                     var vertex = new Vector3();
  103.                     var edgeIndex = 0;
  104.  
  105.                     //For Every Cube Edge
  106.                     for (var i = 0; i < 12; i++)
  107.                     {
  108.                         //Use Edge Mask to Check if Crossed
  109.                         if (!Convert.ToBoolean(edgeMask & (1 << i)))
  110.                         {
  111.                             continue;
  112.                         }
  113.  
  114.                         //If So, Increment Edge Crossing #
  115.                         edgeIndex++;
  116.  
  117.                         //Find Intersection Point
  118.                         var e0 = cubeEdges[i << 1];
  119.                         var e1 = cubeEdges[(i << 1) + 1];
  120.                         var g0 = grid[e0];
  121.                         var g1 = grid[e1];
  122.                         var t = g0 - g1;
  123.                         if (Math.Abs(t) > 1e-16)
  124.                             t = g0 / t;
  125.                         else
  126.                             continue;
  127.  
  128.                         //Interpolate Vertices, Add Intersections
  129.                         for(int j = 0, k = 1; j < 3; j++, k <<=1)
  130.                         {
  131.                             var a = e0 & k;
  132.                             var b = e1 & k;
  133.                             if (a != b)
  134.                                 vertex[j] += Convert.ToBoolean(a) ? 1f - t : t;
  135.                             else
  136.                                 vertex[j] += Convert.ToBoolean(a) ? 1f : 0;
  137.                         }
  138.                     }
  139.  
  140.                     //Average Edge Intersections, Add to Coordinate
  141.                     var s = 1f / edgeIndex;
  142.                     for(var i = 0; i < 3; i++)
  143.                     {
  144.                         vertex[i] = pos[i] + s * vertex[i];
  145.                     }
  146.  
  147.                     //Add Vertex to Buffer, Store Pointer to Vertex Index
  148.                     buffer[bufferIndex] = vertices.Count;
  149.                     Control.msg = buffer[bufferIndex];
  150.                     vertices.Add(vertex);
  151.  
  152.                     //Add Faces (Loop Over 3 Base Components)
  153.                     for (var i = 0; i < 3; i ++)
  154.                     {
  155.                         //First 3 Entries Indicate Crossings on Edge
  156.                         if(!Convert.ToBoolean(edgeMask & (1 << i)))
  157.                         {
  158.                             continue;
  159.                         }
  160.  
  161.                         //i - Axes, iu, iv - Ortho Axes
  162.                         var iu = (i + 1) % 3;
  163.                         var iv = (i + 2) % 3;
  164.  
  165.                         //Skip if on Boundary
  166.                         if (pos[iu] == 0 || pos[iv] == 0)
  167.                             continue;
  168.  
  169.                         //Otherwise, Look Up Adjacent Edges in Buffer
  170.                         var du = R[iu];
  171.                         var dv = R[iv];
  172.  
  173.                         //Flip Orientation Depending on Corner Sign
  174.                         if (Convert.ToBoolean(mask & 1))
  175.                         {
  176.                             faces.Add(buffer[bufferIndex]);
  177.                             faces.Add(buffer[bufferIndex - du]);
  178.                             faces.Add(buffer[bufferIndex - du - dv]);
  179.                             faces.Add(buffer[bufferIndex - dv]);
  180.                         }
  181.                         else
  182.                         {
  183.                             faces.Add(buffer[bufferIndex]);
  184.                             faces.Add(buffer[bufferIndex - dv]);
  185.                             faces.Add(buffer[bufferIndex - du - dv]);
  186.                             faces.Add(buffer[bufferIndex - du]);
  187.                         }
  188.                     }
  189.                    
  190.                 }
  191.             }
  192.         }
  193.  
  194.         //Construct
  195.         mesh.SetVertices(vertices);
  196.         mesh.SetIndices(faces.ToArray(), MeshTopology.Quads, 0);
  197.         mesh.name = "Procedural Mesh";
  198.         mesh.RecalculateNormals();
  199.         return mesh;
  200.     }
  201. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement