Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by BoredVoid · Feb 17 at 07:32 PM · dotsmarching cubes

How to implement Marching Cubes as IJobParallelFor

I don't know how to get the Job System implemented in my code. Would be great if someone could give me a rough idea on how to do it.

Here's my code rn:

 for( int x=0 ; x<width-1 ; x++ )
 for( int y=0 ; y<height-1 ; y++ )
 for( int z=0 ; z<depth-1 ; z++ )
 {
     // get the values in the 8 neighbours which make up a cube
     for( int i=0 ; i<8 ; i++ )
     {
         int ix = x + VertexOffset[i,0];
         int iy = y + VertexOffset[i,1];
         int iz = z + VertexOffset[i,2];
         Cube[i] = voxels[ ix + iy*width + iz*width * height ];
     }
 
     // perform algorithm
     March( x , y , z , Cube , verts , indices );
 }

And the Vertex Offset array:

 protected static readonly int[,] VertexOffset = new int[,]
 {
     {0,0,0} , {1,0,0} , {1,1,0} , {0,1,0} ,
     {0,0,1} , {1,0,1} , {1,1,1} , {0,1,1}
 };

Can i get this to work using IJobParallelFor and when yes, then how would i get the data needed for the March function?

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image andrew-lukasik · Feb 17 at 09:46 PM 0
Share


I don't know how to get the Job System implemented in my code

Here is a starting point:

 public struct ThyJob : IJobParallelFor
 {
     [ReadOnly] NativeArray<?> Voxels;
     [WriteOnly] NativeArray<?> Cube;
     void IJobParallelFor.Execute ( int i )
     {
         foreach neighbour
             Cube[i] = Voxels[ neighbour ];// idk what this is, but fine
     }
 }


No idea what that Cube array is. The basic setup for marching cubes algo is:

  1. Iterate neighbors to create a bitmask representations.

  2. Create a mesh, cell by cell, using bitmasks as lookup hashes/keys to find matching geometry

  3. That's it


    // get the values in the 8 neighbours which make up a cube

    3d grid cell has either 6 or 14 neighbors
avatar image BoredVoid · Feb 18 at 05:33 AM 0
Share

I figure i'll have to make the March function into an IJobParallelFor but how would i start them parallel and how would i give them the data they need?

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by andrew-lukasik · Feb 23 at 09:45 PM


Here is an example of how to read the voxel field in a IJobParallelFor and construct basic mesh data with 4 different IJob executed in parallel (thanks to scheduling setup and RO dependencies).


https://i.imgur.com/X63acUO.gif

To make this code work, import this mesh into your project: marching-squares-prototype.fbx ( RMB/Save link as...)

And use it to fill the Template field as follows:

alt text


profiler timeline for 32/32/32 grid; 32k voxels @ i3-4170 cpu:

https://i.imgur.com/hjuR6Cs.jpg



