Skip to content

Instantly share code, notes, and snippets.

@HyroVitalyProtago
Created October 12, 2017 12:58
Show Gist options
  • Select an option

  • Save HyroVitalyProtago/87528d5ee829dc2c16c005059f0585c8 to your computer and use it in GitHub Desktop.

Select an option

Save HyroVitalyProtago/87528d5ee829dc2c16c005059f0585c8 to your computer and use it in GitHub Desktop.
Nested prefab for unity from https://codeshare.io/Gkn9z4
using UnityEngine;
public class NestedPrefab : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField]
protected GameObject prefabTarget;
[ContextMenu("Apply nested Prefab")]
public virtual void ApplyNestedPrefab()
{
UnityEditor.PrefabUtility.ReplacePrefab(this.gameObject, this.prefabTarget, UnityEditor.ReplacePrefabOptions.ReplaceNameBased);
Component nestedPrefabComponent = this.prefabTarget.GetComponentInChildren<NestedPrefab>();
GameObject.DestroyImmediate(nestedPrefabComponent, true);
}
#endif
}
using UnityEngine;
using System.Collections.Generic;
using System.IO;
public class Surface_Nets : MonoBehaviour {
private int[] MeshVolumeDims = null;
private float[] MeshVolume = null;
private List<Vector3> VolumeMeshVertices = null;
private List<int> VolumeMeshFaces = null;
private int volumeSize = 0;
private int volumeBufferSize = 0;
private int[] cube_edges = new int[24];
private int[] edge_table = new int[256];
private int[] _buffer = new int[4096];
void InitEdgeTable()
{
//Initialize the cube_edges table
// This is just the vertex number of each cube
int k = 0;
int i,j;
for(i=0; i<8; ++i)
{
for(j=1; j<=4; j<<=1)
{
int p = i^j;
if(i <= p)
{
cube_edges[k++] = i;
cube_edges[k++] = p;
}
}
}
//Initialize the intersection table.
// This is a 2^(cube configuration) -> 2^(edge configuration) map
// There is one entry for each possible cube configuration, and the output is a 12-bit vector enumerating all edges crossing the 0-level.
for(i=0; i<256; ++i)
{
int em = 0;
for(j=0; j<24; j+=2)
{
bool a = 0 != (i & (1<<cube_edges[j])); // Originally !! instead of 0 !=
bool b = 0 != (i & (1<<cube_edges[j+1]));
em |= a != b ? (1 << (j >> 1)) : 0;
}
edge_table[i] = em;
}
}
int CalculateMask( float[] data, int[] dims, float[] grid, int n )
{
//Read in 8 field values around this vertex and store them in an array
//Also calculate 8-bit mask, like in marching cubes, so we can speed up sign checks later
int mask = 0;
int g = 0;
int idx = n;
for(int k=0; k<2; ++k )
{
for(int j=0; j<2; ++j )
{
for(int i=0; i<2; ++i )
{
float p = data[idx];
grid[g] = p;
mask |= (p < 0) ? (1<<g) : 0;
++g;
++idx;
}
idx += dims[0]-2;
}
idx += dims[0]*(dims[1]-2);
}
return mask;
}
int CalculateCrossings( float[] grid, int edge_mask, float[] v )
{
int e_count = 0;
//For every edge of the cube...
for(int i=0; i<12; ++i)
{
//Use edge mask to check if it is crossed
if(0 == (edge_mask & (1<<i))) continue;
//If it did, increment number of edge crossings
++e_count;
//Now find the point of intersection
int e0 = cube_edges[ i<<1 ]; //Unpack vertices
int e1 = cube_edges[(i<<1)+1];
float g0 = grid[e0]; //Unpack grid values
float g1 = grid[e1];
float t = g0 - g1; //Compute point of intersection
if(Mathf.Abs(t) > 1e-6)
{
t = g0 / t;
}
else
{
continue;
}
//Interpolate vertices and add up intersections (this can be done without multiplying)
int k=1;
for(int j=0; j<3; ++j)
{
int a = e0 & k;
int b = e1 & k;
if(a != b)
{
v[j] += a != 0 ? 1.0f - t : t;
}
else
{
v[j] += a != 0 ? 1.0f : 0;
}
k<<=1;
}
}
return e_count;
}
void GetFaces(List<int> faces, int[] buffer, int edge_mask, int mask, int m, int[] x, int[] R )
{
//Now we need to add faces together, to do this we just loop over 3 basis components
for(int i=0; i<3; ++i)
{
//The first three entries of the edge_mask count the crossings along the edge
if( 0 == (edge_mask & (1<<i)) ) continue;
// i = axes we are point along. iu, iv = orthogonal axes
int iu = (i+1)%3;
int iv = (i+2)%3;
//If we are on a boundary, skip it
if(x[iu] == 0 || x[iv] == 0) continue;
//Otherwise, look up adjacent edges in buffer
int du = R[iu];
int dv = R[iv];
int[] temp = new int[4];
if((mask & 1) != 0)
{
temp[0] = buffer[m];
temp[1] = buffer[m-du];
temp[2] = buffer[m-du-dv];
temp[3] = buffer[m-dv];
}
else
{
temp[0] = buffer[m];
temp[1] = buffer[m-dv];
temp[2] = buffer[m-du-dv];
temp[3] = buffer[m-du];
}
// 6 indices to a quad
faces.Add(temp[0]);
faces.Add(temp[1]);
faces.Add(temp[2]);
faces.Add(temp[2]);
faces.Add(temp[3]);
faces.Add(temp[0]);
//faces.Add(temp);
}
}
void CreateSurfaceNetMesh(float[] data, int[] dims)
{
int n = 0;
int[] x = new int[3];
int[] R = new int[3];
float[] grid = new float[8];
int buf_no = 1;
R[0] = 1;
R[1] = dims[0]+1;
R[2] = (dims[0]+1)*(dims[1]+1);
//Resize buffer if necessary
if(R[2] * 2 > _buffer.Length)
{
_buffer = new int[R[2] * 2];
}
//March over the voxel grid
for(x[2]=0; x[2]<dims[2]-1; ++x[2])
{
//m is the pointer into the buffer we are going to use.
//This is slightly obtuse because javascript does not have good support for packed data structures, so we must use typed arrays :(
//The contents of the buffer will be the indices of the vertices on the previous x/y slice of the volume
int m = 1 + (dims[0]+1) * (1 + buf_no * (dims[1]+1));
for(x[1]=0; x[1]<dims[1]-1; ++x[1] )
{
for(x[0]=0; x[0]<dims[0]-1; ++x[0] )
{
int mask = CalculateMask(data,dims,grid,n);
//Check for early termination if cell does not intersect boundary
if(mask != 0 && mask != 0xff)
{
//Sum up edge intersections
int edge_mask = edge_table[mask];
float[] v = new float[3];
v[0] = v[1] = v[2] = 0.0f;
int e_count = CalculateCrossings(grid,edge_mask,v);
//Now we just average the edge intersections and add them to coordinate
float s = 1.0f / e_count;
for(int i=0; i<3; ++i)
{
v[i] = s * v[i] + x[i];
}
//Add vertex to buffer, store pointer to vertex index in buffer
_buffer[m] = VolumeMeshVertices.Count;
Vector3 v3 = new Vector3( Mathf.Floor(v[0]), Mathf.Floor(v[1]), Mathf.Floor(v[2]) );
VolumeMeshVertices.Add(v3);
GetFaces(VolumeMeshFaces, _buffer, edge_mask, mask, m, x, R);
}
++n; ++m;
}
++n;
m+=2;
}
n+=dims[0];
buf_no ^= 1;
R[2]=-R[2];
}
}
void getVolumeFromFile( string filename, int[] res, ref float[] volume, ref int volumeSize, ref int volumeBufferSize )
{
FileStream fs = File.Open(filename,FileMode.Open);
BinaryReader br = new BinaryReader(fs);
int iTemp = br.ReadInt32(); // Magic
int SizeX = br.ReadInt32();
int SizeY = br.ReadInt32();
int SizeZ = br.ReadInt32();
iTemp = br.ReadInt32(); // bits_per_voxel
res[0] = SizeX;
res[1] = SizeY;
res[2] = SizeZ;
int size = SizeX*SizeY*SizeZ;
if( volume == null || size >= volumeBufferSize )
volume = new float[size];
if( size > volumeBufferSize )
volumeBufferSize = size;
volumeSize = size;
int c = 0;
while( br.PeekChar() != -1 ) {
float val = br.ReadSingle();
volume[c] = (1.0f-val)*2.0f-1.0f;
c++;
}
br.Close();
fs.Close();
}
void TempChange( List<int[]> list )
{
int[] x = new int[4];
x[0] = x[1] = x[2] = x[3] = 32;
list.Add(x);
}
void UpdateMesh()
{
if( VolumeMeshFaces == null )
VolumeMeshFaces = new List<int>();
else
VolumeMeshFaces.Clear();
if( VolumeMeshVertices == null )
VolumeMeshVertices = new List<Vector3>();
else
VolumeMeshVertices.Clear();
getVolumeFromFile("dice.rawvox",MeshVolumeDims,ref MeshVolume,ref volumeSize,ref volumeBufferSize);
CreateSurfaceNetMesh(MeshVolume,MeshVolumeDims);
MeshFilter meshfilter = gameObject.GetComponent("MeshFilter") as MeshFilter;
int vertCount = VolumeMeshVertices.Count;
//int indexCount = VolumeMeshFaces.Count;
//int triCount = indexCount / 3;
if( vertCount > 0 && vertCount <= 65000 )
{
if( meshfilter.mesh == null )
meshfilter.mesh = new Mesh();
else
meshfilter.mesh.Clear();
Vector3[] verts = VolumeMeshVertices.ToArray();
int[] tris = VolumeMeshFaces.ToArray();
meshfilter.mesh.vertices = verts;
meshfilter.mesh.triangles = tris;
meshfilter.mesh.RecalculateBounds();
Bounds bounds = meshfilter.mesh.bounds;
Vector2[] uvs = new Vector2[vertCount];
Vector2[] uvs2 = new Vector2[vertCount];
for( int i = 0 ; i < vertCount; i++ )
{
float u = verts[i].x / bounds.size.x * 8.0f;
uvs[i] = new Vector2(u, verts[i].z / bounds.size.x * 8.0f);
uvs2[i] = new Vector2(u, verts[i].y / bounds.size.x * 8.0f);
}
meshfilter.mesh.uv = uvs;
meshfilter.mesh.uv2 = uvs2;
meshfilter.mesh.RecalculateNormals();
}
}
void Start ()
{
var fStartTime = Time.realtimeSinceStartup;
InitEdgeTable();
MeshVolumeDims = new int[3];
UpdateMesh();
var fEndTime = Time.realtimeSinceStartup;
Debug.Log("C# Implementation : " + (fEndTime - fStartTime));
MeshRenderer mesh_renderer = gameObject.GetComponent("MeshRenderer") as MeshRenderer;
mesh_renderer.material.color = Color.white;
}
void Update () {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment