noradninja

GlobalGrabOnce

Mar 3rd, 2026
43
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.13 KB | None | 0 0
  1. using UnityEngine;
  2. using UnityEngine.Rendering;
  3.  
  4. [RequireComponent(typeof(Camera))]
  5. public class GlobalGrabOnce : MonoBehaviour
  6. {
  7.     [Header("Global Texture A (e.g. AfterForwardOpaque)")]
  8.     public string globalTextureNameA = "_GlobalGrabTexture";
  9.     public CameraEvent copyEventA = CameraEvent.AfterForwardOpaque;
  10.     public GrabResolution resolutionA = GrabResolution.Full;
  11.  
  12.     [Header("Global Texture B (e.g. After Everything)")]
  13.     public string globalTextureNameB = "_GlobalGrabTextureAfterAll";
  14.     public CameraEvent copyEventB = CameraEvent.BeforeImageEffects;
  15.     public GrabResolution resolutionB = GrabResolution.Full;
  16.  
  17.     [Header("Optional Processing for Global Texture B")]
  18.     public bool processB = true;
  19.     public Material processBMaterial; // postprocessing material (expects _MainTex)
  20.  
  21.     public FilterMode filterMode = FilterMode.Bilinear;
  22.  
  23.     public enum GrabResolution
  24.     {
  25.         Full,   // 1
  26.         Half,   // 2
  27.         Quarter // 4
  28.     }
  29.  
  30.     Camera _cam;
  31.  
  32.     CommandBuffer _cbA;
  33.     CommandBuffer _cbB;
  34.  
  35.     RenderTexture _rtA;
  36.     RenderTexture _rtB;
  37.  
  38.     // Temp for processing B (screen -> temp -> processed -> B)
  39.     RenderTexture _rtBTemp;
  40.  
  41.     int _wA, _hA;
  42.     int _wB, _hB;
  43.     int _wBTemp, _hBTemp;
  44.  
  45.     void OnEnable()
  46.     {
  47.         _cam = GetComponent<Camera>();
  48.         CreateOrResizeRTs();
  49.         BuildCommandBuffers();
  50.     }
  51.  
  52.     void OnDisable()
  53.     {
  54.         Cleanup();
  55.     }
  56.  
  57.     void Update()
  58.     {
  59.         CreateOrResizeRTs();
  60.     }
  61.  
  62.     int GetDivisor(GrabResolution res)
  63.     {
  64.         switch (res)
  65.         {
  66.             default:
  67.             case GrabResolution.Full: return 1;
  68.             case GrabResolution.Half: return 2;
  69.             case GrabResolution.Quarter: return 4;
  70.         }
  71.     }
  72.  
  73.     void CreateOrResizeRTs()
  74.     {
  75.         if (_cam == null) return;
  76.  
  77.         CreateOrResizeSingle(
  78.             resolutionA,
  79.             ref _rtA,
  80.             ref _wA,
  81.             ref _hA,
  82.             globalTextureNameA,
  83.             "GlobalGrabOnceRT_A"
  84.         );
  85.  
  86.         CreateOrResizeSingle(
  87.             resolutionB,
  88.             ref _rtB,
  89.             ref _wB,
  90.             ref _hB,
  91.             globalTextureNameB,
  92.             "GlobalGrabOnceRT_B"
  93.         );
  94.  
  95.         // Only allocate temp if we are actually processing B
  96.         if (processB && processBMaterial != null)
  97.         {
  98.             CreateOrResizeSingle(
  99.                 resolutionB,
  100.                 ref _rtBTemp,
  101.                 ref _wBTemp,
  102.                 ref _hBTemp,
  103.                 "_Unused_GlobalGrabOnceTempB",
  104.                 "GlobalGrabOnceRT_B_Temp"
  105.             );
  106.         }
  107.         else
  108.         {
  109.             if (_rtBTemp != null)
  110.             {
  111.                 _rtBTemp.Release();
  112.                 DestroyImmediate(_rtBTemp);
  113.                 _rtBTemp = null;
  114.                 _wBTemp = _hBTemp = 0;
  115.             }
  116.         }
  117.  
  118.         // If command buffers already exist, rebuild to bind new RTs
  119.         if (_cbA != null || _cbB != null)
  120.             BuildCommandBuffers();
  121.     }
  122.  
  123.     void CreateOrResizeSingle(
  124.         GrabResolution resolution,
  125.         ref RenderTexture rt,
  126.         ref int wCache,
  127.         ref int hCache,
  128.         string globalName,
  129.         string debugName
  130.     )
  131.     {
  132.         int div = GetDivisor(resolution);
  133.         int w = Mathf.Max(1, _cam.pixelWidth / div);
  134.         int h = Mathf.Max(1, _cam.pixelHeight / div);
  135.  
  136.         if (rt != null && w == wCache && h == hCache)
  137.             return;
  138.  
  139.         wCache = w;
  140.         hCache = h;
  141.  
  142.         if (rt != null)
  143.         {
  144.             rt.Release();
  145.             DestroyImmediate(rt);
  146.         }
  147.  
  148.         rt = new RenderTexture(w, h, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default);
  149.         rt.name = debugName;
  150.         rt.filterMode = filterMode;
  151.         rt.wrapMode = TextureWrapMode.Clamp;
  152.         rt.useMipMap = false;
  153.         rt.autoGenerateMips = false;
  154.         rt.Create();
  155.  
  156.         // Only publish globals for the actual A/B textures (skip temps)
  157.         if (!string.IsNullOrEmpty(globalName) && globalName[0] == '_'
  158.             && (globalName == globalTextureNameA || globalName == globalTextureNameB))
  159.         {
  160.             Shader.SetGlobalTexture(globalName, rt);
  161.             Shader.SetGlobalVector(globalName + "_TexelSize",
  162.                 new Vector4(1f / w, 1f / h, w, h));
  163.         }
  164.     }
  165.  
  166.     void BuildCommandBuffers()
  167.     {
  168.         if (_cam == null || _rtA == null || _rtB == null)
  169.             return;
  170.  
  171.         // Remove old
  172.         if (_cbA != null)
  173.         {
  174.             _cam.RemoveCommandBuffer(copyEventA, _cbA);
  175.             _cbA.Release();
  176.             _cbA = null;
  177.         }
  178.  
  179.         if (_cbB != null)
  180.         {
  181.             _cam.RemoveCommandBuffer(copyEventB, _cbB);
  182.             _cbB.Release();
  183.             _cbB = null;
  184.         }
  185.  
  186.         // A: simple copy
  187.         _cbA = new CommandBuffer();
  188.         _cbA.name = "GlobalGrabOnce Copy A";
  189.         _cbA.Blit(BuiltinRenderTextureType.CurrentActive, _rtA);
  190.         _cam.AddCommandBuffer(copyEventA, _cbA);
  191.  
  192.         // B: copy or copy+process
  193.         _cbB = new CommandBuffer();
  194.         _cbB.name = (processB && processBMaterial != null) ? "GlobalGrabOnce Copy+Process B" : "GlobalGrabOnce Copy B";
  195.  
  196.         if (processB && processBMaterial != null)
  197.         {
  198.             // If temp isn't available for some reason, fall back to copy
  199.             if (_rtBTemp != null)
  200.             {
  201.                 _cbB.Blit(BuiltinRenderTextureType.CurrentActive, _rtBTemp);
  202.                 _cbB.Blit(_rtBTemp, _rtB, processBMaterial);
  203.             }
  204.             else
  205.             {
  206.                 _cbB.Blit(BuiltinRenderTextureType.CurrentActive, _rtB);
  207.             }
  208.         }
  209.         else
  210.         {
  211.             _cbB.Blit(BuiltinRenderTextureType.CurrentActive, _rtB);
  212.         }
  213.  
  214.         _cam.AddCommandBuffer(copyEventB, _cbB);
  215.  
  216.         // Refresh globals
  217.         Shader.SetGlobalTexture(globalTextureNameA, _rtA);
  218.         Shader.SetGlobalTexture(globalTextureNameB, _rtB);
  219.  
  220.         Shader.SetGlobalVector(globalTextureNameA + "_TexelSize",
  221.             new Vector4(1f / _wA, 1f / _hA, _wA, _hA));
  222.  
  223.         Shader.SetGlobalVector(globalTextureNameB + "_TexelSize",
  224.             new Vector4(1f / _wB, 1f / _hB, _wB, _hB));
  225.     }
  226.  
  227.     void Cleanup()
  228.     {
  229.         if (_cam != null)
  230.         {
  231.             if (_cbA != null) _cam.RemoveCommandBuffer(copyEventA, _cbA);
  232.             if (_cbB != null) _cam.RemoveCommandBuffer(copyEventB, _cbB);
  233.         }
  234.  
  235.         if (_cbA != null)
  236.         {
  237.             _cbA.Release();
  238.             _cbA = null;
  239.         }
  240.  
  241.         if (_cbB != null)
  242.         {
  243.             _cbB.Release();
  244.             _cbB = null;
  245.         }
  246.  
  247.         if (_rtA != null)
  248.         {
  249.             _rtA.Release();
  250.             DestroyImmediate(_rtA);
  251.             _rtA = null;
  252.         }
  253.  
  254.         if (_rtB != null)
  255.         {
  256.             _rtB.Release();
  257.             DestroyImmediate(_rtB);
  258.             _rtB = null;
  259.         }
  260.  
  261.         if (_rtBTemp != null)
  262.         {
  263.             _rtBTemp.Release();
  264.             DestroyImmediate(_rtBTemp);
  265.             _rtBTemp = null;
  266.         }
  267.     }
  268. }
  269.  
Advertisement
Add Comment
Please, Sign In to add comment