当前位置:   article > 正文

Unity渲染(四):Shader着色器基础入门之获取当前屏幕贴图_unity shader将当前帧画面作为贴图

unity shader将当前帧画面作为贴图

Unity渲染(四):Shader着色器基础入门之获取当前屏幕贴图

通过这里,你会学习到怎么获取当前屏幕的贴图以及UV,通常用于屏幕的后处理。

上一章:Shader着色器基础入门之模糊(Blur)

开发环境:Unity5.0或者更高


在这里插入图片描述

通过获取屏幕贴图和uv,让屏幕的某个区域变亮

概述

1. 获取屏幕贴图
2. 获取屏幕UV
3. 完整代码
  • 1
  • 2
  • 3

1.1 获取屏幕贴图

Unity 内置GrabPass 来获取屏幕贴图,语法如下,代码写在SubShader里面。

Unity-GrabPass官方说明

GrabPass{"自定义贴图名称"}
  • 1

此Pass的作用是获取当前帧缓冲的内容。我们可以打开FrameDebugger看到

在这里插入图片描述


1.2 获取屏幕UV

Unity提供了一个接口用于获取物体在屏幕上的uv坐标
ComputeGrabScreenPos (float4 clipPos) ComputeGrabScreenPos 官方说明

他需要传入一个float4的坐标,这个坐标是裁剪空间的坐标,在shader可以通过UnityObjectToClipPos()接口获取
该函数定义在UnityCG.cginc, 使用之前需要引入这个文件

#include "UnityCG.cginc"
  • 1

他的函数原型是这样


inline float4 ComputeGrabScreenPos (float4 pos) {
    #if UNITY_UV_STARTS_AT_TOP
    float scale = -1.0;
    #else
    float scale = 1.0;
    #endif
    float4 o = pos * 0.5f;
    o.xy = float2(o.x, o.y*scale) + o.w;
#ifdef UNITY_SINGLE_PASS_STEREO
    o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endif
    o.zw = pos.zw;
    return o;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

代码说明

  1. #if UNITY_UV_STARTS_AT_TOP 因为在DX平台和OpenGl平台,坐标轴不一样,DX定义(0,0)为左上角,而OpenGl的定义(0,0)在左下角。防止图像翻转加上这个代码
  2. 我们首先要了解如何将坐标从裁剪空间转换到屏幕空间。中间过程有两步,先进行透视除法,将xyz值都除以w分量,让x,y,z的范围都处于[-1,1]之间,所谓透视除法主要是针对透视投影,对于正交投影这个w=1。之后将这个[-1,1]的坐标转换到屏幕空间,x坐标由[-1,1]->[0,屏幕宽度] ,y坐标由[-1,1]->[0,屏幕高度],这两步可以归结为以下公式

在这里插入图片描述

裁剪空间转为屏幕空间公式

但我们需要的是UV坐标,只需要转换到[0,1]即可,相当于上述公式的pixelWidth = 1,pixelHeight = 1,
当相机为正交投影时:上述公式clipw = 1 则带入可得到Unity源码中的float4 o = pos * 0.5f; o.xy = float2(o.x, o.y*scale) + o.w;,
当相机为透视投影时 源码使用TransformStereoScreenSpaceTex(o.xy, pos.w);进行处理,里面的代码是

float2 TransformStereoScreenSpaceTex(float2 uv, float w)
{
    float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex];
    return uv.xy * scaleOffset.xy + scaleOffset.zw * w;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

原理是将透视投影的相机平头截体向中间缩放挤压,变成和正交投影一样,在和正交投影一样处理。

最后我们需要再采样的时候将uv.xy / uv.w 因为我们再上面假设clipw =1了


1.3 完整代码

Shader "Toturial/ScreenGrab"
{
Properties
    {
        _MainTex("MainTex",2D) = "white"{}
    }

    SubShader
    {
        GrabPass{"_bTexture"}
        Tags{"Queue"="Transparent"}
        Pass
        {
            CGPROGRAM
            #include "UnityCG.cginc"
            #pragma vertex vert
            #pragma fragment frag

            sampler2D _MainTex;
            sampler2D _bTexture;

            struct a2v
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 pos   : SV_POSITION;
                float4 grabPos : TEXCOORD1;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeScreenPos(o.pos);
                return o;
            }

            fixed4 frag(v2f i) : SV_TARGET
            {
                fixed4 screenColor = tex2D(_bTexture, i.grabPos.xy / i.grabPos.w);
                return screenColor * 2;

            }

            ENDCG
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

最终得到效果

在这里插入图片描述

最终效果
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号