Пример #1
0
        public void PartialSortInsertionMergeRadix(uint[] values)
        {
            NativeArray <uint> supportArray = new NativeArray <uint>();
            int sortCount = 5;

            foreach (var algorithmId in Enum.GetValues(typeof(SortAlgorithm)))
            {
                var algorithmValue = (SortAlgorithm)algorithmId;
                var array          = new NativeArray <uint>(values, Allocator.Temp);
                if (algorithmValue == SortAlgorithm.Insertion)
                {
                    CoreUnsafeUtils.InsertionSort(array, sortCount);
                }
                else if (algorithmValue == SortAlgorithm.Merge)
                {
                    CoreUnsafeUtils.MergeSort(array, sortCount, ref supportArray);
                }
                else if (algorithmValue == SortAlgorithm.Radix)
                {
                    CoreUnsafeUtils.RadixSort(array, sortCount, ref supportArray);
                }

                for (int i = 0; i < sortCount - 1; ++i)
                {
                    Assert.LessOrEqual(array[i], array[i + 1]);
                }
                for (int i = sortCount; i < array.Length; ++i)
                {
                    Assert.That(array[i] == 0 || array[i] == 1);
                }
                array.Dispose();
            }

            supportArray.Dispose();
        }
        public void QuickSortHash(Hash128[] l, Hash128[] r)
        {
            var lPtr = stackalloc Hash128[l.Length];
            var rPtr = stackalloc Hash128[r.Length];

            for (int i = 0; i < l.Length; ++i)
            {
                lPtr[i] = l[i];
                rPtr[i] = r[i];
            }

            CoreUnsafeUtils.QuickSort <Hash128>(l.Length, lPtr);
            CoreUnsafeUtils.QuickSort <Hash128>(r.Length, rPtr);

            for (int i = 0; i < l.Length - 1; ++i)
            {
                Assert.LessOrEqual(lPtr[i], lPtr[i + 1]);
                Assert.LessOrEqual(rPtr[i], rPtr[i + 1]);
            }

            for (int i = 0; i < l.Length; ++i)
            {
                Assert.AreEqual(lPtr[i], rPtr[i]);
            }
        }
Пример #3
0
 /// <summary>
 /// Perform a quick sort on a <see cref="ListBuffer{T}"/>.
 /// </summary>
 /// <param name="self">The list to sort.</param>
 /// <typeparam name="T">The type of the element in the list.</typeparam>
 public static void QuickSort <T>(this ListBuffer <T> self)
     where T : unmanaged, IComparable <T>
 {
     unsafe
     {
         CoreUnsafeUtils.QuickSort <int>(self.Count, self.BufferPtr);
     }
 }
Пример #4
0
        public void InsertionSort(uint[] values)
        {
            var array = new NativeArray <uint>(values, Allocator.Temp);

            CoreUnsafeUtils.InsertionSort(array, array.Length);
            for (int i = 0; i < array.Length - 1; ++i)
            {
                Assert.LessOrEqual(array[i], array[i + 1]);
            }

            array.Dispose();
        }
        public void QuickSort(int[] values)
        {
            // We must perform a copy to avoid messing the test data directly
            var ptrValues = stackalloc int[values.Length];

            values.CopyTo(ptrValues, values.Length);

            CoreUnsafeUtils.QuickSort <int>(values.Length, ptrValues);

            for (int i = 0; i < values.Length - 1; ++i)
            {
                Assert.LessOrEqual(ptrValues[i], ptrValues[i + 1]);
            }
        }
