#if UNITY_EDITOR using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using HTraceWSGI.Scripts.PipelinesConfigurator; using UnityEditor; using UnityEngine; using UnityEngine.Rendering; using Object = System.Object; using UnityEngine.Rendering.HighDefinition; namespace HTraceWSGI.Scripts.Patcher { internal static class HPatcher { private static bool IsGlobalSettingsWithHtraceResources() { RenderPipelineGlobalSettings globalSettings = GraphicsSettings.GetSettingsForRenderPipeline(); #if UNITY_2022_2_OR_NEWER && !UNITY_6000_0_OR_NEWER object hdrpResourcesField = globalSettings.GetType().GetField("m_RenderPipelineResources", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(globalSettings); object shadersObj = hdrpResourcesField.GetType().GetField("shaders")?.GetValue(hdrpResourcesField); object ssgi = shadersObj?.GetType().GetField("screenSpaceGlobalIlluminationCS")?.GetValue(shadersObj); return ssgi != null&& ssgi.ToString().Contains("HTrace"); #endif #if UNITY_6000_0_OR_NEWER object msettingsObject = globalSettings.GetType().GetField("m_Settings", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(globalSettings); object settingsListObject = msettingsObject?.GetType().GetField("m_SettingsList", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(msettingsObject); object mListObject = settingsListObject?.GetType().GetField("m_List", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(settingsListObject); object hdRenderPipelineRuntimeShadersObject = null; FieldInfo ssaoComputeFieldInfo = null; foreach (object obj in (IList)mListObject) { if (obj.GetType().Name.Contains("HDRenderPipelineRuntimeShaders")) { ssaoComputeFieldInfo = obj.GetType().GetField("m_ScreenSpaceGlobalIlluminationCS", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); hdRenderPipelineRuntimeShadersObject = obj; } } object computeValue = ssaoComputeFieldInfo.GetValue(hdRenderPipelineRuntimeShadersObject); //it may be null return hdRenderPipelineRuntimeShadersObject != null && ssaoComputeFieldInfo != null && computeValue != null && ((ComputeShader)computeValue).name.Contains("HTrace"); #endif } //Project settings - Global Settings - Resources public static void RenderPipelineRuntimeResourcesPatch(bool forceReplace = false) { if (IsGlobalSettingsWithHtraceResources() == true) return; CreateRpResourcesFolders(); CopyAndChangeSSGICompute(forceReplace: forceReplace); #if UNITY_2022_2_OR_NEWER && !UNITY_6000_0_OR_NEWER //new SetNewRuntimeResourcesInUnity(); //old // { // GetHDRenderPipelineRuntimeResources(out UnityEngine.Object localRuntimeResourcesObject); //todo we can avoid copied resources and change it directly // ReplaceSSGIComputeInLocalResources(localRuntimeResourcesObject); // SetNewRuntimeResources(localRuntimeResourcesObject); // } #endif #if UNITY_6000_0_OR_NEWER SetNewRuntimeResourcesInUnity6000(); #endif } private static void CreateRpResourcesFolders() { if (!Directory.Exists(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources"))) { Directory.CreateDirectory(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources")); AssetDatabase.Refresh(); } if (!Directory.Exists(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "HDRP"))) { Directory.CreateDirectory(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "HDRP")); AssetDatabase.Refresh(); } // if (!Directory.Exists(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "URP"))) // { // Directory.CreateDirectory(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "URP")); // AssetDatabase.Refresh(); // } // if (!Directory.Exists(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "BIRP"))) // { // Directory.CreateDirectory(Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "BIRP")); // AssetDatabase.Refresh(); // } } public static void GlobalSettingsPlayerResourcesRestore() { #if UNITY_6000_0_OR_NEWER RenderPipelineGlobalSettings globalSettings = GraphicsSettings.GetSettingsForRenderPipeline(); object msettingsObject = globalSettings.GetType().GetField("m_Settings", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(globalSettings); object settingsListObject = msettingsObject?.GetType().GetField("m_SettingsList", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(msettingsObject); object mListObject = settingsListObject?.GetType().GetField("m_List", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(settingsListObject); object hdRenderPipelineRuntimeShadersObject = null; FieldInfo ssgiComputeFieldInfo = null; foreach (object obj in (IList)mListObject) { if (obj.GetType().Name.Contains("HDRenderPipelineRuntimeShaders")) { ssgiComputeFieldInfo = obj.GetType().GetField("m_ScreenSpaceGlobalIlluminationCS", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); hdRenderPipelineRuntimeShadersObject = obj; } } string originalSsgiComputePath = Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "HDRP Resources", "ScreenSpaceGlobalIlluminationOriginal.compute"); string ssgiComputeRelativePath = Path.Combine("Assets", Path.GetRelativePath(Application.dataPath, originalSsgiComputePath)).ReplaceLeftSlashesToRight(); Object originalSsgiComputeObject = AssetDatabase.LoadMainAssetAtPath(ssgiComputeRelativePath); ssgiComputeFieldInfo?.SetValue(hdRenderPipelineRuntimeShadersObject, originalSsgiComputeObject); #endif } private static void CopyAndChangeSSGICompute(bool revert = false, bool forceReplace = false) { string ssgiComputeFullPath = Path.Combine(ConfiguratorUtils.GetFullHdrpPath(), "Runtime", "Lighting", "ScreenSpaceLighting", "ScreenSpaceGlobalIllumination.compute"); string ssgiComputeHtraceFullPath = Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "HDRP", "ScreenSpaceGlobalIlluminationHTrace.compute"); if (File.Exists(ssgiComputeHtraceFullPath) && forceReplace == false) { return; } try { File.Copy(ssgiComputeFullPath, ssgiComputeHtraceFullPath, true); } catch (Exception e) { Debug.LogError($"{ConfiguratorUtils.GetUnityAndHdrpVersion()} \n" + $"Source path: {ssgiComputeFullPath} \n" + $"Destination path: {ssgiComputeHtraceFullPath} \n" + $"{e.Message}"); return; } string[] pattern1 = { "// deferred opaque always use FPTL", "#define USE_FPTL_LIGHTLIST 1", "", "// HDRP generic includes", }; string[] newpattern1 = { "// deferred opaque always use FPTL", "#define USE_FPTL_LIGHTLIST 1", "", "#pragma multi_compile _ HTRACE_OVERRIDE", "// HDRP generic includes", }; string[] pattern2 = { "// Input depth pyramid texture", "TEXTURE2D_X(_DepthTexture);", "// Stencil buffer of the current frame", "TEXTURE2D_X_UINT2(_StencilTexture);", "// Input texture that holds the offset for every level of the depth pyramid", "StructuredBuffer _DepthPyramidMipLevelOffsets;", "", "// Constant buffer that holds all scalar that we need", "CBUFFER_START(UnityScreenSpaceGlobalIllumination)", }; string[] newpattern2 = { "// Input depth pyramid texture", "TEXTURE2D_X(_DepthTexture);", "// Stencil buffer of the current frame", "TEXTURE2D_X_UINT2(_StencilTexture);", "// Input texture that holds the offset for every level of the depth pyramid", "StructuredBuffer _DepthPyramidMipLevelOffsets;", "// HTrace buffer", "TEXTURE2D_X(_HTraceBufferGI);", "", "// Constant buffer that holds all scalar that we need", "CBUFFER_START(UnityScreenSpaceGlobalIllumination)", }; string[] pattern3 = { "[numthreads(INDIRECT_DIFFUSE_TILE_SIZE, INDIRECT_DIFFUSE_TILE_SIZE, 1)]", "void TRACE_GLOBAL_ILLUMINATION(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)", "{", " UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);", "", " // Compute the pixel position to process", " uint2 currentCoord = dispatchThreadId.xy;", " uint2 inputCoord = dispatchThreadId.xy;", }; string[] newpattern3 = { "[numthreads(INDIRECT_DIFFUSE_TILE_SIZE, INDIRECT_DIFFUSE_TILE_SIZE, 1)]", "void TRACE_GLOBAL_ILLUMINATION(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)", "{", " UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);", "", "#if defined HTRACE_OVERRIDE", " return;", "#endif", " // Compute the pixel position to process", " uint2 currentCoord = dispatchThreadId.xy;", " uint2 inputCoord = dispatchThreadId.xy;", }; string[] pattern4 = { "[numthreads(INDIRECT_DIFFUSE_TILE_SIZE, INDIRECT_DIFFUSE_TILE_SIZE, 1)]", "void REPROJECT_GLOBAL_ILLUMINATION(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)", "{", " UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);", "", " // Compute the pixel position to process", " uint2 inputCoord = dispatchThreadId.xy;", " uint2 currentCoord = dispatchThreadId.xy;", }; string[] newpattern4 = { "[numthreads(INDIRECT_DIFFUSE_TILE_SIZE, INDIRECT_DIFFUSE_TILE_SIZE, 1)]", "void REPROJECT_GLOBAL_ILLUMINATION(uint3 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint2 groupId : SV_GroupID)", "{", " UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);", "", "#if defined HTRACE_OVERRIDE", " _IndirectDiffuseTextureRW[COORD_TEXTURE2D_X(dispatchThreadId.xy)] = LOAD_TEXTURE2D_X(_HTraceBufferGI, dispatchThreadId.xy).xyz;", " return;", "#endif", " // Compute the pixel position to process", " uint2 inputCoord = dispatchThreadId.xy;", " uint2 currentCoord = dispatchThreadId.xy;", }; List patterns = new List() { pattern1, pattern2, pattern3, pattern4, }; List newpatterns = new List() { newpattern1, newpattern2, newpattern3, newpattern4, }; List resultLines = new List(); if(revert == false) PatcherUtils.ReplacePatterns(ssgiComputeHtraceFullPath, patterns, newpatterns, ref resultLines); else PatcherUtils.ReplacePatterns(ssgiComputeHtraceFullPath, newpatterns, patterns, ref resultLines); File.WriteAllLines(ssgiComputeHtraceFullPath, resultLines); AssetDatabase.Refresh(); } private static void SetNewRuntimeResourcesInUnity() { RenderPipelineGlobalSettings globalSettings = GraphicsSettings.GetSettingsForRenderPipeline(); string runtimeResourcePath = Path.Combine(ConfiguratorUtils.GetFullHdrpPath(), "Runtime", "RenderPipelineResources", "HDRenderPipelineRuntimeResources.asset"); string runtimeResourcesRelativePath = Path.Combine("Assets", Path.GetRelativePath(Application.dataPath, runtimeResourcePath)).ReplaceLeftSlashesToRight(); UnityEngine.Object unityRuntimeResourcesObject = AssetDatabase.LoadMainAssetAtPath(runtimeResourcesRelativePath); string ssgiFullPath = Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "HDRP", "ScreenSpaceGlobalIlluminationHTrace.compute"); string ssgiRelativePath = Path.Combine("Assets", Path.GetRelativePath(Application.dataPath, ssgiFullPath)).ReplaceLeftSlashesToRight(); UnityEngine.Object ssgiObject = AssetDatabase.LoadMainAssetAtPath(ssgiRelativePath); object hdrpResourcesObj = globalSettings.GetType().GetField("m_RenderPipelineResources", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(globalSettings); object shadersObj = hdrpResourcesObj.GetType().GetField("shaders")?.GetValue(hdrpResourcesObj); FieldInfo ssgiField = shadersObj?.GetType().GetField("screenSpaceGlobalIlluminationCS"); ssgiField?.SetValue(shadersObj, ssgiObject); } private static void SetNewRuntimeResourcesInUnity6000() { RenderPipelineGlobalSettings globalSettings = GraphicsSettings.GetSettingsForRenderPipeline(); object msettingsObject = globalSettings.GetType().GetField("m_Settings", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(globalSettings); object settingsListObject = msettingsObject?.GetType().GetField("m_SettingsList", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(msettingsObject); object mListObject = settingsListObject?.GetType().GetField("m_List", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(settingsListObject); object hdRenderPipelineRuntimeShadersObject = null; object hdrpRayTracingResourcesObject = null; FieldInfo ssgiComputeFieldInfo = null; string ssgiComputePath = Path.Combine(ConfiguratorUtils.GetHTraceFolderPath(), "RP Resources", "HDRP", "ScreenSpaceGlobalIlluminationHTrace.compute"); string ssgiComputeRelativePath = Path.Combine("Assets", Path.GetRelativePath(Application.dataPath, ssgiComputePath)).ReplaceLeftSlashesToRight(); Object gtaoComputeObject = AssetDatabase.LoadMainAssetAtPath(ssgiComputeRelativePath); foreach (object obj in (IList)mListObject) { if (obj.GetType().Name.Contains("HDRenderPipelineRuntimeShaders")) { ssgiComputeFieldInfo = obj.GetType().GetField("m_ScreenSpaceGlobalIlluminationCS", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); hdRenderPipelineRuntimeShadersObject = obj; } } ssgiComputeFieldInfo?.SetValue(hdRenderPipelineRuntimeShadersObject, gtaoComputeObject); AssetDatabase.ImportAsset(ssgiComputeRelativePath, ImportAssetOptions.ForceUpdate); } } } #endif