Ejemplo n.º 1
0
        public static void WriteTextureFileToDisk(Texture target, string filePath)
        {
            var rt   = target as RenderTexture;
            var cube = target as Cubemap;

            if (rt != null)
            {
                var t2D   = CopyRenderTextureToTexture2D(rt);
                var bytes = t2D.EncodeToEXR(Texture2D.EXRFlags.CompressZIP);
                HDBakingUtilities.CreateParentDirectoryIfMissing(filePath);
                File.WriteAllBytes(filePath, bytes);
                return;
            }
            else if (cube != null)
            {
                var t2D = new Texture2D(cube.width * 6, cube.height, GraphicsFormat.R16G16B16A16_SFloat, TextureCreationFlags.None);
                var cmd = new CommandBuffer {
                    name = "CopyCubemapToTexture2D"
                };
                for (int i = 0; i < 6; ++i)
                {
                    cmd.CopyTexture(
                        cube, i, 0, 0, 0, cube.width, cube.height,
                        t2D, 0, 0, cube.width * i, 0
                        );
                }
                Graphics.ExecuteCommandBuffer(cmd);
                var bytes = t2D.EncodeToEXR(Texture2D.EXRFlags.CompressZIP);
                HDBakingUtilities.CreateParentDirectoryIfMissing(filePath);
                File.WriteAllBytes(filePath, bytes);
                return;
            }
            throw new ArgumentException();
        }
        void DeleteCubemapAssets(bool deleteUnusedOnly)
        {
            var gameObjects = new List <GameObject>();
            var indices     = new List <int>();
            var scenes      = new List <Scene>();

            SceneObjectIDMap.GetAllIDsForAllScenes(
                HDBakingUtilities.SceneObjectCategory.ReflectionProbe,
                gameObjects, indices, scenes
                );

            var indicesSet = new HashSet <int>(indices);

            const int bufferLength = 1 << 10;
            var       bufferStart  = stackalloc byte[bufferLength];
            var       buffer       = new CoreUnsafeUtils.FixedBufferStringQueue(bufferStart, bufferLength);

            // Look for baked assets in scene folders
            for (int sceneI = 0, sceneC = SceneManager.sceneCount; sceneI < sceneC; ++sceneI)
            {
                var scene       = SceneManager.GetSceneAt(sceneI);
                var sceneFolder = HDBakingUtilities.GetBakedTextureDirectory(scene);
                if (!Directory.Exists(sceneFolder))
                {
                    continue;
                }

                var types = TypeInfo.GetEnumValues <ProbeSettings.ProbeType>();
                for (int typeI = 0; typeI < types.Length; ++typeI)
                {
                    var files = Directory.GetFiles(
                        sceneFolder,
                        HDBakingUtilities.HDProbeAssetPattern(types[typeI])
                        );
                    for (int fileI = 0; fileI < files.Length; ++fileI)
                    {
                        if (!HDBakingUtilities.TryParseBakedProbeAssetFileName(
                                files[fileI], out ProbeSettings.ProbeType fileProbeType, out int fileIndex
                                ))
                        {
                            continue;
                        }

                        // This file is a baked asset for a destroyed game object
                        // We can destroy it
                        if (!indicesSet.Contains(fileIndex) && deleteUnusedOnly
                            // Or we delete all assets
                            || !deleteUnusedOnly)
                        {
                            if (!buffer.TryPush(files[fileI]))
                            {
                                DeleteAllAssetsIn(ref buffer);
                            }
                        }
                    }
                }
            }
            DeleteAllAssetsIn(ref buffer);
        }
Ejemplo n.º 3
0
        internal static void RenderAndWriteToFile(
            HDProbe probe, string targetFile,
            RenderTexture cubeRT, RenderTexture planarRT
            )
        {
            var settings = probe.settings;

            switch (settings.type)
            {
            case ProbeSettings.ProbeType.ReflectionProbe:
            {
                var positionSettings = ProbeCapturePositionSettings.ComputeFrom(probe, null);
                HDRenderUtilities.Render(probe.settings, positionSettings, cubeRT,
                                         forceFlipY: true,
                                         forceInvertBackfaceCulling: true, // Cubemap have an RHS standard, so we need to invert the face culling
                                         (uint)StaticEditorFlags.ReflectionProbeStatic
                                         );
                HDBakingUtilities.CreateParentDirectoryIfMissing(targetFile);
                if (Provider.isActive && HDEditorUtils.IsAssetPath(targetFile))
                {
                    Checkout(targetFile, CheckoutMode.Both);
                }
                HDTextureUtilities.WriteTextureFileToDisk(cubeRT, targetFile);
                break;
            }

            case ProbeSettings.ProbeType.PlanarProbe:
            {
                var planarProbe      = (PlanarReflectionProbe)probe;
                var positionSettings = ProbeCapturePositionSettings.ComputeFromMirroredReference(
                    probe,
                    planarProbe.referencePosition
                    );

                HDRenderUtilities.Render(
                    settings,
                    positionSettings,
                    planarRT,
                    out var cameraSettings, out var cameraPositionSettings
                    );
                HDBakingUtilities.CreateParentDirectoryIfMissing(targetFile);
                if (Provider.isActive && HDEditorUtils.IsAssetPath(targetFile))
                {
                    Checkout(targetFile, CheckoutMode.Both);
                }
                HDTextureUtilities.WriteTextureFileToDisk(planarRT, targetFile);
                var renderData           = new HDProbe.RenderData(cameraSettings, cameraPositionSettings);
                var targetRenderDataFile = targetFile + ".renderData";
                if (Provider.isActive && HDEditorUtils.IsAssetPath(targetRenderDataFile))
                {
                    Checkout(targetRenderDataFile, CheckoutMode.Both);
                }
                HDBakingUtilities.TrySerializeToDisk(renderData, targetRenderDataFile);
                break;
            }
            }
        }