Пример #6
0
        public void RadixSort(uint[] values)
        {
            NativeArray <uint> supportArray = new NativeArray <uint>();
            var array = new NativeArray <uint>(values, Allocator.Temp);

            CoreUnsafeUtils.RadixSort(array, array.Length, ref supportArray);
            for (int i = 0; i < array.Length - 1; ++i)
            {
                Assert.LessOrEqual(array[i], array[i + 1]);
            }

            array.Dispose();
            supportArray.Dispose();
        }
 private void SortLightKeys()
 {
     using (new ProfilingScope(null, ProfilingSampler.Get(HDProfileId.SortVisibleLights)))
     {
         //Tunning against ps4 console,
         //32 items insertion sort has a workst case of 3 micro seconds.
         //200 non recursive merge sort has around 23 micro seconds.
         //From 200 and more, Radix sort beats everything.
         var sortSize = sortedLightCounts;
         if (sortSize <= 32)
         {
             CoreUnsafeUtils.InsertionSort(m_SortKeys, sortSize);
         }
         else if (m_Size <= 200)
         {
             CoreUnsafeUtils.MergeSort(m_SortKeys, sortSize, ref m_SortSupportArray);
         }
         else
         {
             CoreUnsafeUtils.RadixSort(m_SortKeys, sortSize, ref m_SortSupportArray);
         }
     }
 }
        public override void Tick(
            SceneStateHash sceneStateHash,
            IScriptableBakedReflectionSystemStageNotifier handle
            )
        {
            if (!AreAllOpenedSceneSaved())
            {
                handle.SetIsDone(true);
                return;
            }

            // On the C# side, we don't have non blocking asset import APIs, and we don't want to block the
            //   UI when the user is editing the world.
            //   So, we skip the baking when the user is editing any UI control.
            if (GUIUtility.hotControl != 0)
            {
                return;
            }

            if (!IsCurrentSRPValid(out HDRenderPipeline hdPipeline))
            {
                if (ShouldIssueWarningForCurrentSRP())
                {
                    Debug.LogWarning("HDBakedReflectionSystem work with HDRP, " +
                                     "please switch your render pipeline or use another reflection system");
                }

                handle.ExitStage((int)BakingStages.ReflectionProbes);
                handle.SetIsDone(true);
                return;
            }

            var ambientProbeHash = sceneStateHash.ambientProbeHash;
            var sceneObjectsHash = sceneStateHash.sceneObjectsHash;
            var skySettingsHash  = sceneStateHash.skySettingsHash;

            DeleteCubemapAssets(true);

            // Explanation of the algorithm:
            // 1. First we create the hash of the world that can impact the reflection probes.
            // 2. Then for each probe, we calculate a hash that represent what this specific probe should have baked.
            // 3. We compare those hashes against the baked one and decide:
            //   a. If we have to remove a baked data
            //   b. If we have to bake a probe
            // 4. Bake all required probes
            // 5. Remove unused baked data
            // 6. Update probe assets

            // == 1. ==
            var allProbeDependencyHash = new Hash128();

            // TODO: All baked probes depend on custom probes (hash all custom probes and set as dependency)
            // TODO: All baked probes depend on HDRP specific Light settings
            HashUtilities.AppendHash(ref ambientProbeHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref sceneObjectsHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref skySettingsHash, ref allProbeDependencyHash);

            var bakedProbes = HDProbeSystem.bakedProbes;

            // == 2. ==
            var states = stackalloc HDProbeBakingState[bakedProbes.Count];

            ComputeProbeInstanceID(bakedProbes, states);
            ComputeProbeSettingsHashes(bakedProbes, states);
            // TODO: Handle bounce dependency here
            ComputeProbeBakingHashes(bakedProbes.Count, allProbeDependencyHash, states);

            CoreUnsafeUtils.QuickSort <HDProbeBakingState, Hash128, HDProbeBakingState.ProbeBakingHash>(
                bakedProbes.Count, states
                );

            int operationCount = 0, addCount = 0, remCount = 0;
            var maxProbeCount = Mathf.Max(bakedProbes.Count, m_HDProbeBakedStates.Length);
            var addIndices    = stackalloc int[maxProbeCount];
            var remIndices    = stackalloc int[maxProbeCount];

            if (m_HDProbeBakedStates.Length == 0)
            {
                for (int i = 0; i < bakedProbes.Count; ++i)
                {
                    addIndices[addCount++] = i;
                }
                operationCount = addCount;
            }
            else
            {
                fixed(HDProbeBakedState *oldBakedStates = &m_HDProbeBakedStates[0])
                {
                    // == 3. ==
                    // Compare hashes between baked probe states and desired probe states
                    operationCount = CoreUnsafeUtils.CompareHashes <
                        HDProbeBakedState, HDProbeBakedState.ProbeBakedHash,
                        HDProbeBakingState, HDProbeBakingState.ProbeBakingHash
                        > (
                        m_HDProbeBakedStates.Length, oldBakedStates, // old hashes
                        bakedProbes.Count, states,                   // new hashes
                        addIndices, remIndices,
                        out addCount, out remCount
                        );
                }
            }

            if (operationCount > 0)
            {
                // == 4. ==
                var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize;
                var planarSize  = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.planarReflectionTextureSize;
                var cubeRT      = HDRenderUtilities.CreateReflectionProbeRenderTarget(cubemapSize);
                var planarRT    = HDRenderUtilities.CreatePlanarProbeRenderTarget(planarSize);

                handle.EnterStage(
                    (int)BakingStages.ReflectionProbes,
                    string.Format("Reflection Probes | {0} jobs", addCount),
                    0
                    );

                // Render probes
                for (int i = 0; i < addCount; ++i)
                {
                    handle.EnterStage(
                        (int)BakingStages.ReflectionProbes,
                        string.Format("Reflection Probes | {0} jobs", addCount),
                        i / (float)addCount
                        );

                    var index      = addIndices[i];
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    // Get from cache or render the probe
                    if (!File.Exists(cacheFile))
                    {
                        RenderAndWriteToFile(probe, cacheFile, cubeRT, planarRT);
                    }
                }
                cubeRT.Release();
                planarRT.Release();

                // Copy texture from cache
                for (int i = 0; i < addCount; ++i)
                {
                    var index      = addIndices[i];
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    Assert.IsTrue(File.Exists(cacheFile));

                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    HDBakingUtilities.CreateParentDirectoryIfMissing(bakedTexturePath);
                    Checkout(bakedTexturePath);
                    // Checkout will make those file writeable, but this is not immediate,
                    // so we retries when this fails.
                    if (!HDEditorUtils.CopyFileWithRetryOnUnauthorizedAccess(cacheFile, bakedTexturePath))
                    {
                        return;
                    }
                }
                // AssetPipeline bug
                // Sometimes, the baked texture reference is destroyed during 'AssetDatabase.StopAssetEditing()'
                //   thus, the reference to the baked texture in the probe is lost
                // Although, importing twice the texture seems to workaround the issue
                for (int j = 0; j < 2; ++j)
                {
                    AssetDatabase.StartAssetEditing();
                    for (int i = 0; i < bakedProbes.Count; ++i)
                    {
                        var index            = addIndices[i];
                        var instanceId       = states[index].instanceID;
                        var probe            = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                        var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                        AssetDatabase.ImportAsset(bakedTexturePath);
                        ImportAssetAt(probe, bakedTexturePath);
                    }
                    AssetDatabase.StopAssetEditing();
                }
                // Import assets
                AssetDatabase.StartAssetEditing();
                for (int i = 0; i < addCount; ++i)
                {
                    var index            = addIndices[i];
                    var instanceId       = states[index].instanceID;
                    var probe            = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    var bakedTexture     = AssetDatabase.LoadAssetAtPath <Texture>(bakedTexturePath);
                    Assert.IsNotNull(bakedTexture, "The baked texture was imported before, " +
                                     "so it must exists in AssetDatabase");

                    probe.SetTexture(ProbeSettings.Mode.Baked, bakedTexture);
                    EditorUtility.SetDirty(probe);
                }
                AssetDatabase.StopAssetEditing();

                // == 5. ==

                // Create new baked state array
                var targetSize        = m_HDProbeBakedStates.Length + addCount - remCount;
                var targetBakedStates = stackalloc HDProbeBakedState[targetSize];
                // Copy baked state that are not removed
                var targetI = 0;
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    if (CoreUnsafeUtils.IndexOf(remIndices, remCount, i) != -1)
                    {
                        continue;
                    }
                    targetBakedStates[targetI++] = m_HDProbeBakedStates[i];
                }
                // Add new baked states
                for (int i = 0; i < addCount; ++i)
                {
                    var state = states[addIndices[i]];
                    targetBakedStates[targetI++] = new HDProbeBakedState
                    {
                        instanceID     = state.instanceID,
                        probeBakedHash = state.probeBakingHash
                    };
                }
                CoreUnsafeUtils.QuickSort <HDProbeBakedState, Hash128, HDProbeBakedState.ProbeBakedHash>(
                    targetI, targetBakedStates
                    );

                Array.Resize(ref m_HDProbeBakedStates, targetSize);
                if (targetSize > 0)
                {
                    fixed(HDProbeBakedState *bakedStates = &m_HDProbeBakedStates[0])
                    {
                        UnsafeUtility.MemCpy(
                            bakedStates,
                            targetBakedStates,
                            sizeof(HDProbeBakedState) * targetSize
                            );
                    }
                }

                // Update state hash
                Array.Resize(ref m_StateHashes, m_HDProbeBakedStates.Length);
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    m_StateHashes[i] = m_HDProbeBakedStates[i].probeBakedHash;
                }
                stateHashes = m_StateHashes;
            }

            handle.ExitStage((int)BakingStages.ReflectionProbes);

            handle.SetIsDone(true);
        }
