static void DoApplyVirtualOffsets(Vector3[] probePositions, out Vector3[] probeOffsets, VirtualOffsetSettings voSettings) { // Limit memory usage based on ray cast / hit structures (of which there are lots per position) int maxPositionsPerBatch; { var rayCastBytesPerPosition = UnsafeUtility.SizeOf <RaycastCommand>() * kRayDirectionsPerPosition; var rayHitBytesPerPosition = UnsafeUtility.SizeOf <RaycastHit>() * kRayDirectionsPerPosition * voSettings.maxHitsPerRay; var rayDataBytesPerPosition = rayCastBytesPerPosition + rayHitBytesPerPosition; maxPositionsPerBatch = (kMaxMemoryUsage / 2) / rayDataBytesPerPosition; #if VERBOSE Debug.Log($"Running virtual offset over {(probePositions.Length + maxPositionsPerBatch - 1)/maxPositionsPerBatch} batches."); #endif } // This data is shared across all jobs var positions = new NativeArray <Vector3>(probePositions, Allocator.TempJob); var offsets = new NativeArray <Vector3>(probePositions.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var searchDistanceForPosition = new NativeArray <float>(positions.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); var positionHasColliders = new NativeArray <bool>(positions.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); // Allocate ray cast/hit data var raycastCommands = new[] { new NativeArray <RaycastCommand>(maxPositionsPerBatch * kRayDirectionsPerPosition, Allocator.TempJob, NativeArrayOptions.UninitializedMemory), new NativeArray <RaycastCommand>(maxPositionsPerBatch * kRayDirectionsPerPosition, Allocator.TempJob, NativeArrayOptions.UninitializedMemory) }; { // We need to set a known per-ray maxHits up-front since raycast command schedule reads this at schedule time. This is a bit annoying but it's a // price we'll have to pay right now to be able to create commands from a job. QueryParameters queryParams = new QueryParameters(); queryParams.hitBackfaces = true; queryParams.layerMask = 0; var defaultRaycastCommand = new RaycastCommand(Vector3.zero, Vector3.zero, queryParams, 0f); for (var i = 0; i < maxPositionsPerBatch * kRayDirectionsPerPosition; ++i) { raycastCommands[0][i] = raycastCommands[1][i] = defaultRaycastCommand; } } var raycastHits = new[] { new NativeArray <RaycastHit>(maxPositionsPerBatch * kRayDirectionsPerPosition * voSettings.maxHitsPerRay, Allocator.TempJob, NativeArrayOptions.UninitializedMemory), new NativeArray <RaycastHit>(maxPositionsPerBatch * kRayDirectionsPerPosition * voSettings.maxHitsPerRay, Allocator.TempJob, NativeArrayOptions.UninitializedMemory) }; // Create job data var createRayCastCommandsJob = new CreateRayCastCommandsJob { voSettings = voSettings, positions = positions, positionHasColliders = positionHasColliders, searchDistanceForPosition = searchDistanceForPosition }; var pushOutGeometryJob = new PushOutGeometryJob { voSettings = voSettings, positions = positions, offsets = offsets, positionHasColliders = positionHasColliders, }; var jobHandles = new JobHandle[2]; try { #if VERBOSE var positionsWithColliders = 0; #endif for (int globalPosIdx = 0, nextBatchIdx = -1; globalPosIdx < positions.Length; globalPosIdx += maxPositionsPerBatch) { // Run a quick overlap check for each search box before setting up rays for the position var batchPosStart = globalPosIdx; var batchPosEnd = Mathf.Min(positions.Length, batchPosStart + maxPositionsPerBatch); for (var batchPosIdx = batchPosStart; batchPosIdx < batchPosEnd; ++batchPosIdx) { m_BakingBatch.uniqueBrickSubdiv.TryGetValue(positions[batchPosIdx], out var subdivLevel); var brickSize = ProbeReferenceVolume.CellSize(subdivLevel); var searchDistance = (brickSize * m_BakingProfile.minBrickSize) / ProbeBrickPool.kBrickCellCount; var scaleForSearchDist = voSettings.searchMultiplier; var distanceSearch = scaleForSearchDist * searchDistance; var positionHasCollider = Physics.CheckBox(positions[batchPosIdx], new Vector3(distanceSearch, distanceSearch, distanceSearch), Quaternion.identity, voSettings.collisionMask); #if VERBOSE if (positionHasCollider) { ++positionsWithColliders; } #endif searchDistanceForPosition[batchPosIdx] = distanceSearch; positionHasColliders[batchPosIdx] = positionHasCollider; } // Swap buffers and sync any already running job at that slot nextBatchIdx = (nextBatchIdx + 1) % 2; jobHandles[nextBatchIdx].Complete(); // Assign ranges and ray/hit arrays createRayCastCommandsJob.startIdx = batchPosStart; createRayCastCommandsJob.endIdx = batchPosEnd; createRayCastCommandsJob.raycastCommands = raycastCommands[nextBatchIdx]; pushOutGeometryJob.startIdx = batchPosStart; pushOutGeometryJob.endIdx = batchPosEnd; pushOutGeometryJob.raycastCommands = raycastCommands[nextBatchIdx]; pushOutGeometryJob.raycastHits = raycastHits[nextBatchIdx]; #if VERBOSE Debug.Log($"Dispatching batch {batchPosStart/maxPositionsPerBatch} {batchPosStart} - {batchPosEnd} using index {nextBatchIdx} (accumulated colliders {positionsWithColliders}"); #endif #if USE_JOBS // Kick off jobs immediately var createRayCastCommandsJobHandle = createRayCastCommandsJob.Schedule(); var raycastCommandsJobHandle = RaycastCommand.ScheduleBatch(raycastCommands[nextBatchIdx], raycastHits[nextBatchIdx], kMinCommandsPerJob, voSettings.maxHitsPerRay, createRayCastCommandsJobHandle); jobHandles[nextBatchIdx] = pushOutGeometryJob.Schedule(raycastCommandsJobHandle); JobHandle.ScheduleBatchedJobs(); #else // Run jobs in-place for easier debugging createRayCastCommandsJob.Run(); RaycastCommand.ScheduleBatch(raycastCommands[nextBatchIdx], raycastHits[nextBatchIdx], voSettings.maxHitsPerRay, kMinCommandsPerJob).Complete(); pushOutGeometryJob.Run(); #endif } // Sync any in-flight jobs (order doesn't matter) JobHandle.CompleteAll(ref jobHandles[0], ref jobHandles[1]); // Copy out result data positions.CopyTo(probePositions); probeOffsets = offsets.ToArray(); #if VERBOSE Debug.Log($"Earlied out {positions.Length - positionsWithColliders}/{positions.Length} probe positions from virtual offset."); Debug.Log($"Working memory used: {(raycastCommands[0].Length * UnsafeUtility.SizeOf<RaycastCommand>() * 2 + raycastHits[0].Length * UnsafeUtility.SizeOf<RaycastHit>() * 2) / 1024 / 1024} MB"); #endif } catch (System.Exception e) { Debug.LogException(e); JobHandle.CompleteAll(ref jobHandles[0], ref jobHandles[1]); probeOffsets = null; } finally { positions.Dispose(); offsets.Dispose(); searchDistanceForPosition.Dispose(); positionHasColliders.Dispose(); raycastCommands[0].Dispose(); raycastCommands[1].Dispose(); raycastHits[0].Dispose(); raycastHits[1].Dispose(); } }
internal void SetBakeSettingsForScene(Scene scene, ProbeDilationSettings dilationSettings, VirtualOffsetSettings virtualOffsetSettings) { if (sceneBakingSettings == null) { sceneBakingSettings = new Dictionary <string, ProbeVolumeBakingProcessSettings>(); } var sceneGUID = GetSceneGUID(scene); sceneBakingSettings[sceneGUID] = new ProbeVolumeBakingProcessSettings(dilationSettings, virtualOffsetSettings); }