Ejemplo n.º 4
0
        internal static void RenderAndWriteToFile(
            HDProbe probe, string targetFile,
            RenderTexture cubeRT, RenderTexture planarRT
            )
        {
            var settings = probe.settings;

            switch (settings.type)
            {
            case ProbeSettings.ProbeType.ReflectionProbe:
            {
                var positionSettings = ProbeCapturePositionSettings.ComputeFrom(probe, null);
                HDRenderUtilities.Render(probe.settings, positionSettings, cubeRT,
                                         forceFlipY: true,
                                         forceInvertBackfaceCulling: true, // TODO: for an unknown reason, we need to invert the backface culling for baked reflection probes, Remove this
                                         (uint)StaticEditorFlags.ReflectionProbeStatic
                                         );
                HDBakingUtilities.CreateParentDirectoryIfMissing(targetFile);
                HDTextureUtilities.WriteTextureFileToDisk(cubeRT, targetFile);
                break;
            }

            case ProbeSettings.ProbeType.PlanarProbe:
            {
                var planarProbe      = (PlanarReflectionProbe)probe;
                var positionSettings = ProbeCapturePositionSettings.ComputeFromMirroredReference(
                    probe,
                    planarProbe.referencePosition
                    );

                HDRenderUtilities.Render(
                    settings,
                    positionSettings,
                    planarRT,
                    out CameraSettings cameraSettings, out CameraPositionSettings cameraPositionSettings
                    );
                HDBakingUtilities.CreateParentDirectoryIfMissing(targetFile);
                HDTextureUtilities.WriteTextureFileToDisk(planarRT, targetFile);
                var renderData = new HDProbe.RenderData(cameraSettings, cameraPositionSettings);
                HDBakingUtilities.TrySerializeToDisk(renderData, targetFile + ".renderData");
                break;
            }
            }
        }
 internal static void AssignRenderData(HDProbe probe, string bakedTexturePath)
 {
     switch (probe.settings.type)
     {
     case ProbeSettings.ProbeType.PlanarProbe:
     {
         var planarProbe = (PlanarReflectionProbe)probe;
         var dataFile    = bakedTexturePath + ".renderData";
         if (File.Exists(dataFile))
         {
             if (HDBakingUtilities.TryDeserializeFromDisk(dataFile, out HDProbe.RenderData renderData))
             {
                 HDProbeSystem.AssignRenderData(probe, renderData, ProbeSettings.Mode.Baked);
                 EditorUtility.SetDirty(probe);
             }
         }
         break;
     }
     }
 }
        internal static void RenderAndWriteToFile(
            HDProbe probe, string targetFile,
            RenderTexture cubeRT, RenderTexture planarRT
            )
        {
            var settings = probe.settings;

            switch (settings.type)
            {
            case ProbeSettings.ProbeType.ReflectionProbe:
            {
                var positionSettings = ProbeCapturePositionSettings.ComputeFrom(probe, null);
                HDRenderUtilities.Render(probe.settings, positionSettings, cubeRT, forceFlipY: true);
                HDBakingUtilities.CreateParentDirectoryIfMissing(targetFile);
                HDTextureUtilities.WriteTextureFileToDisk(cubeRT, targetFile);
                break;
            }

            case ProbeSettings.ProbeType.PlanarProbe:
            {
                var planarProbe      = (PlanarReflectionProbe)probe;
                var positionSettings = ProbeCapturePositionSettings.ComputeFromMirroredReference(
                    probe,
                    planarProbe.referencePosition
                    );

                HDRenderUtilities.Render(
                    settings,
                    positionSettings,
                    planarRT,
                    out CameraSettings cameraSettings, out CameraPositionSettings cameraPositionSettings
                    );
                HDBakingUtilities.CreateParentDirectoryIfMissing(targetFile);
                HDTextureUtilities.WriteTextureFileToDisk(planarRT, targetFile);
                var renderData = new HDProbe.RenderData(cameraSettings, cameraPositionSettings);
                HDBakingUtilities.TrySerializeToDisk(renderData, targetFile + ".renderData");
                break;
            }
            }
        }
        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);
        }
        public static bool BakeProbes(IList <HDProbe> bakedProbes)
        {
            if (!(RenderPipelineManager.currentPipeline is HDRenderPipeline hdPipeline))
            {
                Debug.LogWarning("HDBakedReflectionSystem work with HDRP, " +
                                 "please switch your render pipeline or use another reflection system");
                return(false);
            }

            var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize;
            var planarSize  = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.planarReflectionTextureSize;

            var cubeRT   = HDRenderUtilities.CreateReflectionProbeRenderTarget(cubemapSize);
            var planarRT = HDRenderUtilities.CreatePlanarProbeRenderTarget(planarSize);

            // Render and write the result to disk
            for (int i = 0; i < bakedProbes.Count; ++i)
            {
                var probe            = bakedProbes[i];
                var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                RenderAndWriteToFile(probe, bakedTexturePath, cubeRT, planarRT);
            }

            // 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 probe            = bakedProbes[i];
                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    AssetDatabase.ImportAsset(bakedTexturePath);
                    ImportAssetAt(probe, bakedTexturePath);
                }
                AssetDatabase.StopAssetEditing();
            }

            AssetDatabase.StartAssetEditing();
            for (int i = 0; i < bakedProbes.Count; ++i)
            {
                var probe            = bakedProbes[i];
                var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);

                // Get or create the baked texture asset for the probe
                var bakedTexture = AssetDatabase.LoadAssetAtPath <Texture>(bakedTexturePath);
                Assert.IsNotNull(bakedTexture, "The baked texture was imported before, " +
                                 "so it must exists in AssetDatabase");

                // Update import settings
                ImportAssetAt(probe, bakedTexturePath);
                probe.SetTexture(ProbeSettings.Mode.Baked, bakedTexture);
                AssignRenderData(probe, bakedTexturePath);
                EditorUtility.SetDirty(probe);
            }
            AssetDatabase.StopAssetEditing();

            cubeRT.Release();
            planarRT.Release();

            return(true);
        }
