屏幕捕捉纹理教程 VR资源

东方喵 2017-12-06 17:17:49

今天教主给大家介绍一下,我们的小可爱GrabPass——屏幕捕捉纹理,简单的说,可以理解为在shader中的作用相当于Unity中的RenderTexture。先上code,再解释:

 
01
02
03
04
05
06
07
08
09
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
52
53
54
55
56
57
58
59
60
61
Shader "东方喵/可爱的GrabPass"   [/color][/size][/font][/backcolor][font=微软雅黑][size=3][color=#000000][backcolor=rgb(250, 250, 250)][/backcolor][backcolor=rgb(250, 250, 250)]{ 
        Properties
        {
        _NormalMap("法线图", 2D) = "bump" {}
        }
 
    SubShader 
    
        ZWrite Off  
        GrabPass 
        {   
            "_GrabTex"//【注1】
        
 
        Pass 
        
            Tags 
            {  
                "RenderType" = "Transparent" 
                "Queue" = "Transparent+1" 
            
 
            CGPROGRAM     
            #include "UnityCG.cginc" 
                        sampler2D _NormalMap;
                        float4 _GrabTex_TexelSize;//抓屏贴图的[backcolor=rgba(128, 128, 128, 0.0470588)]纹素大小
                        sampler2D _GrabTex;//抓屏贴图
 
 
                        struct appdata {
                                float4 vertex : POSITION;
                                float2 uv : TEXCOORD0;
                        };
                        struct v2f
                        {
                                float4 pos : SV_POSITION;
                                float2 uv : TEXCOORD0;
                                float4 uv0 : TEXCOORD1;
                        };
 
                        v2f vert(appdata v)
                        {
                                v2f o;
                                o.pos = UnityObjectToClipPos(v.vertex);//【注2】
                                o.uv = v.uv;
                                o.uv0 = ComputeGrabScreenPos(o.pos);//【注3】
                                return o;
                        }
 
            fixed4 frag(v2f i) : SV_Target 
            
                                float3 bump = UnpackNormal(tex2D(_NormalMap, i.uv));//【注4】
                                float2 offset = bump.rg * _GrabTex_TexelSize.rg *25* sin(_Time.g);
                                fixed4 o = tex2D(_GrabTex, (i.uv0.rg + offset) / i.uv0.a);
                                return o-fixed4(0.1,0.1,0.1,0);
            
            #pragma vertex vert 
            #pragma fragment frag 
            ENDCG 
        
    
}

 

 


解释:
【注1】
此处给出一个抓屏贴图的名称,抓屏的贴图就可以通过这张贴图来获取,如果此处为空,则默认抓屏到_GrabTexture中。

【注2】

等价于:mul(UNITY_MATRIX_MVP, float4(pos, 1.0))

【注3】
此句为计算该模型顶点在屏幕坐标的纹理信息,目的为获取模型后方的屏幕纹理,否则将获取全屏的纹理,unity封装的UnityCG.cginc代码中有:
 
01
02
03
04
05
06
07
08
09
10
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;
      o.zw = pos.zw;
      return o;
    }

【注4】
unity封装的UnityCG.cginc代码中有:
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
inline fixed3 UnpackNormal(fixed4 packednormal)
{
#if defined(UNITY_NO_DXT5nm)
    return packednormal.xyz * 2 - 1;
#else
    return UnpackNormalDXT5nm(packednormal);
#endif
}
inline fixed3 UnpackNormalDXT5nm (fixed4 packednormal)
{
    fixed3 normal;
    normal.xy = packednormal.wy * 2 - 1;
    normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
    return normal;
}

这里有两个方法,以UnpackNormal方法来说,它最主要的也就是 
packednormal.xyz * 2 - 1; 
要解释这个,就必须讲到法线纹理的生成。法线纹理是把模型的法线信息存到图片中去,每条法线的x,y,z对应的存到每个像素的r,g,b中。每条法线里的每个数值都是一个[-1,1]的闭合区间里,像素的每个数值则都是在[0,255]中,(n + vec3(1.0,1.0,1.0)) * (255.0 / 2.0),每个法线向量,经过加上 vec3(1.0,1.0,1.0)。变成[0,2]的闭合区间里,然后除以2,再乘以255,发现向量,就会转换成了[0,255]里的数值。这也是上述那条公式的由来。 
至于法线纹理如何生成,有兴趣的可以详细了解一下这个算法,各个软件的生成算法不一样,最终得到的法线纹理也不一样。但是纹理里的数据,肯定是符合规范的法线纹理数据,可以在shader中使用。 
另外一个方法UnpackNormalDXT5nm ,则是一个压缩法线纹理后的方法。大家都知道,法线是一个单位向量,也就是它的长度是1,所以只需要知道x,y的数值,是可以计算得到z的数值的,z=1-(x+y)的平方。这样就可以减少贴图的大小,减少GPU的数据传输量。
99VR视界二维码
热门推荐
Hot Recommended
在线客服