public static void avoidProcess(Boid[] boids) { int count = FirstCheck(boids); int index = 0; int[] map = new int[count]; while (count > 0 && index < BoidHelper.directions.Length) { Vector3 rayDirection = BoidHelper.directions[index]; var results = new NativeArray <RaycastHit>(count, Allocator.TempJob); var commands = new NativeArray <SpherecastCommand>(count, Allocator.TempJob); int cmdId = 0; for (int i = 0; i < boids.Length; i++) { if (boids[i].checkState == CheckState.Updated) { continue; } Vector3 dir = boids[i].cachedTransform.TransformDirection(rayDirection); map[cmdId] = i; commands[cmdId] = new SpherecastCommand( boids[i].position, boids[i].settings.boundsRadius, dir, boids[i].settings.collisionAvoidDst, boids[i].settings.obstacleMask ); cmdId++; } // Schedule the batch of raycasts JobHandle handle = SpherecastCommand.ScheduleBatch(commands, results, batchSize, default(JobHandle)); // Wait for the batch processing job to complete handle.Complete(); int currentCount = count; // Copy the result. If batchedHit.collider is null there was no hit for (int i = 0; i < currentCount; i++) { int mapId = map[i]; if (results[i].collider == null) { boids[mapId].checkState = CheckState.Updated; boids[mapId].accelerate = boids[mapId].cachedTransform.TransformDirection(rayDirection); count--; break; } } // Dispose the buffers results.Dispose(); commands.Dispose(); index++; } }
private JobHandle SphereRaycastAhead([ReadOnly] TransformAccessArray transformAccessArray, JobHandle dependency = default) { float radius = 0.5f; for (int i = 0; i < _avoidanceCommands.Length; i++) { _avoidanceCommands[i] = new SpherecastCommand(transformAccessArray[i].position, radius, transformAccessArray[i].forward, 100); } var handle = SpherecastCommand.ScheduleBatch(_avoidanceCommands, _avoidanceHits, 64, dependency); return(handle); }
private JobHandle SphereCastUnder([ReadOnly] TransformAccessArray transformAccessArray, JobHandle dependency = default) { float radius = 0.5f; for (int i = 0; i < _surfaceNormalsCommands.Length; i++) { _surfaceNormalsCommands[i] = new SpherecastCommand( transformAccessArray[i].position + transformAccessArray[i].up * settings.height, radius, -transformAccessArray[i].up, 100); } var handle = SpherecastCommand.ScheduleBatch(_surfaceNormalsCommands, _surfaceNormalsHits, 64, dependency); return(handle); }
private Vector3 ObstacleRaysJob() { Vector3[] rayDirections = BoidHelper.directions; int count = rayDirections.Length; // count = 1; // Perform a single raycast using RaycastCommand and wait for it to complete // Setup the command and result buffers var results = new NativeArray <RaycastHit>(count, Allocator.TempJob); // var commands = new NativeArray<RaycastCommand>(count, Allocator.TempJob); var commands = new NativeArray <SpherecastCommand>(count, Allocator.TempJob); // Set the data of the first command Vector3 origin = position; for (int i = 0; i < count; i++) { Vector3 dir = cachedTransform.TransformDirection(rayDirections[i]); Vector3 direction = dir; commands[i] = new SpherecastCommand(origin, settings.boundsRadius, direction, settings.collisionAvoidDst, settings.obstacleMask); } // Schedule the batch of raycasts JobHandle handle = SpherecastCommand.ScheduleBatch(commands, results, batchSize, default(JobHandle)); // Wait for the batch processing job to complete handle.Complete(); Vector3 result = forward; // Copy the result. If batchedHit.collider is null there was no hit for (int i = 0; i < count; i++) { if (results[i].collider == null) { result = cachedTransform.TransformDirection(rayDirections[i]); break; } } // Dispose the buffers results.Dispose(); commands.Dispose(); return(result); }
public void Execute(int index) { var rayHit = spherecastHits[index]; if (rayHit.point != default(Vector3)) { var previousCommand = previousCommands[index]; //little hack to bypass same collider hit in specific cases var point = rayHit.point; var distance = previousCommand.distance - (point - previousCommand.origin).magnitude; spherecastCommands[index] = new SpherecastCommand(point, previousCommand.radius, previousCommand.direction, distance, previousCommand.layerMask); } else { spherecastCommands[index] = default(SpherecastCommand); } }
public static int FirstCheck(Boid[] boids) { int count = boids.Length; var results = new NativeArray <RaycastHit>(count, Allocator.TempJob); var commands = new NativeArray <SpherecastCommand>(count, Allocator.TempJob); for (int i = 0; i < boids.Length; i++) { commands[i] = new SpherecastCommand( boids[i].position, boids[i].settings.boundsRadius, boids[i].forward, boids[i].settings.collisionAvoidDst, boids[i].settings.obstacleMask ); } JobHandle handle = SpherecastCommand.ScheduleBatch(commands, results, batchSize, default(JobHandle)); // Wait for the batch processing job to complete handle.Complete(); // Copy the result. If batchedHit.collider is null there was no hit for (int i = 0; i < boids.Length; i++) { if (results[i].collider == null) { boids[i].checkState = CheckState.Updated; boids[i].accelerate = Vector3.zero; count--; } else { boids[i].checkState = CheckState.NeedUpdate; } } // Dispose the buffers results.Dispose(); commands.Dispose(); return(count); }
public void Execute(int index) { var entity = Entities[StartIndex + index]; var position = entityTransaction.GetComponentData <Position>(entity); var rotation = entityTransaction.GetComponentData <Rotation>(entity); var sphere = entityTransaction.GetComponentData <SphereColliderComponentData>(entity); var collisionLayer = entityTransaction.GetSharedComponentData <CollisionLayerComponentData>(entity); SpherecastCommand spherecast = Spherecasts[StartIndex + index * 3]; var dir = ((position.Value + sphere.Center) - (float3)spherecast.origin); spherecast.direction = math.normalizesafe(dir); spherecast.distance = math.length(dir); spherecast.layerMask = collisionLayer.Mask1; Spherecasts[StartIndex + index * 3] = spherecast; spherecast.layerMask = collisionLayer.Mask2; Spherecasts[StartIndex + index * 3 + 1] = spherecast; spherecast.layerMask = collisionLayer.Mask3; Spherecasts[StartIndex + index * 3 + 2] = spherecast; }
void IEcsRunSystem.Run() { int count = _filter.GetEntitiesCount(); if (count != 0) { // New Arrays hits = new NativeArray <RaycastHit>(count, Allocator.TempJob); commands = new NativeArray <SpherecastCommand>(count, Allocator.TempJob); // Fill input Array foreach (var i in _filter) { commands[i] = NewComand(i); } // Schedule handle = SpherecastCommand.ScheduleBatch(commands, hits, 4); // Finalize FinalizeJob(); } }
public void SingleHitsTest() { var maxHits = 4; var rayStart = new Vector3(0f, 2f, 0f); var cubeCommand = new SpherecastCommand(cubeCollider.transform.position + rayStart, 1f, Vector3.down); var meshCubeCommand = new SpherecastCommand(meshCubeCollider.transform.position + rayStart, 1f, Vector3.down); var meshConvexCommand = new SpherecastCommand(meshConvexCollider.transform.position + rayStart, 1f, Vector3.down); var emptyCommand = new SpherecastCommand(new Vector3(30f, 0f, 0f) + rayStart, 1f, Vector3.down); var commandsArray = new SpherecastCommand[] { cubeCommand, meshCubeCommand, emptyCommand, meshConvexCommand }; commands = new NativeArray <SpherecastCommand>(commandsArray, Allocator.TempJob); commandHits = new NativeArray <RaycastHit>(commands.Length * maxHits, Allocator.TempJob); raycastAllCommand = new SpherecastAllCommand(commands, commandHits, maxHits); raycastAllCommand.Schedule(default(JobHandle)).Complete(); Assert.AreEqual(cubeCollider, commandHits[maxHits * 0].collider); Assert.AreEqual(meshCubeCollider, commandHits[maxHits * 1].collider); Assert.AreEqual(null, commandHits[maxHits * 2].collider); var physicsHits = new RaycastHit[maxHits]; for (int i = 0; i < commands.Length; i++) { var unityHitsCount = Physics.SphereCastNonAlloc(commands[i].origin, commands[i].radius, commands[i].direction, physicsHits); for (int j = 0; j < unityHitsCount; j++) { var physicsHit = physicsHits[j]; var commandHit = commandHits[i * maxHits + j]; RaycastHitEquality.AssertEqual(physicsHit, commandHit); } if (unityHitsCount < maxHits) { Assert.AreEqual(null, commandHits[i * maxHits + unityHitsCount].collider); } } }
public void FromInsideHitsTest() { var maxHits = 4; var direction = new Vector3(1f, 1f).normalized; var cubeCommand = new SpherecastCommand(cubeCollider.transform.position, 0.1f, direction); var meshCubeCommand = new SpherecastCommand(meshCubeCollider.transform.position, 0.1f, direction); var meshConvexCommand = new SpherecastCommand(meshConvexCollider.transform.position, 0.1f, direction); var commandsArray = new SpherecastCommand[] { cubeCommand, meshCubeCommand, meshConvexCommand }; commands = new NativeArray <SpherecastCommand>(commandsArray, Allocator.TempJob); commandHits = new NativeArray <RaycastHit>(commands.Length * maxHits, Allocator.TempJob); raycastAllCommand = new SpherecastAllCommand(commands, commandHits, maxHits); raycastAllCommand.Schedule(default(JobHandle)).Complete(); for (int i = 0; i < commands.Length; i++) { Assert.IsNull(commandHits[i * maxHits].collider, "SpherecastCommand behaviour changed, spherecasting from inside now returns collision"); } }
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { NativeArray <SphereColliderComponentData> sphereColliders = chunk.GetNativeArray(SphereColliderType); NativeArray <Position> positions = chunk.GetNativeArray(PositionType); NativeArray <Scale> scales = chunk.GetNativeArray(ScaleType); NativeArray <Entity> entities = chunk.GetNativeArray(EntityType); float3 zero = float3.zero; for (int i = 0, length = sphereColliders.Length; i < length; ++i) { SphereColliderComponentData sphere = sphereColliders[i]; Position position = positions[i]; Scale scale = scales[i]; SpherecastCommand sphereCast = new SpherecastCommand(position.Value + sphere.Center, sphere.Radius * math.max(scale.Value.z, math.max(scale.Value.y, scale.Value.x)), zero, 0, 0); SphereCasts.TryAdd(entities[i], sphereCast); } }
public void NeedForMinStepTest() { var maxHits = 4; var rayStart = new Vector3(0f, 4f, 0f); var meshConvexCommand = new SpherecastCommand(meshConvexCollider.transform.position + rayStart, 0.1f, Vector3.down); var commandsArray = new SpherecastCommand[] { meshConvexCommand }; commands = new NativeArray <SpherecastCommand>(commandsArray, Allocator.TempJob); commandHits = new NativeArray <RaycastHit>(commands.Length * maxHits, Allocator.TempJob); //setting minStep to 0f raycastAllCommand = new SpherecastAllCommand(commands, commandHits, maxHits); raycastAllCommand.Schedule(default(JobHandle)).Complete(); Assert.AreEqual(meshConvexCollider, commandHits[0].collider); var physicsHits = new RaycastHit[maxHits]; for (int i = 0; i < commands.Length; i++) { var unityHitsCount = Physics.SphereCastNonAlloc(commands[i].origin, commands[i].radius, commands[i].direction, physicsHits); for (int j = 0; j < unityHitsCount; j++) { var physicsHit = physicsHits[j]; var commandHit = commandHits[i * maxHits + j]; RaycastHitEquality.AssertEqual(physicsHit, commandHit); } if (unityHitsCount < maxHits) { Assert.IsNull(commandHits[i * maxHits + unityHitsCount].collider, "RaycastHit in corner point behaviour changed, minStep may be required"); } } }
protected override JobHandle OnUpdate(JobHandle inputDeps) { PreCollisionSystem preCollisionSystem = World.Active.GetExistingManager <PreCollisionSystem>(); if (preCollisionSystem != null) { var entities = preCollisionSystem.Entities; var boxcasts = preCollisionSystem.Boxcasts; var spherecasts = preCollisionSystem.Spherecasts; var capsulecasts = preCollisionSystem.Capsulecasts; EntityManager.CompleteAllJobs(); if (boxcasts.IsCreated && boxcasts.Length != 0) { var hitBoxCollider = new NativeArray <RaycastHit>(boxcasts.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var transaction = EntityManager.BeginExclusiveEntityTransaction(); var job = new UpdateBoxDistDir { Boxcasts = boxcasts, Entities = entities, entityTransaction = transaction }; var handle = job.Schedule(boxcasts.Length / 3, 32, inputDeps); EntityManager.ExclusiveEntityTransactionDependency = handle; Utils.Utils.ScheduleBatchedJobAndComplete(handle); EntityManager.EndExclusiveEntityTransaction(); handle = BoxcastCommand.ScheduleBatch(boxcasts, hitBoxCollider, 1, default); Utils.Utils.ScheduleBatchedJobAndComplete(handle); InvokeCollisionResponse(entities, hitBoxCollider, 0, boxcasts.Length); hitBoxCollider.Dispose(); } if (spherecasts.IsCreated && spherecasts.Length != 0) { var hitSphereCollider = new NativeArray <RaycastHit>(spherecasts.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var transaction = EntityManager.BeginExclusiveEntityTransaction(); var job = new UpdateSphereDistDir { Spherecasts = spherecasts, Entities = entities, entityTransaction = transaction, StartIndex = boxcasts.Length / 3 }; var handle = job.Schedule(spherecasts.Length / 3, 32, inputDeps); EntityManager.ExclusiveEntityTransactionDependency = handle; Utils.Utils.ScheduleBatchedJobAndComplete(handle); EntityManager.EndExclusiveEntityTransaction(); handle = SpherecastCommand.ScheduleBatch(spherecasts, hitSphereCollider, 1, default); Utils.Utils.ScheduleBatchedJobAndComplete(handle); InvokeCollisionResponse(entities, hitSphereCollider, boxcasts.Length, spherecasts.Length); hitSphereCollider.Dispose(); } if (capsulecasts.IsCreated && capsulecasts.Length != 0) { var hitCapsuleCollider = new NativeArray <RaycastHit>(capsulecasts.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var transaction = EntityManager.BeginExclusiveEntityTransaction(); var job = new UpdateCapsuleDistDir { Capsulecasts = capsulecasts, Entities = entities, entityTransaction = transaction, StartIndex = (boxcasts.Length + spherecasts.Length) / 3 }; var handle = job.Schedule(capsulecasts.Length / 3, 32, inputDeps); EntityManager.ExclusiveEntityTransactionDependency = handle; Utils.Utils.ScheduleBatchedJobAndComplete(handle); EntityManager.EndExclusiveEntityTransaction(); handle = CapsulecastCommand.ScheduleBatch(capsulecasts, hitCapsuleCollider, 1, default); Utils.Utils.ScheduleBatchedJobAndComplete(handle); InvokeCollisionResponse(entities, hitCapsuleCollider, spherecasts.Length, capsulecasts.Length); hitCapsuleCollider.Dispose(); } } return(inputDeps); }