Пример #9
0
        public override void Tick(
            SceneStateHash sceneStateHash,
            IScriptableBakedReflectionSystemStageNotifier handle
            )
        {
            if (!AreAllOpenedSceneSaved())
            {
                handle.SetIsDone(true);
                return;
            }

            // On the C# side, we don't have non blocking asset import APIs, and we don't want to block the
            //   UI when the user is editing the world.
            //   So, we skip the baking when the user is editing any UI control.
            if (GUIUtility.hotControl != 0)
            {
                return;
            }

            if (!IsCurrentSRPValid(out HDRenderPipeline hdPipeline))
            {
                if (ShouldIssueWarningForCurrentSRP())
                {
                    Debug.LogWarning("HDBakedReflectionSystem work with HDRP, " +
                                     "Either switch your render pipeline or use a different reflection system. You may need to trigger a " +
                                     "C# domain reload to initialize the appropriate reflection system. One way to do this is to compile a script.");
                }

                handle.ExitStage((int)BakingStages.ReflectionProbes);
                handle.SetIsDone(true);
                return;
            }

            var ambientProbeHash = sceneStateHash.ambientProbeHash;
            var sceneObjectsHash = sceneStateHash.sceneObjectsHash;
            var skySettingsHash  = sceneStateHash.skySettingsHash;

            DeleteCubemapAssets(true);

            // Explanation of the algorithm:
            // 1. First we create the hash of the world that can impact the reflection probes.
            // 2. Then for each probe, we calculate a hash that represent what this specific probe should have baked.
            // 3. We compare those hashes against the baked one and decide:
            //   a. If we have to remove a baked data
            //   b. If we have to bake a probe
            // 4. Bake all required probes
            //   a. Bake probe that were added or modified
            //   b. Bake probe with a missing baked texture
            // 5. Remove unused baked data
            // 6. Update probe assets

            // == 1. ==
            var allProbeDependencyHash = new Hash128();

            // TODO: All baked probes depend on custom probes (hash all custom probes and set as dependency)
            // TODO: All baked probes depend on HDRP specific Light settings
            HashUtilities.AppendHash(ref ambientProbeHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref sceneObjectsHash, ref allProbeDependencyHash);
            HashUtilities.AppendHash(ref skySettingsHash, ref allProbeDependencyHash);

            var bakedProbes     = HDProbeSystem.bakedProbes;
            var bakedProbeCount = HDProbeSystem.bakedProbeCount;

            // == 2. ==
            var states = stackalloc HDProbeBakingState[bakedProbeCount];
            // A list of indices of probe we may want to force to rebake, even if the hashes matches.
            // Usually, add a probe when something external to its state or the world state forces the bake.
            var probeForcedToBakeIndices      = stackalloc int[bakedProbeCount];
            var probeForcedToBakeIndicesCount = 0;
            var probeForcedToBakeIndicesList  = new ListBuffer <int>(
                probeForcedToBakeIndices,
                &probeForcedToBakeIndicesCount,
                bakedProbeCount
                );

            ComputeProbeInstanceID(bakedProbes, states);
            ComputeProbeSettingsHashes(bakedProbes, states);
            // TODO: Handle bounce dependency here
            ComputeProbeBakingHashes(bakedProbeCount, allProbeDependencyHash, states);

            // Force to rebake probe with missing baked texture
            for (var i = 0; i < bakedProbeCount; ++i)
            {
                var instanceId = states[i].instanceID;
                var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                if (probe.bakedTexture != null && !probe.bakedTexture.Equals(null))
                {
                    continue;
                }

                probeForcedToBakeIndicesList.TryAdd(i);
            }

            CoreUnsafeUtils.QuickSort <HDProbeBakingState, Hash128, HDProbeBakingState.ProbeBakingHash>(
                bakedProbeCount, states
                );

            int operationCount = 0, addCount = 0, remCount = 0;
            var maxProbeCount = Mathf.Max(bakedProbeCount, m_HDProbeBakedStates.Length);
            var addIndices    = stackalloc int[maxProbeCount];
            var remIndices    = stackalloc int[maxProbeCount];

            if (m_HDProbeBakedStates.Length == 0)
            {
                for (int i = 0; i < bakedProbeCount; ++i)
                {
                    addIndices[addCount++] = i;
                }
                operationCount = addCount;
            }
            else
            {
                fixed(HDProbeBakedState *oldBakedStates = &m_HDProbeBakedStates[0])
                {
                    // == 3. ==
                    // Compare hashes between baked probe states and desired probe states
                    operationCount = CoreUnsafeUtils.CompareHashes <
                        HDProbeBakedState, HDProbeBakedState.ProbeBakedHash,
                        HDProbeBakingState, HDProbeBakingState.ProbeBakingHash
                        > (
                        m_HDProbeBakedStates.Length, oldBakedStates, // old hashes
                        bakedProbeCount, states,                     // new hashes
                        addIndices, remIndices,
                        out addCount, out remCount
                        );
                }
            }

            if (operationCount > 0 || probeForcedToBakeIndicesList.Count > 0)
            {
                // == 4. ==
                var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize;
                // We force RGBAHalf as we don't support 11-11-10 textures (only RT)
                var probeFormat = GraphicsFormat.R16G16B16A16_SFloat;

                var cubeRT = HDRenderUtilities.CreateReflectionProbeRenderTarget(cubemapSize, probeFormat);

                handle.EnterStage(
                    (int)BakingStages.ReflectionProbes,
                    string.Format("Reflection Probes | {0} jobs", addCount),
                    0
                    );

                // Compute indices of probes to bake: added, modified probe or with a missing baked texture.
                var toBakeIndices      = stackalloc int[bakedProbeCount];
                var toBakeIndicesCount = 0;
                var toBakeIndicesList  = new ListBuffer <int>(toBakeIndices, &toBakeIndicesCount, bakedProbeCount);
                {
                    // Note: we will add probes from change check and baked texture missing check.
                    //   So we can add at most 2 time the probe in the list.
                    var toBakeIndicesTmp      = stackalloc int[bakedProbeCount * 2];
                    var toBakeIndicesTmpCount = 0;
                    var toBakeIndicesTmpList  =
                        new ListBuffer <int>(toBakeIndicesTmp, &toBakeIndicesTmpCount, bakedProbeCount * 2);

                    // Add the indices from the added or modified detection check
                    toBakeIndicesTmpList.TryCopyFrom(addIndices, addCount);
                    // Add the probe with missing baked texture check
                    probeForcedToBakeIndicesList.TryCopyTo(toBakeIndicesTmpList);

                    // Sort indices
                    toBakeIndicesTmpList.QuickSort();
                    // Add to final list without the duplicates
                    var lastValue = int.MaxValue;
                    for (var i = 0; i < toBakeIndicesTmpList.Count; ++i)
                    {
                        if (lastValue == toBakeIndicesTmpList.GetUnchecked(i))
                        {
                            // Skip duplicates
                            continue;
                        }

                        lastValue = toBakeIndicesTmpList.GetUnchecked(i);
                        toBakeIndicesList.TryAdd(lastValue);
                    }
                }

                // Render probes that were added or modified
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    handle.EnterStage(
                        (int)BakingStages.ReflectionProbes,
                        string.Format("Reflection Probes | {0} jobs", addCount),
                        i / (float)toBakeIndicesCount
                        );

                    var index      = toBakeIndicesList.GetUnchecked(i);
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    // Get from cache or render the probe
                    if (!File.Exists(cacheFile))
                    {
                        var planarRT = HDRenderUtilities.CreatePlanarProbeRenderTarget((int)probe.resolution, probeFormat);
                        RenderAndWriteToFile(probe, cacheFile, cubeRT, planarRT);
                        planarRT.Release();
                    }
                }
                cubeRT.Release();

                // Copy texture from cache
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    var index      = toBakeIndicesList.GetUnchecked(i);
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    var cacheFile  = GetGICacheFileForHDProbe(states[index].probeBakingHash);

                    if (string.IsNullOrEmpty(probe.gameObject.scene.path))
                    {
                        continue;
                    }

                    Assert.IsTrue(File.Exists(cacheFile));

                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    HDBakingUtilities.CreateParentDirectoryIfMissing(bakedTexturePath);
                    Checkout(bakedTexturePath);
                    // Checkout will make those file writeable, but this is not immediate,
                    // so we retries when this fails.
                    if (!HDEditorUtils.CopyFileWithRetryOnUnauthorizedAccess(cacheFile, bakedTexturePath))
                    {
                        return;
                    }
                }
                // AssetPipeline bug
                // Sometimes, the baked texture reference is destroyed during 'AssetDatabase.StopAssetEditing()'
                //   thus, the reference to the baked texture in the probe is lost
                // Although, importing twice the texture seems to workaround the issue
                for (int j = 0; j < 2; ++j)
                {
                    AssetDatabase.StartAssetEditing();
                    for (int i = 0; i < bakedProbeCount; ++i)
                    {
                        var index      = toBakeIndicesList.GetUnchecked(i);
                        var instanceId = states[index].instanceID;
                        var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                        if (string.IsNullOrEmpty(probe.gameObject.scene.path))
                        {
                            continue;
                        }

                        var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                        AssetDatabase.ImportAsset(bakedTexturePath);
                        ImportAssetAt(probe, bakedTexturePath);
                    }
                    AssetDatabase.StopAssetEditing();
                }
                // Import assets
                AssetDatabase.StartAssetEditing();
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    var index      = toBakeIndicesList.GetUnchecked(i);
                    var instanceId = states[index].instanceID;
                    var probe      = (HDProbe)EditorUtility.InstanceIDToObject(instanceId);
                    if (string.IsNullOrEmpty(probe.gameObject.scene.path))
                    {
                        continue;
                    }

                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    var bakedTexture     = AssetDatabase.LoadAssetAtPath <Texture>(bakedTexturePath);
                    Assert.IsNotNull(bakedTexture, "The baked texture was imported before, " +
                                     "so it must exists in AssetDatabase");

                    probe.SetTexture(ProbeSettings.Mode.Baked, bakedTexture);
                    EditorUtility.SetDirty(probe);
                }
                AssetDatabase.StopAssetEditing();

                // == 5. ==

                // Create new baked state array
                var targetSize        = m_HDProbeBakedStates.Length - remCount + toBakeIndicesList.Count;
                var targetBakedStates = stackalloc HDProbeBakedState[targetSize];
                // Copy baked state that are not removed
                var targetI = 0;
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    if (CoreUnsafeUtils.IndexOf(remIndices, remCount, i) != -1)
                    {
                        continue;
                    }
                    Assert.IsTrue(targetI < targetSize);
                    targetBakedStates[targetI++] = m_HDProbeBakedStates[i];
                }
                // Add new baked states
                for (int i = 0; i < toBakeIndicesList.Count; ++i)
                {
                    var state = states[toBakeIndicesList.GetUnchecked(i)];
                    Assert.IsTrue(targetI < targetSize);
                    targetBakedStates[targetI++] = new HDProbeBakedState
                    {
                        instanceID     = state.instanceID,
                        probeBakedHash = state.probeBakingHash
                    };
                }
                CoreUnsafeUtils.QuickSort <HDProbeBakedState, Hash128, HDProbeBakedState.ProbeBakedHash>(
                    targetI, targetBakedStates
                    );

                Array.Resize(ref m_HDProbeBakedStates, targetSize);
                if (targetSize > 0)
                {
                    fixed(HDProbeBakedState *bakedStates = &m_HDProbeBakedStates[0])
                    {
                        UnsafeUtility.MemCpy(
                            bakedStates,
                            targetBakedStates,
                            sizeof(HDProbeBakedState) * targetSize
                            );
                    }
                }

                // Update state hash
                Array.Resize(ref m_StateHashes, m_HDProbeBakedStates.Length);
                for (int i = 0; i < m_HDProbeBakedStates.Length; ++i)
                {
                    m_StateHashes[i] = m_HDProbeBakedStates[i].probeBakedHash;
                }
                stateHashes = m_StateHashes;
            }

            handle.ExitStage((int)BakingStages.ReflectionProbes);

            handle.SetIsDone(true);
        }
