Search Unity

Question Physic issue with burst and Jobs

Discussion in 'Physics' 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 ?