Compute Shader for Calculations? (like, find closet thing ?)

Hi, most people talking about compute shaders and say it can calculate more things @ once using GPU.

My problem is can I use it for find closet enemy to player, something like that?

foreach(Transform potentialTarget in enemies)
{
    Vector3 directionToTarget = potentialTarget.position - currentPosition;
    float dSqrToTarget = directionToTarget.sqrMagnitude;
    if(dSqrToTarget < closestDistanceSqr)
    {
        closestDistanceSqr = dSqrToTarget;
        bestTarget = potentialTarget;
    }
}

can I use compute shader to do this (above), If I can do this. can you give example how to do it.

2 Answers

2

You don’t need a GPU to make this fast, necessarily. While GPU allows for massively parallel computations it comes with it’s costs like: some additional complexity, data transfer/synchronisation considerations, DX11 required (or mobile equivalent, whatever that is). IJobParallelForTransform Burst-compiled job deals with this decently well too - good enough for your case maybe.

Test case: 1000 Transforms costs about 0.07 ms (aux thread)

190701-gif-02012022-19-08-06-2

FindClosestTransform.cs

using UnityEngine;
using UnityEngine.Jobs;

using Unity.Entities;
using Unity.Mathematics;
using Unity.Collections;
using Unity.Jobs;

using Random = UnityEngine.Random;
using BurstCompile = Unity.Burst.BurstCompileAttribute;

public class FindClosestTransform : MonoBehaviour
{

    [SerializeField] Transform[] _transforms = new Transform[0];
    TransformAccessArray _transformsAccess = default(TransformAccessArray);
    public JobHandle Dependency = default(JobHandle);
    NativeArray<float> _distances;
    NativeArray<int> _index;

    void Start ()
    {
        if( _transforms.Length==0 )
        {
            var parent = new GameObject( "test transforms" ).transform;
            _transforms = new Transform[ 1000 ];
            for( int i=_transforms.Length-1 ; i!=-1 ; i-- )
            {
                _transforms *= new GameObject().transform;
                _transforms*.position = Random.insideUnitSphere;
                _transforms*.SetParent( parent , worldPositionStays:true );
            }
        }
        _transformsAccess = new TransformAccessArray( _transforms );
        _distances = new NativeArray<float>( _transforms.Length , Allocator.Persistent );
        _index = new NativeArray<int>( 1 , Allocator.Persistent );
    }

    void OnDrawGizmos ()
    {
        foreach( var t in _transforms )
            if( t!=null )
                Gizmos.DrawIcon( t.position , "animationkeyframe" );
    }

    void OnDestroy ()
    {
        Dependency.Complete();
        if( _transformsAccess.isCreated ) _transformsAccess.Dispose();
        if( _distances.IsCreated ) _distances.Dispose();
        if( _index.IsCreated ) _index.Dispose();
    }

    void Update ()
    {
        Dependency.Complete();
        Debug.DrawLine( transform.position , _transforms[_index[0]].position );

        var job1 = new CalculateDistances{
            Position	= (float3) transform.position ,
            Distances	= _distances
        };
        Dependency = job1.Schedule( _transformsAccess );
        var job2 = new FindIndexWithLowestValue{
            Values	= _distances ,
            Index	= _index
        };
        Dependency = job2.Schedule( Dependency );
    }

    [BurstCompile]
    public struct CalculateDistances : IJobParallelForTransform
    {
        public float3 Position;
        [WriteOnly] public NativeArray<float> Distances;
        void IJobParallelForTransform.Execute ( int index , TransformAccess transform )
            => Distances[index] = math.distancesq( Position , transform.position );
    }

    [BurstCompile]
    public struct FindIndexWithLowestValue : IJob
    {
        [ReadOnly] public NativeArray<float> Values;
        [WriteOnly] public NativeArray<int> Index;
        void IJob.Execute ()
        {
            int lowestValueIndex = 0;
            float lowest = float.MaxValue;
            for( int i=0 ; i<Values.Length ; i++ )
            if( Values*<lowest )
            {
                lowest = Values*;
                lowestValueIndex = i;
            }
            Index[0] = lowestValueIndex;
        }
    }
}

Thans Lot @andrew-lukasik

Thans Lot @andrew-lukasik