Пример #10
0
        ProbeVolumeList PrepareVisibleProbeVolumeList(ScriptableRenderContext renderContext, HDCamera hdCamera, CommandBuffer cmd)
        {
            ProbeVolumeList probeVolumes = new ProbeVolumeList();

            if (ShaderConfig.s_ProbeVolumesEvaluationMode == ProbeVolumesEvaluationModes.Disabled)
            {
                return(probeVolumes);
            }

            if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.ProbeVolume))
            {
                return(probeVolumes);
            }

            var  settings = hdCamera.volumeStack.GetComponent <ProbeVolumeController>();
            bool octahedralDepthOcclusionFilterIsEnabled = settings.leakMitigationMode.value == LeakMitigationMode.OctahedralDepthOcclusionFilter;

            using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.PrepareProbeVolumeList)))
            {
                ClearProbeVolumeAtlasIfRequested(cmd);

                Vector3 camPosition = hdCamera.camera.transform.position;
                Vector3 camOffset   = Vector3.zero;// World-origin-relative

                if (ShaderConfig.s_CameraRelativeRendering != 0)
                {
                    camOffset = camPosition; // Camera-relative
                }

                m_VisibleProbeVolumeBounds.Clear();
                m_VisibleProbeVolumeData.Clear();

                // Collect all visible finite volume data, and upload it to the GPU.
                List <ProbeVolume> volumes = ProbeVolumeManager.manager.volumes;

                int probeVolumesCount = Math.Min(volumes.Count, k_MaxVisibleProbeVolumeCount);
                int sortCount         = 0;

                // Sort probe volumes smallest from smallest to largest volume.
                // Same as is done with reflection probes.
                // See LightLoop.cs::PrepareLightsForGPU() for original example of this.
                for (int probeVolumesIndex = 0; (probeVolumesIndex < volumes.Count) && (sortCount < probeVolumesCount); probeVolumesIndex++)
                {
                    ProbeVolume volume = volumes[probeVolumesIndex];

#if UNITY_EDITOR
                    if (!volume.IsAssetCompatible())
                    {
                        continue;
                    }
#endif

                    if (ShaderConfig.s_ProbeVolumesAdditiveBlending == 0 && volume.parameters.volumeBlendMode != VolumeBlendMode.Normal)
                    {
                        // Non-normal blend mode volumes are not supported. Skip.
                        continue;
                    }

                    float probeVolumeDepthFromCameraWS = Vector3.Dot(hdCamera.camera.transform.forward, volume.transform.position - camPosition);
                    if (probeVolumeDepthFromCameraWS >= volume.parameters.distanceFadeEnd)
                    {
                        // Probe volume is completely faded out from distance fade optimization.
                        // Do not bother adding it to the list, it would evaluate to zero weight.
                        continue;
                    }

                    // TODO: cache these?
                    var obb = new OrientedBBox(Matrix4x4.TRS(volume.transform.position, volume.transform.rotation, volume.parameters.size));

                    // Handle camera-relative rendering.
                    obb.center -= camOffset;

                    // Frustum cull on the CPU for now. TODO: do it on the GPU.
                    if (GeometryUtils.Overlap(obb, hdCamera.frustum, hdCamera.frustum.planes.Length, hdCamera.frustum.corners.Length))
                    {
                        var logVolume = CalculateProbeVolumeLogVolume(volume.parameters.size);

                        m_ProbeVolumeSortKeys[sortCount++] = PackProbeVolumeSortKey(volume.parameters.volumeBlendMode, logVolume, probeVolumesIndex);
                    }
                }

                CoreUnsafeUtils.QuickSort(m_ProbeVolumeSortKeys, 0, sortCount - 1); // Call our own quicksort instead of Array.Sort(sortKeys, 0, sortCount) so we don't allocate memory (note the SortCount-1 that is different from original call).

                for (int sortIndex = 0; sortIndex < sortCount; ++sortIndex)
                {
                    // In 1. we have already classify and sorted the probe volume, we need to use this sorted order here
                    uint sortKey = m_ProbeVolumeSortKeys[sortIndex];
                    int  probeVolumesIndex;
                    UnpackProbeVolumeSortKey(sortKey, out probeVolumesIndex);

                    ProbeVolume volume = volumes[probeVolumesIndex];

                    // TODO: cache these?
                    var obb = new OrientedBBox(Matrix4x4.TRS(volume.transform.position, volume.transform.rotation, volume.parameters.size));

                    // Handle camera-relative rendering.
                    obb.center -= camOffset;

                    // TODO: cache these?
                    var data = volume.parameters.ConvertToEngineData();

                    // Note: The system is not aware of slice packing in Z.
                    // Need to modify scale and bias terms just before uploading to GPU.
                    // TODO: Should we make it aware earlier up the chain?
                    data.scale.z = data.scale.z / (float)m_ProbeVolumeAtlasSHRTDepthSliceCount;
                    data.bias.z  = data.bias.z / (float)m_ProbeVolumeAtlasSHRTDepthSliceCount;

                    m_VisibleProbeVolumeBounds.Add(obb);
                    m_VisibleProbeVolumeData.Add(data);
                }

                s_VisibleProbeVolumeBoundsBuffer.SetData(m_VisibleProbeVolumeBounds);
                s_VisibleProbeVolumeDataBuffer.SetData(m_VisibleProbeVolumeData);

                // Fill the struct with pointers in order to share the data with the light loop.
                probeVolumes.bounds = m_VisibleProbeVolumeBounds;
                probeVolumes.data   = m_VisibleProbeVolumeData;

                // For now, only upload one volume per frame.
                // This is done:
                // 1) To timeslice upload cost across N frames for N volumes.
                // 2) To avoid creating a sync point between compute buffer upload and each volume upload.
                const int volumeUploadedToAtlasSHCapacity = 1;
                int       volumeUploadedToAtlasOctahedralDepthCapacity = octahedralDepthOcclusionFilterIsEnabled ? 1 : 0;
                int       volumeUploadedToAtlasSHCount = 0;
                int       volumeUploadedToAtlasOctahedralDepthCount = 0;

                for (int sortIndex = 0; sortIndex < sortCount; ++sortIndex)
                {
                    uint sortKey = m_ProbeVolumeSortKeys[sortIndex];
                    int  probeVolumesIndex;
                    UnpackProbeVolumeSortKey(sortKey, out probeVolumesIndex);

                    ProbeVolume volume = volumes[probeVolumesIndex];

                    if (volumeUploadedToAtlasSHCount < volumeUploadedToAtlasSHCapacity)
                    {
                        bool volumeWasUploaded = EnsureProbeVolumeInAtlas(renderContext, cmd, volume);
                        if (volumeWasUploaded)
                        {
                            ++volumeUploadedToAtlasSHCount;
                        }
                    }

                    if (volumeUploadedToAtlasOctahedralDepthCount < volumeUploadedToAtlasOctahedralDepthCapacity)
                    {
                        bool volumeWasUploaded = EnsureProbeVolumeInAtlasOctahedralDepth(renderContext, cmd, volume);
                        if (volumeWasUploaded)
                        {
                            ++volumeUploadedToAtlasOctahedralDepthCount;
                        }
                    }

                    if (volumeUploadedToAtlasSHCount == volumeUploadedToAtlasSHCapacity &&
                        volumeUploadedToAtlasOctahedralDepthCount == volumeUploadedToAtlasOctahedralDepthCapacity)
                    {
                        // Met our capacity this frame. Early out.
                        break;
                    }
                }

                return(probeVolumes);
            }
        }