LetsCubeMarch.cs

 // web* src = https://gist.github.com/andrew-raphael-lukasik/cbf9d0097c3b4da67b5e0ecb3715e219
 using UnityEngine;
 using Unity.Mathematics;
 using Unity.Collections;
 using Unity.Jobs;
 using UnityEngine.Rendering;
 
 using BurstCompile = Unity.Burst.BurstCompileAttribute;
 
 [RequireComponent( typeof(MeshFilter) , typeof(MeshRenderer) )]
 public class LetsCubeMarch : MonoBehaviour
 {
     [SerializeField] int3 _numCells = new int3( 32 , 32 , 32 );
     [SerializeField] float3 _noiseRepetition = new float3( 10 , 10 , 10 );
     [SerializeField] float3 _noiseOffset = new float3( 0.5f , 1.4f , -0.35f );
     [SerializeField][Range(0,1)] float _fill = 0.45f;
     [SerializeField] Mesh[] _template = new Mesh[6];
     public JobHandle Dependency = default(JobHandle);
     NativeArray<byte> _voxels;
     NativeArray<int> _templateIndices0, _templateIndices1, _templateIndices2, _templateIndices3, _templateIndices4, _templateIndices5;
     NativeArray<Vector3> _templateVertices0, _templateVertices1, _templateVertices2, _templateVertices3, _templateVertices4, _templateVertices5;
     NativeArray<Vector3> _templateNormals0, _templateNormals1, _templateNormals2, _templateNormals3, _templateNormals4, _templateNormals5;
     NativeArray<Vector2> _templateUVs0, _templateUVs1, _templateUVs2, _templateUVs3, _templateUVs4, _templateUVs5;
     NativeList<int> _indices;
     NativeList<Vector3> _vertices, _normals;
     NativeList<Vector2> _uv;
     NativeList<VoxelsToBitmasksJob.Entry> _relevantVoxelData;
     Mesh _mesh = null;
     bool _voxelsChanged, _jobScheduled;
 
     void Awake ()
     {
         _mesh = new Mesh();
         for( int i=0 ; i<_template.Length ; i++ )
             Debug.Log($"template {i} // topology:{_template[i].GetTopology(0)}, tri:{_template[i].triangles.Length}, vert:{_template[i].vertices.Length}");
         _mesh.MarkDynamic();
         GetComponent<MeshFilter>().sharedMesh = _mesh;
 
         var generateVoxelsJob = new GenerateVoxelsJob( numCells:_numCells , threshold:1.0f-_fill*2f , noiseRepetition:_noiseRepetition , noiseOffset:_noiseOffset , Allocator.TempJob );
         generateVoxelsJob.Schedule( _numCells.x*_numCells.y*_numCells.z , 128 ).Complete();
         _voxels = generateVoxelsJob.Results;
         _voxelsChanged = true;
 
         _indices = new NativeList<int>( Allocator.Persistent );
         _vertices = new NativeList<Vector3>( Allocator.Persistent );
         _normals = new NativeList<Vector3>( Allocator.Persistent );
         _uv = new NativeList<Vector2>( Allocator.Persistent );
         _relevantVoxelData = new NativeList<VoxelsToBitmasksJob.Entry>( Allocator.Persistent );
 
         _templateVertices0 = new NativeArray<Vector3>( _template[0].vertices , Allocator.Persistent );// x-
         _templateVertices1 = new NativeArray<Vector3>( _template[1].vertices , Allocator.Persistent );// x+
         _templateVertices2 = new NativeArray<Vector3>( _template[2].vertices , Allocator.Persistent );// y-
         _templateVertices3 = new NativeArray<Vector3>( _template[3].vertices , Allocator.Persistent );// y+
         _templateVertices4 = new NativeArray<Vector3>( _template[4].vertices , Allocator.Persistent );// z-
         _templateVertices5 = new NativeArray<Vector3>( _template[5].vertices , Allocator.Persistent );// z+
 
         _templateNormals0 = new NativeArray<Vector3>( _template[0].normals , Allocator.Persistent );// x-
         _templateNormals1 = new NativeArray<Vector3>( _template[1].normals , Allocator.Persistent );// x+
         _templateNormals2 = new NativeArray<Vector3>( _template[2].normals , Allocator.Persistent );// y-
         _templateNormals3 = new NativeArray<Vector3>( _template[3].normals , Allocator.Persistent );// y+
         _templateNormals4 = new NativeArray<Vector3>( _template[4].normals , Allocator.Persistent );// z-
         _templateNormals5 = new NativeArray<Vector3>( _template[5].normals , Allocator.Persistent );// z+
 
         _templateUVs0 = new NativeArray<Vector2>( _template[0].uv , Allocator.Persistent );// x-
         _templateUVs1 = new NativeArray<Vector2>( _template[1].uv , Allocator.Persistent );// x+
         _templateUVs2 = new NativeArray<Vector2>( _template[2].uv , Allocator.Persistent );// y-
         _templateUVs3 = new NativeArray<Vector2>( _template[3].uv , Allocator.Persistent );// y+
         _templateUVs4 = new NativeArray<Vector2>( _template[4].uv , Allocator.Persistent );// z-
         _templateUVs5 = new NativeArray<Vector2>( _template[5].uv , Allocator.Persistent );// z+
         
         _templateIndices0 = new NativeArray<int>( _template[0].triangles , Allocator.Persistent );// x-
         _templateIndices1 = new NativeArray<int>( _template[1].triangles , Allocator.Persistent );// x+
         _templateIndices2 = new NativeArray<int>( _template[2].triangles , Allocator.Persistent );// y-
         _templateIndices3 = new NativeArray<int>( _template[3].triangles , Allocator.Persistent );// y+
         _templateIndices4 = new NativeArray<int>( _template[4].triangles , Allocator.Persistent );// z-
         _templateIndices5 = new NativeArray<int>( _template[5].triangles , Allocator.Persistent );// z+
     }
 
     void OnDestroy ()
     {
         Dependency.Complete();
 
         if( _voxels.IsCreated ) _voxels.Dispose();
         if( _indices.IsCreated ) _indices.Dispose();
         if( _vertices.IsCreated ) _vertices.Dispose();
         if( _normals.IsCreated ) _normals.Dispose();
         if( _uv.IsCreated ) _uv.Dispose();
         if( _relevantVoxelData.IsCreated ) _relevantVoxelData.Dispose();
 
         if( _templateVertices0.IsCreated ) _templateVertices0.Dispose();
         if( _templateVertices1.IsCreated ) _templateVertices1.Dispose();
         if( _templateVertices2.IsCreated ) _templateVertices2.Dispose();
         if( _templateVertices3.IsCreated ) _templateVertices3.Dispose();
         if( _templateVertices4.IsCreated ) _templateVertices4.Dispose();
         if( _templateVertices5.IsCreated ) _templateVertices5.Dispose();
 
         if( _templateNormals0.IsCreated ) _templateNormals0.Dispose();
         if( _templateNormals1.IsCreated ) _templateNormals1.Dispose();
         if( _templateNormals2.IsCreated ) _templateNormals2.Dispose();
         if( _templateNormals3.IsCreated ) _templateNormals3.Dispose();
         if( _templateNormals4.IsCreated ) _templateNormals4.Dispose();
         if( _templateNormals5.IsCreated ) _templateNormals5.Dispose();
 
         if( _templateUVs0.IsCreated ) _templateUVs0.Dispose();
         if( _templateUVs1.IsCreated ) _templateUVs1.Dispose();
         if( _templateUVs2.IsCreated ) _templateUVs2.Dispose();
         if( _templateUVs3.IsCreated ) _templateUVs3.Dispose();
         if( _templateUVs4.IsCreated ) _templateUVs4.Dispose();
         if( _templateUVs5.IsCreated ) _templateUVs5.Dispose();
 
         if( _templateIndices0.IsCreated ) _templateIndices0.Dispose();
         if( _templateIndices1.IsCreated ) _templateIndices1.Dispose();
         if( _templateIndices2.IsCreated ) _templateIndices2.Dispose();
         if( _templateIndices3.IsCreated ) _templateIndices3.Dispose();
         if( _templateIndices4.IsCreated ) _templateIndices4.Dispose();
         if( _templateIndices5.IsCreated ) _templateIndices5.Dispose();
 
         if( _templateUVs0.IsCreated ) _templateUVs0.Dispose();
         if( _templateUVs1.IsCreated ) _templateUVs1.Dispose();
         if( _templateUVs2.IsCreated ) _templateUVs2.Dispose();
         if( _templateUVs3.IsCreated ) _templateUVs3.Dispose();
         if( _templateUVs4.IsCreated ) _templateUVs4.Dispose();
         if( _templateUVs5.IsCreated ) _templateUVs5.Dispose();
 
         Destroy( _mesh );
     }
     
     void Update ()
     {
         Dependency.Complete();
         if( _jobScheduled )
         {
             Debug.Log($"new mesh data // indices:{_indices.Length}, vertices:{_vertices.Length}, normals:{_normals.Length}, uv:{_uv.Length} ");
             
             _mesh.Clear();
             _mesh.SetVertices( _vertices.AsArray() );
             _mesh.SetNormals( _normals.AsArray() );
             _mesh.SetUVs( 0 , _uv.AsArray() );
             _mesh.indexFormat = _indices.Length>ushort.MaxValue ? IndexFormat.UInt32 : IndexFormat.UInt16;
             _mesh.SetIndices( _indices.AsArray() , MeshTopology.Triangles , 0 );
 
             _jobScheduled = false;
         }
 
         if( _voxelsChanged )
         {
             _vertices.Clear();
             _indices.Clear();
             _normals.Clear();
             _uv.Clear();
             _relevantVoxelData.Clear();
             int maxCellCount = _numCells.x * _numCells.y * _numCells.z;
             int maxVerticesInSingleTemplateMesh = 4;// estimate the max number of vertices (you may want to change this when mesh changes)
             int maxVertices = maxCellCount * 6*maxVerticesInSingleTemplateMesh;
             _relevantVoxelData.Capacity = maxCellCount;
 
             var voxelsToBitmasksJob = new VoxelsToBitmasksJob{
                 NumCells            = _numCells ,
                 Voxels                = _voxels ,
                 Results                = _relevantVoxelData.AsParallelWriter() ,
             };
             var vertJob = new VertJob{
                 Entries                = _relevantVoxelData ,
                 Vertices            = _vertices ,
                 TemplateVertices0    = _templateVertices0 ,
                 TemplateVertices1    = _templateVertices1 ,
                 TemplateVertices2    = _templateVertices2 ,
                 TemplateVertices3    = _templateVertices3 ,
                 TemplateVertices4    = _templateVertices4 ,
                 TemplateVertices5    = _templateVertices5 ,
             };
             var normJob = new NormalsJob{
                 Entries                = _relevantVoxelData ,
                 Normals                = _normals ,
                 TemplateNormals0    = _templateNormals0 ,
                 TemplateNormals1    = _templateNormals1 ,
                 TemplateNormals2    = _templateNormals2 ,
                 TemplateNormals3    = _templateNormals3 ,
                 TemplateNormals4    = _templateNormals4 ,
                 TemplateNormals5    = _templateNormals5 ,
             };
             var uvJob = new UVJob{
                 Entries                = _relevantVoxelData ,
                 UV                    = _uv ,
                 TemplateUVs0        = _templateUVs0 ,
                 TemplateUVs1        = _templateUVs1 ,
                 TemplateUVs2        = _templateUVs2 ,
                 TemplateUVs3        = _templateUVs3 ,
                 TemplateUVs4        = _templateUVs4 ,
                 TemplateUVs5        = _templateUVs5 ,
             };
             var indicesJob = new IndicesJob{
                 Entries                = _relevantVoxelData ,
                 Indices                = _indices ,
                 TemplateIndices0    = _templateIndices0 ,
                 TemplateIndices1    = _templateIndices1 ,
                 TemplateIndices2    = _templateIndices2 ,
                 TemplateIndices3    = _templateIndices3 ,
                 TemplateIndices4    = _templateIndices4 ,
                 TemplateIndices5    = _templateIndices5 ,
                 TemplateVertices0Length    = _templateVertices0.Length ,
                 TemplateVertices1Length    = _templateVertices1.Length ,
                 TemplateVertices2Length    = _templateVertices2.Length ,
                 TemplateVertices3Length    = _templateVertices3.Length ,
                 TemplateVertices4Length    = _templateVertices4.Length ,
                 TemplateVertices5Length    = _templateVertices5.Length ,
             };
             
             Dependency = voxelsToBitmasksJob.Schedule( _voxels.Length , _numCells.x*_numCells.y , Dependency );
             var parallelJobs = new NativeArray<JobHandle>( 4 , Allocator.Temp );
             parallelJobs[0] = vertJob.Schedule( Dependency );
             parallelJobs[1] = normJob.Schedule( Dependency );
             parallelJobs[2] = uvJob.Schedule( Dependency );
             parallelJobs[3] = indicesJob.Schedule( Dependency );
             Dependency = JobHandle.CombineDependencies( parallelJobs );
             
             _voxelsChanged = false;
             _jobScheduled = true;
         }
     }
 
     #if UNITY_EDITOR
     void OnValidate ()
     {
         if( Application.isPlaying && _voxels.IsCreated )
         {
             if( _jobScheduled )
             {
                 Dependency.Complete();
                 _jobScheduled = false;
             }
             _voxels.Dispose();
             var generateVoxelsJob = new GenerateVoxelsJob( numCells:_numCells , threshold:1.0f-_fill*2f , noiseRepetition:_noiseRepetition , noiseOffset:_noiseOffset , Allocator.TempJob );
             generateVoxelsJob.Schedule( _numCells.x*_numCells.y*_numCells.z , 128 ).Complete();
             _voxels = generateVoxelsJob.Results;
             _voxelsChanged = true;
         }
     }
     void OnDrawGizmos ()
     {
         float3 cellSize = Vector3.one;
         Gizmos.matrix = transform.localToWorldMatrix;
         if( !Application.isPlaying )
         {
             int len = _numCells.x*_numCells.y*_numCells.z;
             var positionsNative = new NativeList<float3>( len , Allocator.TempJob );
             var job = new OnDrawGizmosJob{
                 NumCells            = _numCells ,
                 Threshold            = 1.0f-_fill*2f ,
                 NoiseRepetition        = _noiseRepetition ,
                 NoiseOffset            = _noiseOffset ,
                 Results                = positionsNative.AsParallelWriter() ,
             };
             job.Schedule( len , _numCells.x*_numCells.y ).Complete();
             float3[] positions = positionsNative.ToArray();
             positionsNative.Dispose();
 
             Gizmos.color = Color.black;
             foreach( float3 point in positions )
                 Gizmos.DrawCube( point , cellSize );
         }
         Gizmos.color = Color.yellow;
         Gizmos.DrawWireCube( (float3)_numCells * 0.5f , (float3)_numCells * cellSize );
     }
     
     [BurstCompile] struct OnDrawGizmosJob : IJobParallelFor
     {
         public int3 NumCells;
         public float Threshold;
         public float3 NoiseRepetition;
         public float3 NoiseOffset;
         [WriteOnly] public NativeList<float3>.ParallelWriter Results;
 
         void IJobParallelFor.Execute ( int i )
         {
             int3 coords = default(Utilities).IndexToCoords( i:i , numCells:NumCells );
             byte voxel = default(Utilities).CoordsToVoxel( coords:coords , numCells:NumCells , threshold:Threshold , noiseRepetition:NoiseRepetition , noiseOffset:NoiseOffset );
             if( voxel!=0 )
             {
                 float3 cellCenter = (float3)coords + new float3{ x=0.5f , y=0.5f , z=0.5f };
                 Results.AddNoResize( cellCenter );
             }
         }
     }
     #endif
 
     [BurstCompile] public struct GenerateVoxelsJob : IJobParallelFor
     {
         public int3 NumCells;
         public float Threshold;
         public float3 NoiseRepetition;
         public float3 NoiseOffset;
         [WriteOnly] public NativeArray<byte> Results;
         public GenerateVoxelsJob ( int3 numCells , float threshold , float3 noiseRepetition , float3 noiseOffset , Allocator allocator )
         {
             this.NumCells = numCells;
             this.Threshold = threshold;
             this.NoiseRepetition = noiseRepetition;
             this.NoiseOffset = noiseOffset;
             this.Results = new NativeArray<byte>( numCells.x*numCells.y*numCells.z , allocator );
         }
         void IJobParallelFor.Execute ( int index )
         {
             int3 coords = default(Utilities).IndexToCoords( i:index , numCells:NumCells );
             Results[index] = default(Utilities).CoordsToVoxel( coords:coords , numCells:NumCells , threshold:Threshold , noiseRepetition:NoiseRepetition , noiseOffset:NoiseOffset );
         }
     }
 
     [BurstCompile] public struct VoxelsToBitmasksJob : IJobParallelFor
     {
         public int3 NumCells;
         [ReadOnly] public NativeArray<byte> Voxels;
         [WriteOnly] public NativeList<Entry>.ParallelWriter Results;
         void IJobParallelFor.Execute ( int index )
         {
             if( Voxels[index]==0 )// iterate empty cells only
             {
                 int3 cellCoords = default(Utilities).IndexToCoords( i:index , numCells:NumCells );
                 int bitmask = 0;
                 for( byte direction=0 ; direction<6 ; direction++ )
                 {
                     int3 neighbourCoords = cellCoords + default(Utilities).Offset(direction);
                     if( !math.any( neighbourCoords<0 | neighbourCoords>=NumCells ) )// index bounds test
                         if( Voxels[default(Utilities).CoordsToIndex(neighbourCoords,NumCells)]!=0 )
                             bitmask |= 1<<direction;
                 }
                 if( bitmask!=0 )// ignore cells neighbouring empty space only
                 {
                     Results.AddNoResize( new Entry{
                         Bitmask        = bitmask ,
                         Coords        = cellCoords
                     } );
                 }
             }
         }
         public struct Entry
         {
             public int Bitmask;
             public int3 Coords;
         }
     }
 
     [BurstCompile] public struct IndicesJob : IJob
     {
         [WriteOnly] public NativeList<int> Indices;
         [ReadOnly] public NativeList<VoxelsToBitmasksJob.Entry> Entries;
         [ReadOnly] public NativeArray<int> TemplateIndices0, TemplateIndices1, TemplateIndices2, TemplateIndices3, TemplateIndices4, TemplateIndices5;
         public int TemplateVertices0Length, TemplateVertices1Length, TemplateVertices2Length, TemplateVertices3Length, TemplateVertices4Length, TemplateVertices5Length;
         void IJob.Execute ()
         {
             int baseIndex = 0;
             foreach( var next in Entries.AsArray() )
             {
                 int bitmask = next.Bitmask;
                 for( byte direction=0 ; direction<6 ; direction++ )
                 if( (bitmask&1<<direction)==1<<direction )// the same as Voxels[neighbourIndex]!=0, but read from bitmask, so it's faster and you can test many directions at once
                 switch( direction )
                 {
                     case 0: foreach( int index in TemplateIndices0 ) Indices.Add( baseIndex + index ); baseIndex += TemplateVertices0Length; break;// x-
                     case 1: foreach( int index in TemplateIndices1 ) Indices.Add( baseIndex + index ); baseIndex += TemplateVertices1Length; break;// x+
                     case 2: foreach( int index in TemplateIndices2 ) Indices.Add( baseIndex + index ); baseIndex += TemplateVertices2Length; break;// y-
                     case 3: foreach( int index in TemplateIndices3 ) Indices.Add( baseIndex + index ); baseIndex += TemplateVertices3Length; break;// y+
                     case 4: foreach( int index in TemplateIndices4 ) Indices.Add( baseIndex + index ); baseIndex += TemplateVertices4Length; break;// z-
                     case 5: foreach( int index in TemplateIndices5 ) Indices.Add( baseIndex + index ); baseIndex += TemplateVertices5Length; break;// z+
                 }
             }
         }
     }
 
     [BurstCompile] public struct VertJob : IJob
     {
         [WriteOnly] public NativeList<Vector3> Vertices;
         [ReadOnly] public NativeList<VoxelsToBitmasksJob.Entry> Entries;
         [ReadOnly] public NativeArray<Vector3> TemplateVertices0, TemplateVertices1, TemplateVertices2, TemplateVertices3, TemplateVertices4, TemplateVertices5;
         void IJob.Execute ()
         {
             foreach( var next in Entries.AsArray() )
             {
                 int3 cellCoords = next.Coords;
                 int bitmask = next.Bitmask;
                 float3 cellCenter = (float3) cellCoords + new float3{ x=0.5f , y=0.5f , z=0.5f };
                 for( byte direction=0 ; direction<6 ; direction++ )
                 if( (bitmask&1<<direction)==1<<direction )// the same as Voxels[neighbourIndex]!=0, but read from bitmask, so it's faster and you can test many directions at once
                 switch( direction )
                 {
                     case 0: foreach( Vector3 vert in TemplateVertices0 ) Vertices.Add( cellCenter + (float3)vert ); break;// x-
                     case 1: foreach( Vector3 vert in TemplateVertices1 ) Vertices.Add( cellCenter + (float3)vert ); break;// x+
                     case 2: foreach( Vector3 vert in TemplateVertices2 ) Vertices.Add( cellCenter + (float3)vert ); break;// y-
                     case 3: foreach( Vector3 vert in TemplateVertices3 ) Vertices.Add( cellCenter + (float3)vert ); break;// y+
                     case 4: foreach( Vector3 vert in TemplateVertices4 ) Vertices.Add( cellCenter + (float3)vert ); break;// z-
                     case 5: foreach( Vector3 vert in TemplateVertices5 ) Vertices.Add( cellCenter + (float3)vert ); break;// z+
                 }
             }
         }
     }
 
     [BurstCompile] public struct NormalsJob : IJob
     {
         [WriteOnly] public NativeList<Vector3> Normals;
         [ReadOnly] public NativeList<VoxelsToBitmasksJob.Entry> Entries;
         [ReadOnly] public NativeArray<Vector3> TemplateNormals0, TemplateNormals1, TemplateNormals2, TemplateNormals3, TemplateNormals4, TemplateNormals5;
         void IJob.Execute ()
         {
             foreach( var next in Entries.AsArray() )
             {
                 int3 cellCoords = next.Coords;
                 int bitmask = next.Bitmask;
                 for( byte direction=0 ; direction<6 ; direction++ )
                 if( (bitmask&1<<direction)==1<<direction )// the same as Voxels[neighbourIndex]!=0, but read from bitmask, so it's faster and you can test many directions at once
                 switch( direction )
                 {
                     case 0: Normals.AddRange( TemplateNormals0 ); break;// x-
                     case 1: Normals.AddRange( TemplateNormals1 ); break;// x+
                     case 2: Normals.AddRange( TemplateNormals2 ); break;// y-
                     case 3: Normals.AddRange( TemplateNormals3 ); break;// y+
                     case 4: Normals.AddRange( TemplateNormals4 ); break;// z-
                     case 5: Normals.AddRange( TemplateNormals5 ); break;// z+
                 }
             }
         }
     }
 
     [BurstCompile] public struct UVJob : IJob
     {
         [WriteOnly] public NativeList<Vector2> UV;
         [ReadOnly] public NativeList<VoxelsToBitmasksJob.Entry> Entries;
         [ReadOnly] public NativeArray<Vector2> TemplateUVs0, TemplateUVs1, TemplateUVs2, TemplateUVs3, TemplateUVs4, TemplateUVs5;
         void IJob.Execute ()
         {
             foreach( var next in Entries.AsArray() )
             {
                 int bitmask = next.Bitmask;
                 for( byte direction=0 ; direction<6 ; direction++ )
                 if( (bitmask&1<<direction)==1<<direction )// the same as Voxels[neighbourIndex]!=0, but read from bitmask, so it's faster and you can test many directions at once
                 switch( direction )
                 {
                     case 0: UV.AddRange( TemplateUVs0 ); break;// x-
                     case 1: UV.AddRange( TemplateUVs1 ); break;// x+
                     case 2: UV.AddRange( TemplateUVs2 ); break;// y-
                     case 3: UV.AddRange( TemplateUVs3 ); break;// y+
                     case 4: UV.AddRange( TemplateUVs4 ); break;// z-
                     case 5: UV.AddRange( TemplateUVs5 ); break;// z+
                 }
             }
         }
     }
 
     public struct Utilities
     {
         public int3 Offset ( int direction )
         {
             switch( direction )
             {
                 case 0:        return new int3{ x=-1 };// x-
                 case 1:        return new int3{ x=+1 };// x+
                 case 2:        return new int3{ y=-1 };// y-
                 case 3:        return new int3{ y=+1 };// y+
                 case 4:        return new int3{ z=-1 };// z-
                 case 5:        return new int3{ z=+1 };// z+
                 default:    throw new System.ArgumentOutOfRangeException();
             }
         }
         public int CoordsToIndex ( int x , int y , int z , int3 numCells ) => z*numCells.x*numCells.y + y*numCells.x + x;
         public int CoordsToIndex ( int3 coords , int3 numCells ) => this.CoordsToIndex( x:coords.x , y:coords.y , z:coords.z , numCells:numCells );
         public int3 IndexToCoords ( int i , int3 numCells )
         {
             int numSlices = numCells.x * numCells.y;
             int z = i / numSlices;
             int ilayer = i % numSlices;
             int y = ilayer / numCells.x;
             int x = ilayer % numCells.x;
             return new int3{ x=x , y=y , z=z };
         }
         public void IndexToCoords ( int i , int3 numCells , out int x , out int y , out int z )
         {
             int3 coords = this.IndexToCoords( i:i , numCells:numCells );
             x = coords.x;
             y = coords.y;
             z = coords.z;
         }
         public byte CoordsToVoxel ( int3 coords , int3 numCells , float threshold , float3 noiseRepetition , float3 noiseOffset )
         {
             float3 noisePos = (float3)coords/(float3)numCells + noiseOffset;
             return noise.pnoise(noisePos,noiseRepetition)>threshold ? (byte)1 : (byte)0;
         }
     }
 
 }



