143 lines
4.2 KiB
C#
143 lines
4.2 KiB
C#
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
using Unity.Collections;
|
|||
|
using Unity.Mathematics;
|
|||
|
using Unity.Burst;
|
|||
|
using System;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
using Unity.Jobs;
|
|||
|
|
|||
|
namespace SLZ.CustomStaticBatching
|
|||
|
{
|
|||
|
public struct SortIdx : IComparable<SortIdx>
|
|||
|
{
|
|||
|
public UInt64 hilbertIdx;
|
|||
|
public int arrayIdx;
|
|||
|
|
|||
|
public int CompareTo(SortIdx other)
|
|||
|
{
|
|||
|
if (this.hilbertIdx > other.hilbertIdx) return 1;
|
|||
|
else if (this.hilbertIdx < other.hilbertIdx) return -1;
|
|||
|
else return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static class HilbertIndex
|
|||
|
{
|
|||
|
|
|||
|
[BurstCompile]
|
|||
|
struct HilbertIndexJob : IJobParallelFor
|
|||
|
{
|
|||
|
[WriteOnly]
|
|||
|
public NativeArray<UInt64> indices;
|
|||
|
[ReadOnly]
|
|||
|
public NativeArray<Vector3> positions;
|
|||
|
[ReadOnly]
|
|||
|
public double3 boundExtent;
|
|||
|
[ReadOnly]
|
|||
|
public double3 boundCenter;
|
|||
|
[ReadOnly]
|
|||
|
public double3 scale;
|
|||
|
|
|||
|
public void Execute(int i)
|
|||
|
{
|
|||
|
double3 position = (double3)(float3)positions[i];
|
|||
|
|
|||
|
position = (scale * (position - boundCenter) + boundExtent) / (2.0 * boundExtent);
|
|||
|
position = math.clamp(position, 0.0, 1.0);
|
|||
|
uint3 intPos = (uint3)((position * 2097152.0d)); // 2 ^ 21
|
|||
|
intPos = intPos & ((2 << 21) - 1);
|
|||
|
indices[i] = GetIndex(intPos.xyz);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Given an unsigned 21-bit integer coordinate of a point within some bounding volume, return the point's distance along a 21-fold hilbert curve.
|
|||
|
/// Based on the AxestoTranspose function found in the appendix of John Skilling; Programming the Hilbert curve. AIP Conference Proceedings 21 April 2004; 707 (1): 381<38>387. https://doi.org/10.1063/1.1751381
|
|||
|
/// </summary>
|
|||
|
/// <param name="boundingCoord">3d unsigned integer coordinate of the point inside of a defined bounding volume.</param>
|
|||
|
/// <returns>The Hilbert index</returns>
|
|||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
//[BurstCompatible]
|
|||
|
[BurstCompile]
|
|||
|
public static UInt64 GetIndex(uint3 boundingCoord)
|
|||
|
{
|
|||
|
int bits = 21;
|
|||
|
uint highestBit = 1U << (bits - 1);
|
|||
|
for (uint nextBit = highestBit; nextBit > 1; nextBit >>= 1)
|
|||
|
{
|
|||
|
uint allBitsSet = nextBit - 1;
|
|||
|
for (int axis = 0; axis < 3; axis++)
|
|||
|
{
|
|||
|
if ((boundingCoord[axis] & nextBit) != 0)
|
|||
|
{
|
|||
|
boundingCoord[0] ^= allBitsSet;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
uint t = (boundingCoord[0] ^ boundingCoord[axis]) & allBitsSet;
|
|||
|
boundingCoord[0] ^= t;
|
|||
|
boundingCoord[axis] ^= t;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (int axis = 1; axis < 3; axis++)
|
|||
|
{
|
|||
|
boundingCoord[axis] ^= boundingCoord[axis - 1];
|
|||
|
}
|
|||
|
uint t2 = 0;
|
|||
|
for (uint nextBit = highestBit; nextBit > 1; nextBit >>= 1)
|
|||
|
{
|
|||
|
if ((boundingCoord[3 - 1] & nextBit) != 0)
|
|||
|
t2 ^= nextBit - 1;
|
|||
|
}
|
|||
|
for (int axis = 0; axis < 3; axis++)
|
|||
|
{
|
|||
|
boundingCoord[axis] ^= t2;
|
|||
|
}
|
|||
|
|
|||
|
return Interleave63Bits(boundingCoord.zyx);
|
|||
|
}
|
|||
|
|
|||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
//[BurstCompatible]
|
|||
|
[BurstCompile]
|
|||
|
public static UInt64 Interleave63Bits(uint3 value)
|
|||
|
{
|
|||
|
Span<UInt64> longVal = stackalloc UInt64[3];
|
|||
|
for (int i = 0; i < 3; i++)
|
|||
|
{
|
|||
|
longVal[i] = value[i] & 0x1fffff;
|
|||
|
longVal[i] = (longVal[i] | longVal[i] << 32) & 0x1f00000000ffff;
|
|||
|
longVal[i] = (longVal[i] | longVal[i] << 16) & 0x1f0000ff0000ff;
|
|||
|
longVal[i] = (longVal[i] | longVal[i] << 8) & 0x100f00f00f00f00f;
|
|||
|
longVal[i] = (longVal[i] | longVal[i] << 4) & 0x10c30c30c30c30c3;
|
|||
|
longVal[i] = (longVal[i] | longVal[i] << 2) & 0x1249249249249249;
|
|||
|
}
|
|||
|
return longVal[0] | longVal[1] << 1 | longVal[2] << 2;
|
|||
|
}
|
|||
|
|
|||
|
public static NativeArray<UInt64> GetHilbertIndices(NativeArray<Vector3> positions, Bounds bounds, Allocator allocator)
|
|||
|
{
|
|||
|
return GetHilbertIndices(positions, bounds, Vector3.one, allocator);
|
|||
|
}
|
|||
|
public static NativeArray<UInt64> GetHilbertIndices(NativeArray<Vector3> positions, Bounds bounds, Vector3 scale, Allocator allocator)
|
|||
|
{
|
|||
|
NativeArray<UInt64> indices = new NativeArray<UInt64>(positions.Length, allocator);
|
|||
|
HilbertIndexJob indexJob = new HilbertIndexJob()
|
|||
|
{
|
|||
|
indices = indices,
|
|||
|
positions = positions,
|
|||
|
boundExtent = (double3)(float3)bounds.extents,
|
|||
|
boundCenter = (double3)(float3)bounds.center,
|
|||
|
scale = (double3)math.saturate((float3)scale)
|
|||
|
};
|
|||
|
JobHandle indexJobHandle = indexJob.Schedule(positions.Length, 8);
|
|||
|
indexJobHandle.Complete();
|
|||
|
return indices;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|