currently RaycastCommand.ScheduleBatch synchronously reads the addresses and lenghts of the passed NativeArrays, which means I can’t generate the raycast commands in a Job without synching with the main thread.
As ScheduleBatch uses the Job system I guess it should be doable to make it support ‘NativeArrays’ received from NativeList.AsDeferredJobArray() too?
You could schedule a job that creates the RaycastCommands, then pass the commands into ScheduleBatch making sure to pass in the previous job’s handle as a dependency. This way you don’t break the dependency chain. Here is some of my project’s code that does this (Ignore the NativeList and substitute in a normal IJobParallelFor):
public static JobHandle CreateParallelRaycasts(
JobHandle inputDeps,
NativeArray<LineOfSightRequest> requests,
NativeList<int> requestsMissesIndices,
int length,
LayerMask mask,
out NativeArray<RaycastHit> results,
out NativeArray<RaycastCommand> commands
)
{
var commandsOut = new NativeArray<RaycastCommand>(length, Allocator.TempJob);
var resultsOut = new NativeArray<RaycastHit>(length, Allocator.TempJob);
var createRaycasts = new CreateRaycastsJob
{
losRequests = requests,
commands = commandsOut,
mask = mask
};
inputDeps = createRaycasts.ScheduleFilter(requestsMissesIndices, INNER_LOOP_BATCH_COUNT, inputDeps);
inputDeps = RaycastCommand.ScheduleBatch(commandsOut, resultsOut, 1, inputDeps);
results = resultsOut;
commands = commandsOut;
return inputDeps;
}
This works if you know how many rays you are going to cast but not if the number of rays changes based on other jobs and you have your info in NativeLists with variable length.
In my current case the raycast count is dependent on a ComponentGroup using a change filter. Getting the count of this ComponentGroup requires the main thread to wait for any dependent writes on the filtered component which I would like to avoid.
Alternatively to AsDeferredJobArray a kind of ScheduleBatchIndirect which receives the raycast count using a native container would work… although I would prefer AsDeferredJobArray as then I wouldn’t need to preallocate a large enough buffer for all cases… maybe querying extra raycasts with maxHits=0 is nearly free …?
Setting an entry to new RaycastCommand() will make that entry be ignored. My experience has been that a buffer big enough to handle more then you can do in a single frame is usually not enough memory to be an issue. If you haven’t noticed raycast commands will be force completed by Unity now before fixed update if they are still running, so there is a practical limit here anyways.
No, it’s just never hitting anything. Getting ‘ignored’ is still slower than not being there and as they are processed in ParallelForBatches unused raycasts have an additional overhead.
Quicktest with 100k raycasts: ‘empty’ commands (distance=0, maxHits=0, mask=0) cost around 8% of a ‘valid’ raycast with infinite ray length. (World with 10k static cube colliders)
That is likely a bug then. I don’t do enough raycasts where they are particularly expensive anyways, but Unity specifically said setting it to a new entry will make it be ignored.