GrabPass捕捉螢幕紋理

來源:互聯網
上載者:User

標籤:

轉自:http://blog.sina.com.cn/s/blog_89d90b7c0102va4m.html

最近在看熱扭曲效果,裡面用到了GrabPass。

之前看過官方翻譯版本的說明http://blog.sina.com.cn/s/blog_89d90b7c01019run.html

但是還是無法理解GrabPass{}是捕捉物體後面的螢幕紋理,還是整個螢幕的紋理,至於為什麼,可以看下面的例子,如果你知道原因求分享。。。

 

1.固定管線版本:

Shader "Custom/Grab" { Properties {  //_MainTex ("Base (RGB)", 2D) = "white" {} } SubShader {  // 在所有不透明對象之後繪製自己,更加靠近螢幕  Tags { "Queue" = "Transparent" }  // 通道1:捕捉對象之後的螢幕內容放到_GrabTexture紋理中  GrabPass{}  // 通道2:設定材質  Pass{   // 使用上面產生的紋理,進行顏色反相(1-原材質色)   SetTexture[_GrabTexture]{combine one-texture}  } } FallBack "Diffuse"}

 

效果如下,它是模數型背後的螢幕紋理:

2.頂點,片段版本:

Shader "Custom/GrabAllVF" { Properties {  //_MainTex ("Base (RGB)", 2D) = "white" {} } SubShader {  // 在所有不透明對象之後繪製自己,更加靠近螢幕  Tags{"Queue"="Transparent"}  // 通道1:捕捉螢幕內容放到_GrabTexture紋理中  GrabPass{}   // 通道2:設定材質  Pass{   Name "pass2"   CGPROGRAM   #pragma vertex vert            #pragma fragment frag   #include "UnityCG.cginc"   sampler2D _GrabTexture;   float4 _GrabTexture_ST;   // 片段程式的輸入   struct v2f {                float4  pos : POSITION;                float2  uv : TEXCOORD0;            };   v2f vert (appdata_base v)            {                v2f o;                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);    o.uv = TRANSFORM_TEX(v.texcoord, _GrabTexture);                return o;            }   float4 frag (v2f i) : COLOR            {    half4 texCol = tex2D(_GrabTexture, float2(1-i.uv.x , 1-i.uv.y));    // 顏色反相,便於觀察效果                return 1 - texCol;            }   ENDCG  } } FallBack "Diffuse"}

 

效果如下:取到的是全屏的紋理:

1和2為什麼取到的螢幕紋理不一樣呢?

 

3.使用vf的方式,只擷取物體後面的螢幕紋理,後面的扭曲效果會用到此方式,代碼如下:

Shader "Custom/GrabVF" { Properties {  //_MainTex ("Base (RGB)", 2D) = "white" {} } SubShader {  // 在所有不透明對象之後繪製自己,更加靠近螢幕  Tags{"Queue"="Transparent"}  // 通道1:捕捉對象之後的螢幕內容放到_GrabTexture紋理中  GrabPass{}   // 通道2:設定材質  Pass{   Name "pass2"   CGPROGRAM   #pragma vertex vert            #pragma fragment frag   #include "UnityCG.cginc"   sampler2D _GrabTexture;   float4 _GrabTexture_ST;   struct v2f {                float4  pos : POSITION; // 輸入的模型空間中,頂點座標資訊                float4  uv : TEXCOORD0; // 材質資訊也包含了xyzw,通常只用xy,但是這裡由頂點產生            };   v2f vert (appdata_base v)            {                v2f o;    // 從模型座標-全局座標-視座標-(視覺平截體乘以投影矩陣並進行透視除法)-剪裁座標                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);    // 【自動產生紋理】通過輸出的pos計算的紋理資訊    // 【解決平台差異】D3D原點在頂部(本機需要讓y縮放乘以-1),openGL在底部                #if UNITY_UV_STARTS_AT_TOP    float scale = -1.0;    #else    float scale = 1.0;    #endif    // pos的範圍是【-1,1】+1為【0,2】,乘以0.5變成uv的範圍【0,1】    // 不清楚為什麼這樣寫,但是標準的寫法就是這樣    o.uv.xy = (float2(o.pos.x, o.pos.y*scale) + o.pos.w) * 0.5;    o.uv.zw = o.pos.zw;                  return o;            }   float4 frag (v2f i) : COLOR            {    // 對_GrabTexture紋理進行取樣,進行2D紋理映射尋找,後面傳入的一定要四元紋理座標。    // UNITY_PROJ_COORD傳入四元紋理座標用於給tex2Dproj讀取,但是多數平台上,返回一樣的值。    // 【自動產生的紋理UV】類型是float4,使用如下方式進行2D紋理映射尋找    //half4 texCol = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uv));    // 也可以使用tex2D進行採樣,但是【自動產生的紋理UV】時必須要除以w轉為齊次座標    float last_x = i.uv.x / i.uv.w;    float last_y = i.uv.y / i.uv.w;     half4 texCol = tex2D(_GrabTexture, float2(last_x, last_y));    // 顏色反相,便於觀察效果                return 1 - texCol;            }   ENDCG  } } FallBack "Diffuse"}

 

沒法一口吃個大胖子,學到這裡才發現底層渲染原理很多都不瞭解,還的再仔細看看基礎知識才行啊。

 

註:

補充於2015年1月4日,來自一位網友的提示。

2中的確是將螢幕的紋理賦值到樣本對象GrabTexture上,所以前面的模型顯示整個螢幕的紋理是正常現象。

3中是計算該模型頂點在螢幕座標的紋理資訊,unity封裝的UnityCG.cginc代碼中有:

   

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;    }

 

與3中給o.uv賦值的代碼是一樣的。所以在頂點程式中可以這樣寫:

 

 v2f vert (appdata_base v)    {     v2f o;     // 從模型座標-全局座標-視座標-(視覺平截體乘以投影矩陣並進行透視除法)-剪裁座標     o.pos = mul(UNITY_MATRIX_MVP,v.vertex);     //o.uv = TRANSFORM_TEX(v.texcoord, _GrabTexture);// UV紋理座標集資訊來自螢幕樣本對象     float4 screenUV = ComputeGrabScreenPos(o.pos);//計算該模型頂點在螢幕座標的紋理資訊     o.uv = screenUV.xy/screenUV.w;     return o;    }

 

嘿嘿,以後我們就可以不用再寫這段代碼了,直接用unity提供的函數ComputeGrabScreenPos,方便!

 

擷取螢幕的紋理,還可以通過攝像機,將渲染的內容寫到RenderTexture中,這樣就可以不使用grabpass,一樣達到擷取螢幕紋理的目標,grabpass比較耗(官方說的,不過我在pc上建立了5000個對象進行測試,沒發現太大差異,手機上沒測過),在手機上比較適合這種方式。實現代碼如下:

 

public class ScreenTexture : MonoBehaviour{    public Camera m_camera;          // 和主攝像機參數一樣的拍照攝像機    private RenderTexture m_tex;    // 攝像機渲染的材質    public Material mat;            // 要控制的材質    void Start()    {        m_tex = new RenderTexture(Screen.width, Screen.height, 16);        m_camera.targetTexture = m_tex;    }    void OnPreCull()    {        mat.SetTexture("_MainTex", m_tex);   // 給shader的主材質賦值,為螢幕紋理    }    void OnPostRender()    {        mat.SetTexture("_MainTex", null);    }}

 

(轉)GrabPass捕捉螢幕紋理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.