Search Unity

Any sort of way to obtain the position of a key inside of NativeHashMap

Discussion in 'Entity Component System' started by Matt_De_Boss_Developer, May 28, 2019.

  1. Matt_De_Boss_Developer

    Matt_De_Boss_Developer

    Joined:
    Oct 17, 2014
    Posts:
    46
    So at the current moment I am attempting to implement a job that takes all active edges and voxels of a density field and then creates vertex data from that field. Both the edges and active voxel ids are storing in HashMaps. However, I am using a NativeHashMap for the voxel ids only to attempt to replicate the usage of a HashSet instead of a HashMap. However, in the job that I have created to visit each active voxel ID (each key in the NativeHashMap is that ID, rather than a HashSet storing all of the ids), I need some sort of way to figure out where each ID lies inside of the NativeHashMap in order to obtain the index of the key in the HashMap (if that makes any sense). This is too be able to use a NativeSlice that is cut out of a NativeArray passed to the job, and it is to be able to take the index of the key and use that index to be able to set data in another NativeArray (example, our Active Voxel ID is 1, so lets go to array[1], and set the value of that array the vertex calculated using a QEF solver). Code is below:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Jobs;
    5. using Unity.Collections;
    6. using Unity.Burst;
    7. using NativeContainers;
    8.  
    9. using static Unity.Mathematics.math;
    10.  
    11. using Unity.Mathematics;
    12.  
    13. [BurstCompile]
    14. public class GenerateVertexDataJob : IJobNativeMultiHashMapVisitKeyValue<int,int> //Using NativeHashMap as a replacement for HashSet
    15.  
    16. {
    17.    
    18.  
    19.     NativeArray<float4> positionMemoryPool;
    20.     NativeArray<float4> normalMemoryPool;
    21.  
    22.     public void ExecuteNext(int key, int value)
    23.     {
    24.         //throw new System.NotImplementedException();
    25.         NativeSlice<float4> p = positionMemoryPool.Slice(INDEX OF KEY HERE * 12, 12);
    26.         NativeSlice<float4> n = normalMemoryPool.Slice(INDEX OF KEY HERE * 12, 12);
    27.  
    28.  
    29.     }
    30. }
    31.  
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    You mentioned edges. So I assume, you know dimensions of your voxel space?
    If so, why not store voxels data in NativeArray or DynamicBuffer? Then you can access them by key/index, since should be known.
     
  3. Matt_De_Boss_Developer

    Matt_De_Boss_Developer

    Joined:
    Oct 17, 2014
    Posts:
    46
    I don't know if I completely understand, but the idea is that I am storing only the active voxels and edges in a NativeHashMap in order to not waste time on processing voxels that aren't on the edge of the volume. The code for what I am doing to obtain these active edges and voxels is below.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Jobs;
    5. using Unity.Burst;
    6. using Unity.Collections;
    7. using NativeContainers;
    8.  
    9. using static Unity.Mathematics.math;
    10.  
    11. using Unity.Mathematics;
    12. public struct Edge
    13. {
    14.     public float4 pos;
    15.     public float4 normal;
    16.     public bool winding;
    17.  
    18. }
    19.  
    20.  
    21. [BurstCompile]
    22. public struct FindActiveVoxelAndEdgesJob : IJobParallelFor
    23. {
    24.  
    25.     [NativeDisableParallelForRestriction] [WriteOnly]
    26.     public NativeHashMap<int, Edge>.Concurrent activeEdges;
    27.  
    28.     [NativeDisableParallelForRestriction]
    29.     [WriteOnly]
    30.     public NativeHashMap<int,int>.Concurrent activeVoxels;
    31.  
    32.  
    33.  
    34.     [NativeDisableParallelForRestriction] [ReadOnly] public NativeArray<float4> AXIS_OFFSET;
    35.  
    36.     [NativeDisableParallelForRestriction] [ReadOnly] public NativeArray<float4> EDGE_NODE_OFFSETS;
    37.  
    38.  
    39.  
    40.  
    41.     public int SizeX;
    42.     public int SizeY;
    43.     public void Execute(int i)
    44.     {
    45.  
    46.         int iz = i / ((SizeX - 0) * (SizeY - 0));
    47.         int ib = i - (((SizeX - 0) * (SizeY - 0)) * iz);
    48.         int iy = ib / (SizeX - 0);
    49.         int ix = ib % (SizeX - 0);
    50.  
    51.         float z = iz;
    52.         float y = iy;
    53.         float x = ix;
    54.  
    55.         float4 idxPos = float4(x, y, z, 0);
    56.         float4 p = idxPos;
    57.  
    58.         for (int axis = 0; axis < 3; axis++)
    59.         {
    60.             float4 q = p + AXIS_OFFSET[axis];
    61.  
    62.             //Debug.Log(AXIS_OFFSET[axis]);
    63.  
    64.             float pDensity = Density(p.xyz);
    65.             float qDensity = Density(q.xyz);
    66.  
    67.  
    68.             bool zeroCrossing =
    69.                 pDensity >= 0.0f && qDensity < 0.0f ||
    70.                 pDensity < 0.0f && qDensity >= 0.0f;
    71.  
    72.  
    73.             if (!zeroCrossing)
    74.             {
    75.                 continue;
    76.             }
    77.  
    78.  
    79.             float t = FindIntersection(p, q);
    80.  
    81.  
    82.  
    83.             float4 pos = float4(VertexInterp(p.xyz, q.xyz, pDensity, qDensity), 1);
    84.  
    85.  
    86.             float H = 0.001f;
    87.  
    88.  
    89.             float4 normal = normalize(float4(
    90.                 Density(pos.xyz + float3(H, 0.0f, 0.0f)) - Density(pos.xyz - float3(H, 0.0f, 0.0f)),
    91.                 Density(pos.xyz + float3(0.0f, H, 0.0f)) - Density(pos.xyz - float3(0.0f, H, 0.0f)),
    92.                 Density(pos.xyz + float3(0.0f, 0.0f, H)) - Density(pos.xyz - float3(0.0f, 0.0f, H)),
    93.                 0.0f));
    94.  
    95.             Edge edge;
    96.             edge.pos = pos;
    97.             edge.normal = normal;
    98.             edge.winding = pDensity >= 0.0f;
    99.  
    100.             int code = EncodeAxisUniqueID(axis, (int)x, (int)y, (int)z);
    101.             activeEdges.TryAdd(code, edge);
    102.  
    103.             for (int e = 0; e < 4; e++)
    104.             {
    105.                 float4 nodeIdxPos = idxPos - EDGE_NODE_OFFSETS[(axis * 4) + e];
    106.                 int nodeID = EncodeVoxelUniqueID(nodeIdxPos);
    107.                 activeVoxels.TryAdd(nodeID, i);
    108.              
    109.             }
    110.  
    111.         }
    112.  
    113.     }
    114.  
    115.     int EncodeAxisUniqueID(int axis, int x, int y, int z)
    116.     {
    117.         return (x << 0) | (y << 10) | (z << 20) | (axis << 30);
    118.     }
    119.  
    120.     int EncodeVoxelUniqueID(float4 idxPos)
    121.     {
    122.             return (int)idxPos.x | ((int)idxPos.y << 10) | ((int)idxPos.z << 20);
    123.     }
    124.  
    125.  
    126.     public float3 VertexInterp(float3 p1, float3 p2, float v1, float v2)
    127.     {
    128.         float mu;
    129.         float3 p;
    130.  
    131.  
    132.  
    133.         mu = (0 - v1) / (v2 - v1);
    134.         p.x = p1.x + mu * (p2.x - p1.x);
    135.         p.y = p1.y + mu * (p2.y - p1.y);
    136.         p.z = p1.z + mu * (p2.z - p1.z);
    137.  
    138.  
    139.  
    140.         return p;
    141.     }
    142.  
    143.     public float Density(float3 pos)
    144.     {
    145.  
    146.         return noise.snoise(pos/16);
    147.  
    148.     }
    149.  
    150.  
    151.  
    152.    
    153.     float FindIntersection(float4 p0, float4 p1)
    154.     {
    155.         int FIND_EDGE_INFO_STEPS = 16;
    156.         float FIND_EDGE_INFO_INCREMENT = 1.0f / FIND_EDGE_INFO_STEPS;
    157.  
    158.         float minValue = float.MinValue;
    159.         float currentT = 0.0f;
    160.         float t = 0.0f;
    161.         for (int i = 0; i < FIND_EDGE_INFO_STEPS; i++)
    162.         {
    163.  
    164.             float4 p = lerp(p0, p1, currentT);
    165.             float d = abs(Density(p.xyz));
    166.             if(d < minValue)
    167.             {
    168.  
    169.                 t = currentT;
    170.                 minValue = d;
    171.             }
    172.  
    173.             currentT++;
    174.  
    175.  
    176.         }
    177.  
    178.  
    179.         return t;
    180.     }
    181.  
    182. }
    183.  
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    That makes sense.
    Well, I know there were while ago somebody request, to read keys.
    But don't remember, what was result / response of that.


    Personally, for most cases I utilize spare of buffer / array, so I don't need clear them, or defragment (compress) buffer / array. That may be suitable, when removing / adding many elements very often.

    As an example, if I remove elements in middle of the set, I just store that index in separate buffer / array, which is store of spares (ints index, to actual array).
    Then when i want to reuse that spare space, or multiple spare spaces, I take last index of spare, or I iterate through buffer / array of spares in ascending order, to get range of actual buffer / array.

    That allows to keep buffer / array relatively compact, while "adding" / "removing" many elements often.

    But may not be necessary suitable for your use, if you don't utilize spare.
    For example if you got 1k elements, and you remove first 999, you got one element still there, but length is still 1k. And you will need iterate through 1k elements anyway, even tho, 999 of them are spares. So that need to be kept in mind.