| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- using System.Collections.Generic;
- using UnityEngine.Assertions;
- namespace UnityEngine.Rendering.PostProcessing
- {
- class TextureLerper
- {
- static TextureLerper m_Instance;
- internal static TextureLerper instance
- {
- get
- {
- if (m_Instance == null)
- m_Instance = new TextureLerper();
- return m_Instance;
- }
- }
- CommandBuffer m_Command;
- PropertySheetFactory m_PropertySheets;
- PostProcessResources m_Resources;
- List<RenderTexture> m_Recycled;
- List<RenderTexture> m_Actives;
- TextureLerper()
- {
- m_Recycled = new List<RenderTexture>();
- m_Actives = new List<RenderTexture>();
- }
- internal void BeginFrame(PostProcessRenderContext context)
- {
- m_Command = context.command;
- m_PropertySheets = context.propertySheets;
- m_Resources = context.resources;
- }
- internal void EndFrame()
- {
- // Release any remaining RT in the recycled list
- if (m_Recycled.Count > 0)
- {
- foreach (var rt in m_Recycled)
- RuntimeUtilities.Destroy(rt);
- m_Recycled.Clear();
- }
- // There's a high probability that RTs will be requested in the same order on next
- // frame so keep them in the same order
- if (m_Actives.Count > 0)
- {
- foreach (var rt in m_Actives)
- m_Recycled.Add(rt);
- m_Actives.Clear();
- }
- }
- RenderTexture Get(RenderTextureFormat format, int w, int h, int d = 1, bool enableRandomWrite = false, bool force3D = false)
- {
- RenderTexture rt = null;
- int i, len = m_Recycled.Count;
- for (i = 0; i < len; i++)
- {
- var r = m_Recycled[i];
- if (r.width == w && r.height == h && r.volumeDepth == d && r.format == format && r.enableRandomWrite == enableRandomWrite && (!force3D || (r.dimension == TextureDimension.Tex3D)))
- {
- rt = r;
- break;
- }
- }
- if (rt == null)
- {
- var dimension = (d > 1) || force3D
- ? TextureDimension.Tex3D
- : TextureDimension.Tex2D;
- rt = new RenderTexture(w, h, 0, format)
- {
- dimension = dimension,
- filterMode = FilterMode.Bilinear,
- wrapMode = TextureWrapMode.Clamp,
- anisoLevel = 0,
- volumeDepth = d,
- enableRandomWrite = enableRandomWrite
- };
- rt.Create();
- }
- else m_Recycled.RemoveAt(i);
- m_Actives.Add(rt);
- return rt;
- }
- internal Texture Lerp(Texture from, Texture to, float t)
- {
- Assert.IsNotNull(from);
- Assert.IsNotNull(to);
- Assert.AreEqual(from.width, to.width);
- Assert.AreEqual(from.height, to.height);
- // Saves a potentially expensive fullscreen blit when using dirt textures & the likes
- if (from == to)
- return from;
- // Don't need to lerp boundary conditions
- if (t <= 0f) return from;
- if (t >= 1f) return to;
- bool is3D = from is Texture3D
- || (from is RenderTexture && ((RenderTexture)from).volumeDepth > 1);
- RenderTexture rt;
- // 3D texture blending is a special case and only works on compute enabled platforms
- if (is3D)
- {
- int dpth = @from is Texture3D ? ((Texture3D) @from).depth : ((RenderTexture) @from).volumeDepth;
- int size = Mathf.Max(from.width, from.height);
- size = Mathf.Max(size, dpth);
-
- rt = Get(RenderTextureFormat.ARGBHalf, from.width, from.height, dpth, true, true);
- var compute = m_Resources.computeShaders.texture3dLerp;
- int kernel = compute.FindKernel("KTexture3DLerp");
- m_Command.SetComputeVectorParam(compute, "_DimensionsAndLerp", new Vector4(from.width, from.height, dpth, t));
- m_Command.SetComputeTextureParam(compute, kernel, "_Output", rt);
- m_Command.SetComputeTextureParam(compute, kernel, "_From", from);
- m_Command.SetComputeTextureParam(compute, kernel, "_To", to);
- uint tgsX, tgsY, tgsZ;
- compute.GetKernelThreadGroupSizes(kernel, out tgsX, out tgsY, out tgsZ);
- Assert.AreEqual(tgsX, tgsY);
- int groupSizeXY = Mathf.CeilToInt(size / (float)tgsX);
- int groupSizeZ = Mathf.CeilToInt(size / (float)tgsZ);
- m_Command.DispatchCompute(compute, kernel, groupSizeXY, groupSizeXY, groupSizeZ);
- return rt;
- }
- // 2D texture blending
- // We could handle textures with different sizes by picking the biggest one to avoid
- // popping effects. This would work in most cases but will still pop if one texture is
- // wider but shorter than the other. Generally speaking you're expected to use same-size
- // textures anyway so we decided not to handle this case at the moment, especially since
- // it would waste a lot of texture memory as soon as you start using bigger textures
- // (snow ball effect).
- var format = TextureFormatUtilities.GetUncompressedRenderTextureFormat(to);
- rt = Get(format, to.width, to.height);
- var sheet = m_PropertySheets.Get(m_Resources.shaders.texture2dLerp);
- sheet.properties.SetTexture(ShaderIDs.To, to);
- sheet.properties.SetFloat(ShaderIDs.Interp, t);
- m_Command.BlitFullscreenTriangle(from, rt, sheet, 0);
- return rt;
- }
- internal Texture Lerp(Texture from, Color to, float t)
- {
- Assert.IsNotNull(from);
- if (t < 0.00001)
- return from;
- bool is3D = from is Texture3D
- || (from is RenderTexture && ((RenderTexture)from).volumeDepth > 1);
- RenderTexture rt;
- // 3D texture blending is a special case and only works on compute enabled platforms
- if (is3D)
- {
- int dpth = @from is Texture3D ? ((Texture3D) @from).depth : ((RenderTexture) @from).volumeDepth;
- int size = Mathf.Max(from.width, from.height);
- size = Mathf.Max(size, dpth);
-
- rt = Get(RenderTextureFormat.ARGBHalf, from.width, from.height, dpth, true, true);
- var compute = m_Resources.computeShaders.texture3dLerp;
- int kernel = compute.FindKernel("KTexture3DLerpToColor");
- m_Command.SetComputeVectorParam(compute, "_DimensionsAndLerp", new Vector4(from.width, from.height, dpth, t));
- m_Command.SetComputeVectorParam(compute, "_TargetColor", new Vector4(to.r, to.g, to.b, to.a));
- m_Command.SetComputeTextureParam(compute, kernel, "_Output", rt);
- m_Command.SetComputeTextureParam(compute, kernel, "_From", from);
- int groupSize = Mathf.CeilToInt(size / 4f);
- m_Command.DispatchCompute(compute, kernel, groupSize, groupSize, groupSize);
- return rt;
- }
- // 2D texture blending
- // We could handle textures with different sizes by picking the biggest one to avoid
- // popping effects. This would work in most cases but will still pop if one texture is
- // wider but shorter than the other. Generally speaking you're expected to use same-size
- // textures anyway so we decided not to handle this case at the moment, especially since
- // it would waste a lot of texture memory as soon as you start using bigger textures
- // (snow ball effect).
- var format = TextureFormatUtilities.GetUncompressedRenderTextureFormat(from);
- rt = Get(format, from.width, from.height);
- var sheet = m_PropertySheets.Get(m_Resources.shaders.texture2dLerp);
- sheet.properties.SetVector(ShaderIDs.TargetColor, new Vector4(to.r, to.g, to.b, to.a));
- sheet.properties.SetFloat(ShaderIDs.Interp, t);
- m_Command.BlitFullscreenTriangle(from, rt, sheet, 1);
- return rt;
- }
-
-
- internal void Clear()
- {
- foreach (var rt in m_Actives)
- RuntimeUtilities.Destroy(rt);
- foreach (var rt in m_Recycled)
- RuntimeUtilities.Destroy(rt);
- m_Actives.Clear();
- m_Recycled.Clear();
- }
- }
- }
|