예제 #1
0
        private void QueuePropagationUpdates(LightPropagationJob propJob)
        {
            var chunkId = propJob.data.chunkId.ToBasic();

            for (Direction dir = 0; (int)dir < DirectionExtensions.numDirections; dir++)
            {
                BorderUpdateRequest borderUpdate = new BorderUpdateRequest();
                var UpdateChunkId = chunkId + DirectionExtensions.Vectors[(int)dir];
                borderUpdate.borderDirection = DirectionExtensions.Opposite[(int)dir];
                borderUpdate.sunlight        = propJob.sunlightNeighbourUpdates[dir].ToArray();
                borderUpdate.dynamic         = propJob.dynamicNeighbourUpdates[dir].ToArray();

                if (borderUpdate.dynamic.Length > 0 || borderUpdate.sunlight.Length > 0)
                {
                    if (pendingLightUpdatesByChunk.TryGetValue(UpdateChunkId, out var chunkUpdateRequest))
                    {
                        chunkUpdateRequest.borderUpdateRequests.Add(borderUpdate);
                    }
                    else
                    {
                        chunkUpdateRequest = new ChunkUpdateRequest()
                        {
                            borderUpdateRequests = new List <BorderUpdateRequest>()
                        };
                        chunkUpdateRequest.borderUpdateRequests.Add(borderUpdate);

                        pendingLightUpdatesByChunk.Add(UpdateChunkId, chunkUpdateRequest);
                        pendingLightUpdatesOrder.Enqueue(UpdateChunkId);
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Runs a fixed number of lighting propagation updates,
        /// and returns a set of the chunk ids alterred by these updates.
        /// </summary>
        /// <returns></returns>
        public HashSet <Vector3Int> Update()
        {
            Profiler.BeginSample("LightManagerUpdate");
            //Process a finite number of the pending updates.
            int processedThisUpdate = 0;
            Queue <WipPropagationUpdate> jobsInProgress = new Queue <WipPropagationUpdate>();

            var touchedByUpdate = new HashSet <Vector3Int>(chunksWhereLightChangedOnBorderSinceLastUpdate);

            chunksWhereLightChangedOnBorderSinceLastUpdate.Clear();

            while (processedThisUpdate < MaxLightUpdates && pendingLightUpdatesOrder.Count > 0)
            {
                var chunkId     = pendingLightUpdatesOrder.Dequeue();
                var chunkUpdate = pendingLightUpdatesByChunk[chunkId];
                pendingLightUpdatesByChunk.Remove(chunkId);

                if (!chunkManager.IsChunkFullyGenerated(chunkId))
                {
                    //skip, as this chunk is no longer valid for updates
                    continue;
                }

                touchedByUpdate.Add(chunkId);
                var data = getJobData(chunkId);

                Assert.IsTrue(chunkUpdate.borderUpdateRequests.Count > 0);

                //Run border resolution jobs for each face update request

                //common queues
                var dynamicPropagationQueue  = new NativeQueue <int3>(Allocator.Persistent);
                var sunlightPropagationQueue = new NativeQueue <int3>(Allocator.Persistent);

                BorderResolutionJob[] borderResolutionJobs = new BorderResolutionJob[chunkUpdate.borderUpdateRequests.Count];

                for (int i = 0; i < chunkUpdate.borderUpdateRequests.Count; i++)
                {
                    var borderUpdate = chunkUpdate.borderUpdateRequests[i];

                    BorderResolutionJob borderJob = new BorderResolutionJob()
                    {
                        data = data,
                        dynamicPropagationQueue  = dynamicPropagationQueue,
                        sunlightPropagationQueue = sunlightPropagationQueue,
                        dynamicFromBorder        = borderUpdate.dynamic.ToNative(Allocator.Persistent),
                        sunlightFromBorder       = borderUpdate.sunlight.ToNative(Allocator.Persistent),
                        toDirection = borderUpdate.borderDirection
                    };

                    borderResolutionJobs[i] = borderJob;
                }

                ///Just one propagation job will be run, with propagation queues
                ///derived from all the border update requests
                LightPropagationJob propJob = new LightPropagationJob()
                {
                    data = data,
                    sunlightNeighbourUpdates = new LightJobNeighbourUpdates(Allocator.Persistent),
                    dynamicNeighbourUpdates  = new LightJobNeighbourUpdates(Allocator.Persistent),
                    sunlightPropagationQueue = sunlightPropagationQueue,
                    dynamicPropagationQueue  = dynamicPropagationQueue,
                    lightsChangedOnBorder    = new NativeArray <bool>(DirectionExtensions.numDirections, Allocator.Persistent)
                };

                if (Parallel)
                {
                    WipPropagationUpdate updateJob = new WipPropagationUpdate()
                    {
                        borderJobs = borderResolutionJobs,
                        propJob    = propJob
                    };

                    JobHandle handle = new JobHandle();
                    //Chain dependencies of border resolution jobs
                    for (int i = 0; i < borderResolutionJobs.Length; i++)
                    {
                        handle = borderResolutionJobs[i].Schedule(handle);
                    }

                    handle           = propJob.Schedule(handle);
                    updateJob.handle = handle;
                    jobsInProgress.Enqueue(updateJob);
                }
                else
                {
                    for (int i = 0; i < borderResolutionJobs.Length; i++)
                    {
                        borderResolutionJobs[i].Run();
                        borderResolutionJobs[i].Dispose();
                    }

                    propJob.Run();
                    var chunkdata = chunkManager.GetChunkData(data.chunkId.ToBasic());
                    chunkdata.SetLightMap(data.lights.ToArray());

                    ///If any light value changes on any of the borders (not just the ones from which
                    ///propagation started), the corresponding neighbour will need to be re-meshed.
                    for (int i = 0; i < propJob.lightsChangedOnBorder.Length; i++)
                    {
                        var neighbourChunkId = chunkId + DirectionExtensions.Vectors[i];
                        if (propJob.lightsChangedOnBorder[i])
                        {
                            touchedByUpdate.Add(neighbourChunkId);
                        }
                    }

                    QueuePropagationUpdates(propJob);
                    propJob.Dispose();
                }



                processedThisUpdate++;
            }

            Assert.AreEqual(pendingLightUpdatesOrder.Count, pendingLightUpdatesByChunk.Count);

            //Complete the jobs
            while (jobsInProgress.Count > 0)
            {
                var wip = jobsInProgress.Dequeue();
                wip.handle.Complete();

                for (int i = 0; i < wip.borderJobs.Length; i++)
                {
                    wip.borderJobs[i].Dispose();
                }

                var chunkId   = wip.propJob.data.chunkId.ToBasic();
                var chunkdata = chunkManager.GetChunkData(chunkId);
                chunkdata.SetLightMap(wip.propJob.data.lights.ToArray());

                ///If any light value changes on any of the borders (not just the ones from which
                ///propagation started), the corresponding neighbour will need to be re-meshed.
                for (int i = 0; i < wip.propJob.lightsChangedOnBorder.Length; i++)
                {
                    var neighbourChunkId = chunkId + DirectionExtensions.Vectors[i];
                    if (wip.propJob.lightsChangedOnBorder[i])
                    {
                        touchedByUpdate.Add(neighbourChunkId);
                    }
                }

                QueuePropagationUpdates(wip.propJob);
                wip.propJob.Dispose();
            }

            Profiler.EndSample();
            return(touchedByUpdate);
        }
예제 #3
0
        public AbstractPipelineJob <LightmapGenerationJobResult> CreateGenerationJob(Vector3Int chunkId)
        {
            int[] heightMap = heightMapProvider.GetHeightMapForColumn(new Vector2Int(chunkId.x, chunkId.z));

            var jobData = getJobData(chunkId);

            var generationJob = new LightGenerationJob()
            {
                data = jobData,
                dynamicPropagationQueue  = new NativeQueue <int3>(Allocator.Persistent),
                sunlightPropagationQueue = new NativeQueue <int3>(Allocator.Persistent),
                heightmap = heightMap.ToNative()
            };

            var propagationJob = new LightPropagationJob()
            {
                data = jobData,
                sunlightPropagationQueue = generationJob.sunlightPropagationQueue,
                dynamicPropagationQueue  = generationJob.dynamicPropagationQueue,
                sunlightNeighbourUpdates = new LightJobNeighbourUpdates(Allocator.Persistent),
                dynamicNeighbourUpdates  = new LightJobNeighbourUpdates(Allocator.Persistent),
                lightsChangedOnBorder    = new NativeArray <bool>(DirectionExtensions.numDirections, Allocator.Persistent)
            };

            Func <LightmapGenerationJobResult> cleanup = () =>
            {
                var result = new LightmapGenerationJobResult();

                result.lights = jobData.lights.ToArray();
                generationJob.Dispose();

                QueuePropagationUpdates(propagationJob);

                ///If any light value changes on any of the borders
                ///the corresponding neighbour will need to be re-meshed.
                for (int i = 0; i < propagationJob.lightsChangedOnBorder.Length; i++)
                {
                    var neighbourChunkId = chunkId + DirectionExtensions.Vectors[i];
                    if (propagationJob.lightsChangedOnBorder[i])
                    {
                        chunksWhereLightChangedOnBorderSinceLastUpdate.Add(neighbourChunkId);
                    }
                }

                propagationJob.Dispose();

                return(result);
            };

            if (!Parallel)
            {
                return(new BasicFunctionJob <LightmapGenerationJobResult>(() =>
                {
                    generationJob.Run();
                    propagationJob.Run();
                    return cleanup();
                }));
            }

            var genHandle  = generationJob.Schedule();
            var propHandle = propagationJob.Schedule(genHandle);

            return(new PipelineUnityJob <LightmapGenerationJobResult>(propHandle, cleanup));
        }