【Unity Shader入門(mén)精要學(xué)習(xí)】高級(jí)紋理(三)

渲染紋理

現(xiàn)代的GPU允許把整個(gè)三維場(chǎng)景渲染到一個(gè)中間緩沖中,即渲染目標(biāo)紋理(Render Target Texture RTT),而不是傳統(tǒng)的幀緩沖或是后備緩沖(backbuffer)。與之相關(guān)的是多重渲染目標(biāo)(Multiple Render Target, MRT),這種技術(shù)指的是GPU允許我們把場(chǎng)景同時(shí)渲染到多個(gè)渲染目標(biāo)紋理中,而不再需要為每個(gè)渲染目標(biāo)紋理單獨(dú)渲染完整的場(chǎng)景。延遲渲染就是使用多重渲染目標(biāo)的一個(gè)應(yīng)用。
Unity為渲染目標(biāo)紋理定義了一種專(zhuān)門(mén)的紋理類(lèi)型——渲染紋理(Render Texture)。Unity渲染紋理有兩種使用方法:
1、在Project下創(chuàng)建一個(gè)渲染紋理,然后將其賦給某個(gè)攝像機(jī),創(chuàng)建的渲染紋理可以調(diào)整分標(biāo)率,濾波模式。這樣攝像機(jī)渲染的結(jié)果會(huì)實(shí)時(shí)更新到這張紋理下。(這種方式也可以通過(guò)寫(xiě)代碼的方式)
2、在屏幕后處理時(shí)使用GrabPass,命令,或是OnRenderImage函數(shù)獲取當(dāng)前屏幕圖像。Unity會(huì)把這個(gè)屏幕圖像放到一張和屏幕分辨率等同的渲染紋理中,然后就可以在Pass中把它當(dāng)成普通的紋理使用就可以,用來(lái)實(shí)現(xiàn)各種屏幕特效。

鏡子效果

其實(shí)鏡子效果的實(shí)現(xiàn)就是在“鏡子”的后面放置一個(gè)攝像機(jī),然后把這個(gè)攝像機(jī)看到的東西畫(huà)在“鏡子”上(就是講這個(gè)攝像機(jī)的RenderTexure當(dāng)成正常的紋理畫(huà)在某個(gè)面上),需要注意的是“鏡子”與主相機(jī)看到的實(shí)際是鏡面的,也就是反過(guò)來(lái)的,所以UV坐標(biāo)需要在X方向上翻轉(zhuǎn)一下。


鏡子效果
Shader "Unlit/Mirror"
{
    Properties
    {
        _MainTex ("Render Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct a2v
            {
                float4 vertex : POSITION;
                float3 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float2 uv:TEXCOORD0;
            };

            sampler2D _MainTex;

            v2f vert (a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                o.uv.x = 1-o.uv.x;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

玻璃效果

當(dāng)我們?cè)赟hader中定義一個(gè)GrabPass之后,Unity會(huì)把當(dāng)前屏幕的圖像繪制在一張紋理中,我們可以再后續(xù)的Pass中訪問(wèn)這張紋理。通常會(huì)使用GrabPass來(lái)實(shí)現(xiàn)諸如玻璃等透明材質(zhì)的模擬,使用GrabPass可以對(duì)該物體后面的圖像進(jìn)行更復(fù)雜的操作,如使用法線模擬折射效果。
在使用GrabPass時(shí)需要注意物體的渲染隊(duì)列設(shè)置,GrabPass通常用于渲染透明物體,盡管代碼里面并不包含混合指令,但仍需要把渲染隊(duì)列設(shè)置成透明隊(duì)列:

Tags{"RenderType"="Opaque" "Queue"="Transparent"}

這樣能保證在畫(huà)這個(gè)物體時(shí)其他不透明的物體已經(jīng)繪制完了。


玻璃
Shader "Unlit/GlassRefraction"
{
    Properties{
        _MainTex("Main Tex",2D)="white"{}
        _BumpTex("Bump Tex",2D)="bump"{}
        _Cubemap("Envirenment Tex",Cube)="_SkyBox"{}
        _Distortion("Distortion",Range(0,100))=50
        _RefractionAmount("Refraction Amount",Range(0,1))=0.5
    }

    SubShader{
        Tags{"RenderType"="Opaque" "Queue"="Transparent"}

        GrabPass{"_RefractionTex"}
        Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;

            sampler2D _BumpTex;
            float4 _BumpTex_ST;

            samplerCUBE _Cubemap;

            float _Distortion;
            fixed _RefractionAmount;

            sampler2D _RefractionTex;
            float4 _RefractionTex_TexelSize;

            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 scrPos : TEXCOORD0;
                float4 uv : TEXCOORD1;
                float4 TtoW0 : TEXCOORD2;
                float4 TtoW1 : TEXCOORD3;
                float4 TtoW2 : TEXCOORD4;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.scrPos = ComputeGrabScreenPos(o.pos);
                o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
                o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpTex);

                float3 worldPos = mul(unity_ObjectToWorld,v.vertex);
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                float3 worldTangent = UnityObjectToWorldDir(v.tangent);
                float3 worldBinormal = cross(normalize(worldTangent),normalize(worldNormal))*v.tangent.w;

                o.TtoW0 = float4(worldTangent.x,worldBinormal.x,worldNormal.x,worldPos.x);
                o.TtoW1 = float4(worldTangent.y,worldBinormal.y,worldNormal.y,worldPos.y);
                o.TtoW2 = float4(worldTangent.z,worldBinormal.z,worldNormal.z,worldPos.z);

                return o;
            }

            fixed4 frag(v2f i):SV_TARGET
            {
                float3 worldPos = float3(i.TtoW0.z,i.TtoW1.z,i.TtoW2.z);
                float3 worldViewDir = UnityWorldSpaceViewDir(worldPos);

                //切線空間
                fixed3 bump = UnpackNormal(tex2D(_BumpTex,i.uv.zw));
                //在切線空間對(duì)法線進(jìn)行偏移,得出偏移的像素?cái)?shù)量,_RefractionTex_TexelSize代表素紋大小
                //如256X512的紋理,素紋大小就是(1/256,1/512)
                float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
                //然后對(duì)屏幕空間XY值進(jìn)行偏移,很疑惑為什么還要乘一次Z值,感覺(jué)不乘也可以
                i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;

                fixed3 refractColor = tex2D(_RefractionTex,i.scrPos.xy/i.scrPos.w).rgb;
                fixed3 diffuseColor = tex2D(_MainTex,i.uv.xy).rgb;

                fixed3 worldBump = normalize(half3(dot(bump,i.TtoW0.xyz),dot(bump,i.TtoW1.xyz),dot(bump,i.TtoW2.xyz)));
                fixed3 reflectDir = reflect(-worldViewDir,worldBump);

                fixed3 reflectColor = texCUBE(_Cubemap,reflectDir).rgb * diffuseColor;

                fixed3 finalColor = reflectColor * (1-_RefractionAmount) + refractColor * _RefractionAmount;

                return fixed4(finalColor,1.0);
            }

            ENDCG
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容