/// <summary> /// Compute a hash of the settings. /// </summary> /// <returns>The computed hash.</returns> public Hash128 ComputeHash() { var h = new Hash128(); var h2 = new Hash128(); HashUtilities.ComputeHash128(ref type, ref h); HashUtilities.ComputeHash128(ref mode, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref lighting, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref proxySettings, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref cameraSettings, ref h2); HashUtilities.AppendHash(ref h2, ref h); if (influence != null) { h2 = influence.ComputeHash(); HashUtilities.AppendHash(ref h2, ref h); } if (proxy != null) { h2 = proxy.ComputeHash(); HashUtilities.AppendHash(ref h2, ref h); } return(h); }
#pragma warning restore 618 internal Hash128 GetHash() { var h = new Hash128(); var h2 = new Hash128(); HashUtilities.ComputeHash128(ref bufferClearing, ref h); HashUtilities.ComputeHash128(ref culling, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref customRenderingSettings, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref defaultFrameSettings, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref flipYMode, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref frustum, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref invertFaceCulling, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref probeLayerMask, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref probeRangeCompressionFactor, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref renderingPathCustomFrameSettings, ref h2); HashUtilities.AppendHash(ref h2, ref h); HashUtilities.ComputeHash128(ref renderingPathCustomFrameSettingsOverrideMask, ref h2); HashUtilities.AppendHash(ref h2, ref h); int volumeHash = volumes.GetHashCode(); h2 = new Hash128((ulong)volumeHash, 0); HashUtilities.AppendHash(ref h2, ref h); return(h); }
public override int GetHashCode() { var h = new Hash128(); HashUtilities.AppendHash(ref m_SceneObjectsHash, ref h); HashUtilities.AppendHash(ref m_SkySettingsHash, ref h); HashUtilities.AppendHash(ref m_AmbientProbeHash, ref h); return(h.GetHashCode()); }
internal static Hash128 CreateWindowAndStageIdentifier(string windowGUID, Stage stage) { Hash128 hash = stage.GetHashForStateStorage(); Hash128 windowHash = Hash128.Compute(windowGUID); Hash128 stageTypeHash = Hash128.Compute(stage.GetType().FullName); HashUtilities.AppendHash(ref windowHash, ref hash); HashUtilities.AppendHash(ref stageTypeHash, ref hash); return(hash); }
public static Hash128 NUVHash(Vector3 n, Vector2 uv) { Hash128 res = new Hash128(); HashUtilities.QuantisedVectorHash(ref n, ref res); Hash128 uvHash = new Hash128(); Vector3 uv3 = new Vector3(uv.x, uv.y, 0.0f); HashUtilities.QuantisedVectorHash(ref uv3, ref uvHash); HashUtilities.AppendHash(ref uvHash, ref res); return(res); }
static void ComputeProbeSettingsHashes(IList <HDProbe> probes, HDProbeBakingState *states) { for (int i = 0; i < probes.Count; ++i) { var probe = probes[i]; var positionSettings = ProbeCapturePositionSettings.ComputeFrom(probe, null); var positionSettingsHash = positionSettings.ComputeHash(); // TODO: make ProbeSettings and unmanaged type so its hash can be the hash of its memory var probeSettingsHash = probe.settings.ComputeHash(); HashUtilities.AppendHash(ref positionSettingsHash, ref probeSettingsHash); states[i].probeSettingsHash = probeSettingsHash; } }
/// <summary>Combine all of the hashes of a collection of hashes.</summary> /// <typeparam name="TValue">Value type.</typeparam> /// <typeparam name="TGetter">Getter type.</typeparam> /// <param name="count">Number of hash to combine.</param> /// <param name="hashes">Hashes to combine.</param> /// <param name="outHash">Hash to update.</param> public static void CombineHashes <TValue, TGetter>(int count, void *hashes, Hash128 *outHash) where TValue : struct where TGetter : struct, IKeyGetter <TValue, Hash128> { var getter = new TGetter(); for (int i = 0; i < count; ++i) { var v = UnsafeUtility.ReadArrayElement <TValue>(hashes, i); var h = getter.Get(ref v); HashUtilities.AppendHash(ref h, ref *outHash); } }
static void ComputeProbeSettingsHashes(IEnumerable <HDProbe> probes, HDProbeBakingState *states) { var i = 0; foreach (var probe in probes) { var positionSettings = ProbeCapturePositionSettings.ComputeFrom(probe, null); var positionSettingsHash = positionSettings.ComputeHash(); // TODO: make ProbeSettings and unmanaged type so its hash can be the hash of its memory var probeSettingsHash = probe.settings.ComputeHash(); HashUtilities.AppendHash(ref positionSettingsHash, ref probeSettingsHash); states[i].probeSettingsHash = probeSettingsHash; ++i; } }
public static Hash128 RefreshCustomIndexers() { Hash128 globalIndexersHash = default; foreach (var customIndexerMethodInfo in TypeCache.GetMethodsWithAttribute <CustomObjectIndexerAttribute>()) { var name = $"{customIndexerMethodInfo.DeclaringType.FullName}.{customIndexerMethodInfo.Name}"; if (SearchSettings.disabledIndexers.Contains(name)) { continue; } try { var customIndexerAttribute = customIndexerMethodInfo.GetCustomAttribute <CustomObjectIndexerAttribute>(); var indexerType = customIndexerAttribute.type; if (indexerType == null) { continue; } if (!ValidateCustomIndexerMethodSignature(customIndexerMethodInfo)) { continue; } if (!(Delegate.CreateDelegate(typeof(CustomIndexerHandler), customIndexerMethodInfo) is CustomIndexerHandler customIndexerAction)) { continue; } if (!s_CustomObjectIndexers.TryGetValue(indexerType, out var indexerList)) { indexerList = new List <CustomIndexerHandler>(); s_CustomObjectIndexers.Add(indexerType, indexerList); } indexerList.Add(customIndexerAction); var customIndexerHash = ComputeCustomIndexerHash(customIndexerMethodInfo, customIndexerAttribute); HashUtilities.AppendHash(ref customIndexerHash, ref globalIndexersHash); } catch (Exception ex) { Debug.LogWarning($"Cannot load CustomObjectIndexer with method: {customIndexerMethodInfo.Name} ({ex.Message})"); } } return(globalIndexersHash); }
void ImportXml(string xmlPath, out VisualTreeAsset vta) { vta = ScriptableObject.CreateInstance <VisualTreeAsset>(); vta.visualElementAssets = new List <VisualElementAsset>(); vta.templateAssets = new List <TemplateAsset>(); var h = new Hash128(); using (var stream = File.OpenRead(xmlPath)) { int readCount = 0; byte[] b = new byte[1024 * 16]; while ((readCount = stream.Read(b, 0, b.Length)) > 0) { for (int i = readCount; i < b.Length; i++) { b[i] = 0; } Hash128 blockHash = new Hash128(); HashUtilities.ComputeHash128(b, ref blockHash); HashUtilities.AppendHash(ref blockHash, ref h); } } vta.contentHash = h.GetHashCode(); XDocument doc; try { doc = XDocument.Load(xmlPath, LoadOptions.SetLineInfo); } catch (Exception e) { logger.LogError(ImportErrorType.Syntax, ImportErrorCode.InvalidXml, e, Error.Level.Fatal, null); return; } LoadXmlRoot(doc, vta); StyleSheet inlineSheet = ScriptableObject.CreateInstance <StyleSheet>(); inlineSheet.name = "inlineStyle"; m_Builder.BuildTo(inlineSheet); vta.inlineSheet = inlineSheet; }
public Hash128 ComputeHash() { var h = new Hash128(); var h2 = new Hash128(); HashUtilities.QuantisedVectorHash(ref proxyPosition, ref h); HashUtilities.QuantisedVectorHash(ref referencePosition, ref h2); HashUtilities.AppendHash(ref h2, ref h); var euler = proxyRotation.eulerAngles; HashUtilities.QuantisedVectorHash(ref euler, ref h2); HashUtilities.AppendHash(ref h2, ref h); euler = referenceRotation.eulerAngles; HashUtilities.QuantisedVectorHash(ref euler, ref h2); HashUtilities.AppendHash(ref h2, ref h); return(h); }
public void Append(float[] values, int count) { if (values == null) { return; } // Pre-2020 versions of Unity don't have Hash128.Append() (can only hash strings and scalars) // For these versions, we'll hash element by element. #if UNITY_2020_1_OR_NEWER m_Hash.Append(values, 0, count); #else for (var i = 0; i < count; i++) { var tempHash = new Hash128(); HashUtilities.ComputeHash128(ref values[i], ref tempHash); HashUtilities.AppendHash(ref tempHash, ref m_Hash); } #endif }
static void LoadCustomObjectIndexers() { Hash128 globalIndexersHash = default; foreach (var customIndexerMethodInfo in Utils.GetAllMethodsWithAttribute <CustomObjectIndexerAttribute>()) { var customIndexerAttribute = customIndexerMethodInfo.GetCustomAttribute <CustomObjectIndexerAttribute>(); var indexerType = customIndexerAttribute.type; if (indexerType == null) { continue; } if (!ValidateCustomIndexerMethodSignature(customIndexerMethodInfo)) { continue; } if (!(Delegate.CreateDelegate(typeof(CustomIndexerHandler), customIndexerMethodInfo) is CustomIndexerHandler customIndexerAction)) { continue; } if (!s_CustomObjectIndexers.TryGetValue(indexerType, out var indexerList)) { indexerList = new List <CustomIndexerHandler>(); s_CustomObjectIndexers.Add(indexerType, indexerList); } indexerList.Add(customIndexerAction); var customIndexerHash = ComputeCustomIndexerHash(customIndexerMethodInfo, customIndexerAttribute); HashUtilities.AppendHash(ref customIndexerHash, ref globalIndexersHash); } #if UNITY_2020_1_OR_NEWER if (!AssetDatabaseAPI.IsAssetImportWorkerProcess()) { EditorApplication.delayCall += () => AssetDatabaseAPI.RegisterCustomDependency(nameof(CustomObjectIndexerAttribute), globalIndexersHash); } #endif }
void ImportXml(string xmlPath, out VisualTreeAsset vta) { var h = new Hash128(); using (var stream = File.OpenRead(xmlPath)) { int readCount = 0; byte[] b = new byte[1024 * 16]; while ((readCount = stream.Read(b, 0, b.Length)) > 0) { for (int i = readCount; i < b.Length; i++) { b[i] = 0; } Hash128 blockHash = new Hash128(); HashUtilities.ComputeHash128(b, ref blockHash); HashUtilities.AppendHash(ref blockHash, ref h); } } CreateVisualTreeAsset(out vta, h); XDocument doc; try { doc = XDocument.Load(xmlPath, LoadOptions.SetLineInfo); } catch (Exception e) { logger.LogError(ImportErrorType.Syntax, ImportErrorCode.InvalidXml, e, Error.Level.Fatal, null); return; } LoadXmlRoot(doc, vta); TryCreateInlineStyleSheet(vta); }
public void Append(string value) { var tempHash = Hash128.Compute(value); HashUtilities.AppendHash(ref tempHash, ref m_Hash); }
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 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); }