marching-squares-prototypefbx.zip (6.5 kB)
screenshot-2022-02-23-221300.jpg (31.8 kB)
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image BoredVoid · Feb 24 at 12:50 PM 0
Share

Ok first of all, thanks for this amazing help. It's nice to see such nice people online. Second of all, i think i've nearly understood your code now, but if i want to maker a "real" marching cubes algorithm, then i'd have to get Native Arrays with multiple dimension for for example the Triangle Connection Table. So i searched online a bit but i can't seem to find a way to do x dimensional Natives Arrays. Any tipps? Do i just flatten/unflatten it? Thanks in advance

avatar image andrew-lukasik BoredVoid · Feb 24 at 05:11 PM 0
Share


Do i just flatten/unflatten it?

Yes


i want to maker a "real" marching cubes algorithm

This one is quite real to me. There are many different variants (distance fields instead of voxels or different mesh sets) but the core idea remains the same. I give you the basic implementation for you to take it in whatever direction you need.


Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

133 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Get GameObject dependencies only once for JobComponentSystem 1 Answer

Can the burst compiler be used for any code? 0 Answers

Does DOTS have a animation component? 1 Answer

Someone Please provide reference materials for starting with Unity Dots 1 Answer

ECS System OnUpdate not being called on Unity 2020.1b7 + UniRx 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges