咱們知道在屏幕後處理裏面經過 Graphics.Blit 函數能夠經過材質處理屏幕圖片, 當咱們想要處理通常圖片的時候, 直接調用GL函數就好了, 按照習慣本身封裝一個 Blit 方法 : html
public static void Blit(Texture source, Material material, RenderTexture destination, int materialPass = 0) { if(material.SetPass(materialPass)) { material.mainTexture = source; Graphics.SetRenderTarget(destination); GL.PushMatrix(); GL.LoadOrtho(); GL.Begin(GL.QUADS); { Vector3 coords = new Vector3(0, 0, 0); GL.TexCoord(coords); GL.Vertex(coords); coords = new Vector3(1, 0, 0); GL.TexCoord(coords); GL.Vertex(coords); coords = new Vector3(1, 1, 0); GL.TexCoord(coords); GL.Vertex(coords); coords = new Vector3(0, 1, 0); GL.TexCoord(coords); GL.Vertex(coords); } GL.End(); GL.PopMatrix(); } }
由於 Graphics.SetRenderTarget 方法傳入的是 RenderTexture, 渲染出來的 RenderTexture 不能直接當成 Texture2D 或 Cubemap 或 Texture3D 等來使用, 通常須要進行二次轉換. 就拿 Texture2D 來做爲例子, 轉換方法貌似有那麼幾種, 下來看看 : ide
0. 各個變量函數
public Material material; public Texture2D input; public Texture2D outPutTex2D; public RenderTexture renderTexture;
1. 使用指針的方式, 通常來講若是 RenderTexture 的內存跟 Texture2D 同樣的話, 用 Texture2D 直接指向 RenderTexture 的相關地址應該就能夠了, 由於官方沒有文檔直接就測試代碼 : 測試
private void Start() { if(renderTexture == false) { renderTexture = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); } renderTexture.hideFlags = HideFlags.DontSave; outPutTex2D = Texture2D.CreateExternalTexture(Screen.width, Screen.height, TextureFormat.ARGB32, false, true, renderTexture.GetNativeTexturePtr()); // ArgumentException: nativeTex can not be null }
在渲染 RenderTexture 以前獲取它的 GetNativeTexturePtr 是不行的, 報錯. 改一下, 在渲染完以後再獲取的話 : spa
private void Start() { if(renderTexture == false) { renderTexture = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); } renderTexture.hideFlags = HideFlags.DontSave; Blit(input, material, renderTexture); var nativeTexturePtr = renderTexture.GetNativeTexturePtr(); if(nativeTexturePtr != System.IntPtr.Zero) { outPutTex2D = Texture2D.CreateExternalTexture(Screen.width, Screen.height, TextureFormat.ARGB32, false, true, nativeTexturePtr); } }
直接就崩了, 雖然斷點看到它的 nativeTexturePtr 確實能獲取到, 不過想到 RenderTexture 在建立的時候沒有指定是哪一種內存, 直接用指針來建立 Texture2D 應該就是會崩的吧.3d
由於官方文檔啥也沒寫, 估計這條路走不通...指針
2. 使用 Texture2D.ReadPixels 方法, 這個是最多見的方法 : rest
private void Start() { int W = (int)Screen.width; int H = (int)Screen.height; if(renderTexture == false) { renderTexture = RenderTexture.GetTemporary(W, H, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); } renderTexture.hideFlags = HideFlags.DontSave; outPutTex2D = new Texture2D(W, H, TextureFormat.ARGB32, false, true); Blit(input, material, renderTexture); var current = RenderTexture.active; RenderTexture.active = renderTexture; outPutTex2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0); outPutTex2D.Apply(); RenderTexture.active = current; }
這個最經常使用, 結果也是正確的沒什麼好說的, 只是效率堪憂code
3. 調用 Graphics.CopyTexture 複製圖片 : orm
private void Start() { int W = (int)Screen.width; int H = (int)Screen.height; if(renderTexture == false) { renderTexture = RenderTexture.GetTemporary(W, H, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); } renderTexture.hideFlags = HideFlags.DontSave; outPutTex2D = new Texture2D(W, H, TextureFormat.ARGB32, false, true); Blit(input, material, renderTexture); if((SystemInfo.copyTextureSupport & UnityEngine.Rendering.CopyTextureSupport.RTToTexture) != 0) { Graphics.CopyTexture(renderTexture, outPutTex2D); } }
這個應該就是上面的使用指針地址進行復制的封裝, 效率槓槓的. 並且也不須要對應類型.
PS : 在官方文檔裏面看見一句話
Compressed texture formats add some restrictions to the CopyTexture with a region variant. For example, PVRTC formats are not supported since they are not block-based (for these formats you can only copy whole texture or whole mip level). For block-based formats (e.g. DXT, ETC), the region size and coordinates must be a multiple of compression block size (4 pixels for DXT).
If both source and destination textures are marked as "readable" (i.e. copy of data exists in system memory for reading/writing on the CPU), these functions copy it as well.
第一句是廢話, 不是對應的大小引擎都不讓你壓縮, 第二句話括號裏的意思是說打開了 reading/writing 的圖片, 會在系統內存裏面存在副本, 那麼就是雙倍的內存佔用了麼? 趕忙測試一下...
沒錯, 正是如此......雖然圖片導入設置自動就是不打開Read/Write的, 之後仍是注意一下的好...