Ejemplo n.º 9
0
        public static bool BakeProbes(IList <HDProbe> bakedProbes)
        {
            if (!(RenderPipelineManager.currentPipeline is HDRenderPipeline hdPipeline))
            {
                Debug.LogWarning("HDBakedReflectionSystem work with HDRP, " +
                                 "please switch your render pipeline or use another reflection system");
                return(false);
            }

            var cubemapSize = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.reflectionCubemapSize;
            var planarSize  = (int)hdPipeline.currentPlatformRenderPipelineSettings.lightLoopSettings.planarReflectionTextureSize;

            var cubeRT   = HDRenderUtilities.CreateReflectionProbeRenderTarget(cubemapSize);
            var planarRT = HDRenderUtilities.CreatePlanarProbeRenderTarget(planarSize);

            // Render and write the result to disk
            for (int i = 0; i < bakedProbes.Count; ++i)
            {
                var probe            = bakedProbes[i];
                var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                RenderAndWriteToFile(probe, bakedTexturePath, cubeRT, planarRT);
            }

            // 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 probe            = bakedProbes[i];
                    var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);
                    AssetDatabase.ImportAsset(bakedTexturePath);
                    ImportAssetAt(probe, bakedTexturePath);
                }
                AssetDatabase.StopAssetEditing();
            }

            AssetDatabase.StartAssetEditing();
            for (int i = 0; i < bakedProbes.Count; ++i)
            {
                var probe            = bakedProbes[i];
                var bakedTexturePath = HDBakingUtilities.GetBakedTextureFilePath(probe);

                // Get or create the baked texture asset for the probe
                var bakedTexture = AssetDatabase.LoadAssetAtPath <Texture>(bakedTexturePath);
                Assert.IsNotNull(bakedTexture, "The baked texture was imported before, " +
                                 "so it must exists in AssetDatabase");

                // Update import settings
                ImportAssetAt(probe, bakedTexturePath);
                probe.SetTexture(ProbeSettings.Mode.Baked, bakedTexture);
                AssignRenderData(probe, bakedTexturePath);
                EditorUtility.SetDirty(probe);
            }
            AssetDatabase.StopAssetEditing();

            // case 1158677
            // The AssetPipeline will destroy and recreate the textures
            // So all transient data will be lost after the call to `AssetDatabase.StopAssetEditing`
            // Here, we increment the updateCount to with an arbitrary number to force the reflection probe cache
            // to update the texture.
            // updateCount is a transient data, so don't execute this code before the asset reload.
            {
                UnityEngine.Random.InitState((int)Time.realtimeSinceStartup);
                for (int i = 0; i < bakedProbes.Count; ++i)
                {
                    var probe = bakedProbes[i];
                    var c     = UnityEngine.Random.Range(2, 10);
                    while (probe.texture.updateCount < c)
                    {
                        probe.texture.IncrementUpdateCount();
                    }
                }
            }

            cubeRT.Release();
            planarRT.Release();

            return(true);
        }