經過GL函數處理圖片以及其它相關功能

  咱們知道在屏幕後處理裏面經過 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);
        }
    }

  這個應該就是上面的使用指針地址進行復制的封裝, 效率槓槓的. 並且也不須要對應類型.

 

  

Graphics.CopyTexture

  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的, 之後仍是注意一下的好...

相關文章
相關標籤/搜索