Пример #11
0
        void BuildDebugRepresentation()
        {
            if (!isDebugViewMaterialInit)
            {
                List <RenderPipelineMaterial> materialList = HDUtils.GetRenderPipelineMaterialList();

                // TODO: Share this code to retrieve deferred material with HDRenderPipeline
                // Find first material that is a deferredMaterial
                Type bsdfDataDeferredType = null;
                foreach (RenderPipelineMaterial material in materialList)
                {
                    if (material.IsDefferedMaterial())
                    {
                        bsdfDataDeferredType = material.GetType().GetNestedType("BSDFData");
                    }
                }

                // TODO: Handle the case of no Gbuffer material
                Debug.Assert(bsdfDataDeferredType != null);

                List <MaterialItem> materialItems = new List <MaterialItem>();

                int numSurfaceDataFields = 0;
                int numBSDFDataFields    = 0;
                foreach (RenderPipelineMaterial material in materialList)
                {
                    MaterialItem item = new MaterialItem();

                    item.className = material.GetType().Name + "/";

                    item.surfaceDataType  = material.GetType().GetNestedType("SurfaceData");
                    numSurfaceDataFields += item.surfaceDataType.GetFields().Length;

                    item.bsdfDataType  = material.GetType().GetNestedType("BSDFData");
                    numBSDFDataFields += item.bsdfDataType.GetFields().Length;

                    materialItems.Add(item);
                }

                // Init list
                List <GUIContent> debugViewMaterialStringsList           = new List <GUIContent>();
                List <int>        debugViewMaterialValuesList            = new List <int>();
                List <GUIContent> debugViewEngineStringsList             = new List <GUIContent>();
                List <int>        debugViewEngineValuesList              = new List <int>();
                List <GUIContent> debugViewMaterialVaryingStringsList    = new List <GUIContent>();
                List <int>        debugViewMaterialVaryingValuesList     = new List <int>();
                List <GUIContent> debugViewMaterialPropertiesStringsList = new List <GUIContent>();
                List <int>        debugViewMaterialPropertiesValuesList  = new List <int>();
                List <GUIContent> debugViewMaterialTextureStringsList    = new List <GUIContent>();
                List <int>        debugViewMaterialTextureValuesList     = new List <int>();
                List <GUIContent> debugViewMaterialGBufferStringsList    = new List <GUIContent>();
                List <int>        debugViewMaterialGBufferValuesList     = new List <int>();

                // First element is a reserved location and should not be used (allow to track error)
                // Special case for None since it cannot be inferred from SurfaceData/BuiltinData
                debugViewMaterialStringsList.Add(new GUIContent("None"));
                debugViewMaterialValuesList.Add(0);

                foreach (MaterialItem item in materialItems)
                {
                    // BuiltinData are duplicated for each material
                    // Giving the material specific types allow to move iterator at a separate range for each material
                    // Otherwise, all BuiltinData will be at same offset and will broke the enum
                    int nbElement = FillWithProperties(typeof(Builtin.BuiltinData), ref debugViewMaterialStringsList, ref debugViewMaterialValuesList, item.className, overrideTypeForIndex: item.surfaceDataType);
                    FillWithProperties(item.surfaceDataType, ref debugViewMaterialStringsList, ref debugViewMaterialValuesList, item.className, baseIndex: nbElement);
                }

                // Engine properties debug
                // First element is a reserved location and should not be used (allow to track error)
                // Special case for None since it cannot be inferred from SurfaceData/BuiltinData
                debugViewEngineStringsList.Add(new GUIContent("None"));
                debugViewEngineValuesList.Add(0);

                foreach (MaterialItem item in materialItems)
                {
                    FillWithProperties(item.bsdfDataType, ref debugViewEngineStringsList, ref debugViewEngineValuesList, item.className);
                }

                // For the following, no need to reserve the 0 case as it is handled in the Enum

                // Attributes debug
                FillWithPropertiesEnum(typeof(DebugViewVarying), ref debugViewMaterialVaryingStringsList, ref debugViewMaterialVaryingValuesList, "");

                // Properties debug
                FillWithPropertiesEnum(typeof(DebugViewProperties), ref debugViewMaterialPropertiesStringsList, ref debugViewMaterialPropertiesValuesList, "");

                // Gbuffer debug
                FillWithPropertiesEnum(typeof(DebugViewGbuffer), ref debugViewMaterialGBufferStringsList, ref debugViewMaterialGBufferValuesList, "");
                FillWithProperties(typeof(Lit.BSDFData), ref debugViewMaterialGBufferStringsList, ref debugViewMaterialGBufferValuesList, "");

                // Convert to array for UI
                debugViewMaterialStrings = debugViewMaterialStringsList.ToArray();
                debugViewMaterialValues  = debugViewMaterialValuesList.ToArray();

                debugViewEngineStrings = debugViewEngineStringsList.ToArray();
                debugViewEngineValues  = debugViewEngineValuesList.ToArray();

                debugViewMaterialVaryingStrings = debugViewMaterialVaryingStringsList.ToArray();
                debugViewMaterialVaryingValues  = debugViewMaterialVaryingValuesList.ToArray();

                debugViewMaterialPropertiesStrings = debugViewMaterialPropertiesStringsList.ToArray();
                debugViewMaterialPropertiesValues  = debugViewMaterialPropertiesValuesList.ToArray();

                debugViewMaterialTextureStrings = debugViewMaterialTextureStringsList.ToArray();
                debugViewMaterialTextureValues  = debugViewMaterialTextureValuesList.ToArray();

                debugViewMaterialGBufferStrings = debugViewMaterialGBufferStringsList.ToArray();
                debugViewMaterialGBufferValues  = debugViewMaterialGBufferValuesList.ToArray();

                isDebugViewMaterialInit = true;

                //raise warning if indexes collide
                unsafe
                {
                    if (CoreUnsafeUtils.HaveDuplicates(debugViewMaterialValues))
                    {
                        Debug.LogError("DebugMenu: debugViewMaterialValues have duplicate values. This will broke the runtime UI.");
                    }
                    if (CoreUnsafeUtils.HaveDuplicates(debugViewEngineValues))
                    {
                        Debug.LogError("DebugMenu: debugViewEngineValues have duplicate values. This will broke the runtime UI.");
                    }
                    if (CoreUnsafeUtils.HaveDuplicates(debugViewMaterialVaryingValues))
                    {
                        Debug.LogError("DebugMenu: debugViewMaterialVaryingValues have duplicate values. This will broke the runtime UI.");
                    }
                    if (CoreUnsafeUtils.HaveDuplicates(debugViewMaterialPropertiesValues))
                    {
                        Debug.LogError("DebugMenu: debugViewMaterialPropertiesValues have duplicate values. This will broke the runtime UI.");
                    }
                    if (CoreUnsafeUtils.HaveDuplicates(debugViewMaterialGBufferValues))
                    {
                        Debug.LogError("DebugMenu: debugViewMaterialGBufferValues have duplicate values. This will broke the runtime UI.");
                    }
                }
            }
        }