- Home /
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.
Answer by andrew-lukasik · Jan 02 at 06:26 PM
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)
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[i] = new GameObject().transform;
_transforms[i].position = Random.insideUnitSphere;
_transforms[i].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[i]<lowest )
{
lowest = Values[i];
lowestValueIndex = i;
}
Index[0] = lowestValueIndex;
}
}
}