Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Burst SphereCast issue

Discussion in 'Burst' started by AnKOu, Jan 12, 2022.

  1. AnKOu

    AnKOu

    Joined:
    Aug 30, 2013
    Posts:
    123
    Hello I'm having a hard time trying to make some SphereCast to work.
    I translated a code which was working in c# into job system but it doesn't work anymore (the physic part only).

    I have a job which prepare all the SpherecastCommand.

    Code (CSharp):
    1.  
    2.         /// <summary>
    3.         /// initial raycast to know if the boid is going straight to an obstacle
    4.         /// </summary>
    5.         [BurstCompile]
    6.         private struct PrepareRaycastJob : IJobParallelFor
    7.         {
    8.             [UCReadOnly]
    9.             public NativeArray<BoidData> _BoidDataArray;
    10.  
    11.             [WriteOnly]
    12.             public NativeArray<SpherecastCommand> _FindObstacleRaycastCommands;
    13.  
    14.             [UCReadOnly] public int _LayerMask;
    15.             [UCReadOnly] public float _SphereRadius;
    16.             [UCReadOnly] public float _MaxRayDistance;
    17.  
    18.             public void Execute(int index)
    19.             {
    20.                 BoidData lBoidData = _BoidDataArray[index];
    21.                 _FindObstacleRaycastCommands[index] = new SpherecastCommand()
    22.                 {
    23.                     direction = math.normalize(lBoidData.Velocity),
    24.                     origin = lBoidData.Position,
    25.                     radius = _SphereRadius,
    26.                     layerMask = _LayerMask,
    27.                     distance = _MaxRayDistance                  
    28.                 };
    29.             }
    30.         }
    I assume this can't be an issue with the parameter as the same where used in the classic c# version and it worked.

    I then have a job which if the result of the raycast is positive will prepare a batch of sphereraycast :
    Code (CSharp):
    1.  
    2.  
    3.         /// <summary>
    4.         /// Prepare the raycast launch when a boid comes too close from a surface.
    5.         /// </summary>
    6.         [BurstCompile]
    7.         private struct PrepareRaycastDodgeObstacleJob : IJobParallelFor
    8.         {
    9.             [UCReadOnly] public NativeArray<BoidData> boidDataArray;
    10.             [UCReadOnly] public NativeArray<RaycastHit> raycastHits;
    11.             [UCReadOnly] public NativeArray<float3> RayDirection;
    12.  
    13.             [WriteOnly]
    14.             [NativeDisableParallelForRestriction]
    15.             public NativeArray<SpherecastCommand> raycastCommands;
    16.  
    17.             [UCReadOnly] public int _LayerMask;
    18.             [UCReadOnly] public float _SphereRadius;
    19.             [UCReadOnly] public float _MaxRayDistance;
    20.  
    21.             public void Execute(int index)
    22.             {
    23.                 RaycastHit lHit = raycastHits[index];
    24.                 if (lHit.colliderInstanceID > 0)
    25.                 {
    26.                     for (int i = 0; i < RayDirection.Length; i++)
    27.                     {
    28.                         raycastCommands[index + i] = new SpherecastCommand()
    29.                         {
    30.                             direction = RayDirection[i],
    31.                             origin = boidDataArray[index].Position,
    32.                             radius = _SphereRadius,
    33.                             layerMask = _LayerMask,
    34.                             distance = _MaxRayDistance
    35.                         };
    36.                     }
    37.                 }
    38.             }
    39.  
    40.         }
    And then a job that use all this data :
    Code (CSharp):
    1.  
    2.  
    3.         /// <summary>
    4.         /// Update acceleration if need to dodge obstacle
    5.         /// </summary>
    6.         [BurstCompile]
    7.         private struct FinalizePositionJob : IJobParallelFor
    8.         {
    9.             [UCReadOnly] public NativeArray<SpherecastCommand> raycastCommand;
    10.             [UCReadOnly] public NativeArray<RaycastHit> mustDodgeRaycastHit;
    11.             [UCReadOnly] public NativeArray<RaycastHit> raycastHits;
    12.             [UCReadOnly] public NativeArray<float3> _Acceleration;
    13.             [UCReadOnly] public int raycastPerBoid;
    14.             [UCReadOnly] public float maxSpeed;
    15.             [UCReadOnly] public float maxSteerForce;
    16.             [UCReadOnly] public float deltaTime;
    17.             [UCReadOnly] public float minSpeed;
    18.  
    19.             //read write
    20.             public NativeArray<BoidData> _BoidData;
    21.  
    22.             public void Execute(int index)
    23.             {
    24.                 BoidData lBoid = _BoidData[index];
    25.                 float3 acceleration = _Acceleration[index];
    26.  
    27.                 //add acceleration to avoid obstacle if needed.
    28.                 if (mustDodgeRaycastHit[index].colliderInstanceID > 0)
    29.                 {
    30.                     float3 dodgeObstacleDir = new float3(0, 0, 0);
    31.                     int lDirectionCount = 0;
    32.                     for (int i = 0; i < raycastPerBoid; i++)
    33.                     {
    34.                         float reverse = 1f;
    35.                         if (raycastHits[i + index].colliderInstanceID > 0) reverse = -1; ;
    36.                         dodgeObstacleDir += (float3)(raycastCommand[i + index].direction) * reverse;
    37.                         lDirectionCount++;
    38.                     }
    39.  
    40.                     acceleration += SteerTowards(dodgeObstacleDir, lBoid.Velocity, maxSpeed, maxSteerForce);
    41.  
    42.                     //test purpose
    43.                     lBoid.Velocity = float3.zero;
    44.                     _BoidData[index] = lBoid;
    45.                     return;
    46.                 }
    47.  
    48.                 lBoid.Velocity += acceleration * deltaTime;
    49.                 float lSpeed = math.length(lBoid.Velocity);
    50.                 float3 dir = lBoid.Velocity / lSpeed;
    51.                 lSpeed = math.clamp(lSpeed, minSpeed, maxSpeed);
    52.                 lBoid.Velocity = dir * lSpeed;
    53.                 lBoid.Position += lBoid.Velocity * deltaTime;
    54.                
    55.                 _BoidData[index] = lBoid;
    56.             }
    57.         }
    I put a return in case the initial raycast hit something to stop the transform but the transform keeps moving through colliders.

    I use handle dependencies to be sure that datas are complete at the moment we use them..

    Code (CSharp):
    1.  
    2.         private JobHandle ComputeObstacleAvoidanceData()
    3.         {
    4.             //first find obstacle raycast
    5.             _FindObstacleRaycastCommands = new NativeArray<SpherecastCommand>(_Boids.Length, Allocator.TempJob);
    6.             PrepareRaycastJob lPrepareRaycastJob = new PrepareRaycastJob()
    7.             {
    8.                 _BoidDataArray = _BoidDataList,
    9.                 _FindObstacleRaycastCommands = _FindObstacleRaycastCommands,
    10.                 _LayerMask = _Settings._ObstacleMask,
    11.                 _MaxRayDistance = _Settings._CollisionAvoidDst,
    12.                 _SphereRadius = _Settings._SphereCastRadius
    13.             };
    14.             JobHandle setupFindObstacleRaycastJobHandle = lPrepareRaycastJob.Schedule(_Boids.Length, 32);
    15.             _FindObstacleHits = new NativeArray<RaycastHit>(_Boids.Length, Allocator.TempJob);
    16.             JobHandle findObstacleJobHandle = SpherecastCommand.ScheduleBatch(_FindObstacleRaycastCommands, _FindObstacleHits, 32, setupFindObstacleRaycastJobHandle);
    17.             _FindObstacleRaycastCommands.Dispose(findObstacleJobHandle);
    18.  
    19.             //find direction to avoid collision
    20.             _DodgeObstacleRaycastCommands = new NativeArray<SpherecastCommand>(_Boids.Length * _RayDirections.Length, Allocator.TempJob);
    21.             PrepareRaycastDodgeObstacleJob lPrepareDodgeObstacleJob = new PrepareRaycastDodgeObstacleJob()
    22.             {
    23.                 boidDataArray = _BoidDataList,
    24.                 _LayerMask = _Settings._ObstacleMask,
    25.                 _MaxRayDistance = _Settings._CollisionAvoidDst,
    26.                 _SphereRadius = _Settings._SphereCastRadius,
    27.                 RayDirection = _RayDirections,
    28.                 raycastHits = _FindObstacleHits,
    29.                 raycastCommands = _DodgeObstacleRaycastCommands
    30.             };
    31.             JobHandle setupDodgeObstacleDependency = lPrepareDodgeObstacleJob.Schedule(_Boids.Length, 32, findObstacleJobHandle);
    32.             JobHandle dependency = JobHandle.CombineDependencies(setupDodgeObstacleDependency, findObstacleJobHandle);
    33.  
    34.             _DodgeObstacleRaycastHits = new NativeArray<RaycastHit>(_Boids.Length * _RayDirections.Length, Allocator.TempJob);
    35.             JobHandle dodgeObstacleDirection = SpherecastCommand.ScheduleBatch(_DodgeObstacleRaycastCommands, _DodgeObstacleRaycastHits, 32, dependency);
    36.  
    37.  
    38.             return dodgeObstacleDirection;
    39.         }

    Code (CSharp):
    1.  
    2.  
    3.         private void FinalizePosition(JobHandle pDependency)
    4.         {
    5.  
    6.             FinalizePositionJob updateAccelerationForDodgeObstacle = new FinalizePositionJob()
    7.             {
    8.                 mustDodgeRaycastHit = _FindObstacleHits,
    9.                 raycastHits = _DodgeObstacleRaycastHits,
    10.                 _Acceleration = _Acceleration,
    11.                 raycastPerBoid = _Settings._RayDirectionsCount,
    12.                 raycastCommand = _DodgeObstacleRaycastCommands,
    13.                 deltaTime = TimeManager.DeltaTime,
    14.                 maxSpeed = _Settings._MaxSpeed,
    15.                 maxSteerForce = _Settings._MaxSteerForce,
    16.                 minSpeed = _Settings._MinSpeed,
    17.                 _BoidData = _BoidDataList
    18.             };
    19.  
    20.             JobHandle lPositionFinalized = updateAccelerationForDodgeObstacle.Schedule(_Boids.Length, 32, pDependency);
    21.  
    22.             UpdateBoidSpatialData updateSpatialData = new UpdateBoidSpatialData()
    23.             {
    24.                 _BoidDatas = _BoidDataList,
    25.                 _CellSize = _Settings._CellSize,
    26.                 _SurroudingBoidData = _SpatialPartitioning
    27.             };
    28.  
    29.             _FindObstacleHits.Dispose(lPositionFinalized);
    30.             _DodgeObstacleRaycastCommands.Dispose(lPositionFinalized);
    31.             _DodgeObstacleRaycastHits.Dispose(lPositionFinalized);
    32.             _Acceleration.Dispose(lPositionFinalized);
    33.  
    34.             JobHandle lOnFinishedUpdateSpatialData = updateSpatialData.Schedule(lPositionFinalized);
    35.  
    36.             UpdateTransformJob updateTransform = new UpdateTransformJob()
    37.             {
    38.                 _BoidDatas = _BoidDataList
    39.             };
    40.             JobHandle onFinishedUpdateTransform = updateTransform.Schedule(_AccessArray, lPositionFinalized);
    41.  
    42.             //assign main handle to let him be called complete next frame
    43.             _MainHandle = JobHandle.CombineDependencies(onFinishedUpdateTransform, lOnFinishedUpdateSpatialData);
    44.         }
    45.  

    Is there something specific to do in order to use those SphereCastCommand with job and burst ?