Exemplo n.º 1
0
        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();
            }
        }
Exemplo n.º 2
0
        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);
        }