DOTS计算Voronoi图形生成,根据点自动划分区域生成多边形
如图,生成Voronoi图形,代码如下。
using UnityEngine; using Unity.Mathematics; using Unity.Jobs; using Unity.Collections; using Unity.Profiling; [ExecuteInEditMode] public class VoronoiTextureBurstJobComponent : MonoBehaviour { [SerializeField][Min(1)] uint _seed = 769; [SerializeField][Range(2,512)] int _width = 300, _height = 300; [SerializeField][Range(1,64)] int _numRandomPoints = 3; Texture2D _texture; NativeList<ushort2> _points; uint lastSeedUsed = 0; void OnValidate () { bool inputChanged = false; if( !_points.IsCreated ) { _points = new NativeList<ushort2>( Allocator.Persistent ); inputChanged = true; } if( _points.Length!=_numRandomPoints ) { _points.Length = _numRandomPoints; inputChanged = true; } if( _texture==null || _texture.width!=_width || _texture.height!=_height ) { if( _texture==null ) DestroyItWillYou( _texture ); _texture = new Texture2D( _width , _height , TextureFormat.RGBA32 , mipCount:0 , linear:true ); inputChanged = true; } if( inputChanged || _seed!=lastSeedUsed ) { lastSeedUsed = _seed; var watch = System.Diagnostics.Stopwatch.StartNew(); var dep = new FillRandomPointsJob{ TextureWidth = _width , TextureHeight = _height , Seed = _seed , Points = _points , }.Schedule(); NativeArray<RGBA32> textureData = _texture.GetRawTextureData<RGBA32>(); new GenerateVoronoiDiagramJob{ Points = _points , TextureWidth = _width , TextureHeight = _height , TextureOutput = textureData , }.Schedule( textureData.Length , _width , dep ).Complete(); _texture.Apply(); Debug.Log( $"jobs took {watch.ElapsedMilliseconds} [ms] to complete"); } } void OnEnable () => OnValidate(); void OnDisable () { if( _texture!=null ) DestroyItWillYou(_texture); if( _points.IsCreated ) _points.Dispose(); } void OnGUI () => GUI.DrawTexture( new Rect(0,0,_width,_height) , _texture ); void DestroyItWillYou ( Object obj ) { if( Application.isPlaying ) Destroy( obj ); else DestroyImmediate( obj ); } [Unity.Burst.BurstCompile] struct FillRandomPointsJob : IJob { public int TextureWidth, TextureHeight; public uint Seed; [WriteOnly] public NativeArray<ushort2> Points; void IJob.Execute () { var rnd = new Unity.Mathematics.Random( Seed ); int len = Points.Length; for( int i=0 ; i<len ; i++ ) Points[i] = new ushort2{ x=(ushort)rnd.NextInt(TextureWidth) , y=(ushort)rnd.NextInt(TextureHeight) }; } } [Unity.Burst.BurstCompile] struct GenerateVoronoiDiagramJob : IJobParallelFor { [ReadOnly] public NativeArray<ushort2> Points; public int TextureWidth, TextureHeight; [WriteOnly] public NativeArray<RGBA32> TextureOutput; void IJobParallelFor.Execute ( int jobIndex ) { float2 pixelPos = new int2{ x=jobIndex%TextureWidth , y=jobIndex/TextureWidth }; float pointDist = float.MaxValue; int pointIndex = -1; for( int i=Points.Length-1 ; i!=-1 ; i-- ) { float2 pointPos = new float2{ x=Points[i].x , y=Points[i].y }; float dist = math.lengthsq( pointPos - pixelPos );// dist sq // float2 vec = math.abs( pointPos - pixelPos ); // float dist = vec.x + vec.y;// manhattan distance if( dist<pointDist ) { pointDist = dist; pointIndex = i; } if( dist<math.max(math.min(TextureWidth*0.01f,TextureHeight*0.01f),1) ) { TextureOutput[jobIndex] = new RGBA32{ r=0 , g=0 , b=0 , a=255 }; return; } } RGBA32 colorFromCoord; { ushort2 pointCoord = Points[pointIndex]; float2 f = new float2{ x=pointCoord.x , y=pointCoord.y } / ( new float2{ x=TextureWidth , y=TextureHeight } - new float2{ x=1 , y=1 } ); byte r = (byte)( 255*f.x ); byte g = (byte)( 255*f.y ); byte b = (byte)( (r+g)%255 ); colorFromCoord = new RGBA32{ r=r , g=g , b=b , a=255 }; } TextureOutput[jobIndex] = colorFromCoord; } } struct ushort2 { public ushort x, y; } struct RGBA32 { public byte r, g, b, a; } }