Unity的Graphic.Blit(Texture source, RenderTexture dest);

本文详细探讨了在Unity中使用Graphic.blit进行纹理绘制的过程,特别是如何通过调整MVP矩阵将一张贴图精确地贴到RenderTexture的指定区域。文章指出,Blit默认的MVP矩阵会导致源纹理绘制在右上角的1/4区域,通过自定义MVP矩阵并考虑源纹理和目标RenderTexture的尺寸比例及位置偏移,可以实现正确的纹理映射。
摘要由CSDN通过智能技术生成

这几天在细读Virtual texture代码,对里面如何将一张贴图贴到RT的指定区域比较感兴趣。

看了下主要是使用Graphic.blit这个API来实现:如下

    private void DrawTexture(Texture source, RenderTexture target, RectInt position)
    {
        if (source == null || target == null || m_DrawTextureShader == null)
            return;

        // 初始化绘制材质
        if (m_DrawTextureMateral == null)
            m_DrawTextureMateral = new Material(m_DrawTextureShader);
            
        // 构建变换矩阵
        float l = position.x * 2.0f / target.width - 1;
        float r = (position.x + position.width) * 2.0f / target.width - 1;
        float b = position.y * 2.0f / target.height - 1;
        float t = (position.y + position.height) * 2.0f / target.height - 1;
        var mat = new Matrix4x4();
        mat.m00 = r - l;
        mat.m03 = l;
        mat.m11 = t - b;
        mat.m13 = b;
        mat.m23 = -1;
        mat.m33 = 1;

        // 绘制贴图
        m_DrawTextureMateral.SetMatrix(Shader.PropertyToID("_ImageMVP"), GL.GetGPUProjectionMatrix(mat, true));

        target.DiscardContents();
        Graphics.Blit(source, target, m_DrawTextureMateral);
    }

 可以看到是通过修改blit时候使用的shader中的MVP矩阵来达到想要的效果。

这个API一开始让我认为是绘制的(-1,1),(1,-1),(-1,-1),(1,1)这四个点,然后MVP矩阵直接使用的identity,这样的话我只要将目标RT的缩放到source一样的大小,并且平移到source的位置就是想要的MVP矩阵

但事实并非如此,且得到的矩阵与上图中代码所写的并不一致。

于是为了搞懂原因,对Graphic.Blit做了测试,故意vert中针对顶点转换到clip空间的操作屏蔽,直接返回v.vertex:

            v2f_img vert (appdata_img v)
            {
                v2f_img o;
               // o.pos = mul(_ImageMVP, v.vertex);
                o.uv = v.texcoord;
				o.pos = v.vertex;
                return o;
            }

会发现,Blit会将source绘制到右上角的1/4。结合源码可以确定blit所绘制的mesh的四个点为(0,0),(0,1),(1,0),(1,1).

而正常使用时却能覆盖整个RT,因此可以推导出Blit的内置MVP矩阵所作的为*2-1的操作,也即MVP矩阵为:\begin{pmatrix} 2& 0& -1\\ 0& 2& -1\\ 0& 0& 1 \end{pmatrix}

知道了Blit的MVP后,再结合上面所说红色部分的就可以得到需要传入的修改后的MVP矩阵:

\begin{pmatrix} \frac{w_{0}}{w} & 0 &offset_{x} \\ 0& \frac{h_{0}}{h} & offset_{y}\\ 0& 0& 1 \end{pmatrix}\begin{pmatrix} 2& 0& -1\\ 0& 2& -1\\ 0& 0& 1 \end{pmatrix}  (注:假设source的宽和高为(w0,h0). RT的宽和高为(w,h).

 \frac{w_{0}}{w}的理由相对简单,只是将RT的大小缩放到source一样大。

offsetX和offsetY其实就是将缩放后的Rect平移到指定位置:如下图将黄色的矩阵平移到绿色的。

实际上就是求绿色的中心点所在坐标。

X很显然为(position.x+position.width/2)/target.width. 得到的范围为(0,1),对应到clip空间下需要*2-1. 因此X = (2*position.x + position.width)/target,width - 1.

Y类似。

代入,最后

 得到的即为代码中的矩阵(这里以3X3矩阵来做说明,因为不涉及到投影变换)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值