Created
October 12, 2017 12:58
-
-
Save HyroVitalyProtago/87528d5ee829dc2c16c005059f0585c8 to your computer and use it in GitHub Desktop.
Nested prefab for unity from https://codeshare.io/Gkn9z4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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