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

相关文章
相关标签/搜索