Camera.targetTexture和SetTargetBuffers的区别

知识点1:Camera.targetTexture

https://docs.unity3d.com/ScriptReference/Camera-targetTexture.html
public RenderTexture targetTexture;

usually cameras render directly to screen, but for some effects it is useful to make a camera render into a texture.
this is done by creating a RenderTexture object and setting it as targetTexture on the camera. the camera will then render into that texture.

when targetTexture is null, camera renders to screen.
when rendering into a texture, the camera always renders into the whole texture;
it is also possible to make camera render into separate RenderBuffers, or into multiple textures at once, using SetTargetBuffers function.

知识点2:Camera.ImageEffects

在这里插入图片描述
这里会有一个Camera.ImageEffects,这是后处理效果。我猜测是OnRenderImage的方法调用。
这是将TempBuffer中的内容拷贝到BackBuffer的过程。
而RenderTexture.ResolveAA则是因为相机开启了抗锯齿。如果我们把它关闭了,则不会有这行了。
在这里插入图片描述

知识点3:Camera.targetTexture和SetTargetBuffers的区别

如下面的代码是没有区别的:

using UnityEngine;

public class TestRenderTexture : MonoBehaviour
{
    public Camera m_camera;
    public RenderTexture rt;
    void Start()
    {
        rt = new RenderTexture(m_camera.pixelWidth, m_camera.pixelHeight, 16);
        rt.name = "xxx";
        m_camera.targetTexture = rt; //使用下面的代码是一样的效果,都是屏幕黑的,渲染到了rt上去。
        //camera.SetTargetBuffers(rt.colorBuffer, rt.depthBuffer);
    }
}

知识点4:RenderTexture.active

https://docs.unity3d.com/ScriptReference/RenderTexture-active.html
all rendering goes into the active RenderTexture. if the active RenderTexture is null everything is rendered in the main window.
setting the RenderTexture.active is the same as calling Graphics.SetRenderTarget.

将从render texture中读取数据:

using UnityEngine;
using System.Collections;

// Get the contents of a RenderTexture into a Texture2D
public class ExampleClass : MonoBehaviour
{
    static public Texture2D GetRTPixels(RenderTexture rt)
    {
        // Remember currently active render texture
        RenderTexture currentActiveRT = RenderTexture.active;
        // Set the supplied RenderTexture as the active one
        RenderTexture.active = rt;
        // Create a new Texture2D and read the RenderTexture image into it
        Texture2D tex = new Texture2D(rt.width, rt.height);
        tex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);

        // Restorie previously active render texture
        RenderTexture.active = currentActiveRT;
        return tex;
    }
}

摄像机的截图:
https://answers.unity.com/questions/27968/getpixels-of-rendertexture.html

Texture2D tex = new Texture2D(width, height, TextureFormat.RGB24, false);
 // ofc you probably don't have a class that is called CameraController :P
 Camera activeCamera = CameraController.getActiveCamera();
 // Initialize and render
 RenderTexture rt = new RenderTexture(width, height, 24);
 activeCamera.targetTexture = rt;
 activeCamera.Render();
 RenderTexture.active = rt;

 // Read pixels
 tex.ReadPixels(rectReadPicture, 0, 0);

 // Clean up
 activeCamera.targetTexture = null;
 RenderTexture.active = null; // added to avoid errors 
 DestroyImmediate(rt);

知识点5:Graphics.Blit函数

https://light11.hatenadiary.com/entry/2018/04/05/195745
https://docs.unity3d.com/ScriptReference/Graphics.Blit.html

举例1:

using UnityEngine;

public class SetTargetBuffers : MonoBehaviour
{
    public Camera m_camera;
    public RenderTexture rt;
    void Start()
    {
        rt = new RenderTexture(m_camera.pixelWidth, m_camera.pixelHeight, 0);
        rt.name = "xxx";
    }

    private void OnPostRender()
    {
        Graphics.Blit(null, rt);
    }
}

首先,我们看帧调试器:

在这里插入图片描述
这里多了个Grab RenderTexture。其实就是上面的blit的操作导致的。这里可以看到拷贝了RT0,还有一个深度:
在这里插入图片描述
这里注意的是,要将球体的位置,移动到0到1之间,这样好方便看到深度信息,如上图。
具体的项目源码在:https://gitee.com/yichichunshui/CommandBufferBlur.git

public static void Blit(Texture source, RenderTexture dest);
如果source为null,则是将backbuffer中的内容,作为source。
如果dest为null,则是将source的内容,经过处理之后,拷贝到backbuffer。

知识点6:OnPreRender和OnPostRender

这两个方法都是unity的生命周期函数,并且必须是脚本挂在摄像机上才会执行。
下面我们的一个需求是,将在摄像机渲染之前,将其内容渲染在rt上,然后在经过处理之后,在拷贝到屏幕上。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class OnPreAndPostRender : MonoBehaviour
{
    public RenderTexture rt;
    public Camera m_camera;
    private void Start()
    {
        rt = new RenderTexture(m_camera.pixelWidth, m_camera.pixelHeight, 16);
        rt.name = "xxx";
    }

    public void OnPreRender()
    {
        m_camera.targetTexture = rt;
    }

    public void OnPostRender()
    {
        m_camera.targetTexture = null;
    }
}

https://zhuanlan.zhihu.com/p/55537649
我又发现了一个大问题,创建rt的时候,一定要和抗锯齿的大小一致,所以最安全的写法:

using UnityEngine;

public class OnPreAndPostRender : MonoBehaviour
{
    public RenderTexture rt;
    public Camera m_camera;
    private void Start()
    {
        rt = new RenderTexture(m_camera.pixelWidth, m_camera.pixelHeight, 16);
        rt.antiAliasing = QualitySettings.antiAliasing > 0 ? QualitySettings.antiAliasing : 1; //这里考虑到不开启抗锯齿的情况
        rt.name = "xxx";
    }
	……
}

总结:

  1. rt的大小要和抗锯齿一致
  2. 使用rt的时候,要在OnPreRender中设置rt,在OnPostRender中设置摄像机的rt=null
  3. 使用SetTargetBuffers的时候,不需要在OnPostRender中设置rt=null。

补充:
Unity的RenderTexture类中: colorBuffer和depthBuffer的两个成员,在何时创建depthBuffer?
在这里插入图片描述
一个rendertexture里面当传递depth大于0的时候,unity会为你创建一个depthbuffer。当传递depth=0的时候,unity则不为你创建depthbuffer。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值