shader实例十六 GrabPass捕捉屏幕纹理 shader 纹理

最近在看热扭曲效果,里面用到了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]{combineone-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
shader实例(十六)GrabPass捕捉屏幕纹理 shader 纹理
#pragmavertex 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
{
half4texCol = 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
#pragmavertex 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
floatscale = -1.0;
#else
floatscale = 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;
returno;
}
float4 frag(v2f i) : COLOR
{
//对_GrabTexture纹理进行取样,进行2D纹理映射查找,后面传入的一定要四元纹理坐标。
//UNITY_PROJ_COORD传入四元纹理坐标用于给tex2Dproj读取,但是多数平台上,返回一样的值。
//【自动生成的纹理UV】类型是float4,使用如下方式进行2D纹理映射查找
//half4texCol = tex2Dproj(_GrabTexture,UNITY_PROJ_COORD(i.uv));

//也可以使用tex2D进行采样,但是【自动生成的纹理UV】时必须要除以w转为齐次坐标
floatlast_x = i.uv.x / i.uv.w;
floatlast_y = i.uv.y / i.uv.w;
half4texCol = 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) {
#ifUNITY_UV_STARTS_AT_TOP
floatscale = -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赋值的代码是一样的。所以在顶点程序中可以这样写:

v2fvert (appdata_base v)
{
v2fo;
//从模型坐标-世界坐标-视坐标-(视觉平截体乘以投影矩阵并进行透视除法)-剪裁坐标
o.pos= mul(UNITY_MATRIX_MVP,v.vertex);
//o.uv= TRANSFORM_TEX(v.texcoord, _GrabTexture);//UV纹理坐标集信息来自屏幕样本对象

float4screenUV = ComputeGrabScreenPos(o.pos);//计算该模型顶点在屏幕坐标的纹理信息
o.uv= screenUV.xy/screenUV.w;
returno;
}

嘿嘿,以后我们就可以不用再写这段代码了,直接用unity提供的函数ComputeGrabScreenPos,方便!

获取屏幕的纹理,还可以通过摄像机,将渲染的内容写到RenderTexture中,这样就可以不使用grabpass,一样达到获取屏幕纹理的目标,grabpass比较耗(官方说的,不过我在pc上创建了5000个对象进行测试,没发现太大差异,手机上没测过),在手机上比较适合这种方式。实现代码如下:

public classScreenTexture : MonoBehaviour
{
publicCameram_camera;//和主摄像机参数一样的拍照摄像机
privateRenderTexturem_tex; //摄像机渲染的材质
publicMaterialmat;// 要控制的材质

void Start()
{
m_tex = new RenderTexture(Screen.width, Screen.height, 16);
m_camera.targetTexture = m_tex;
}

void OnPreCull()
{
mat.SetTexture("_MainTex",m_tex);//给shader的主材质赋值,为屏幕纹理
}
voidOnPostRender()
{
mat.SetTexture("_MainTex", null);
}
}

  

爱华网本文地址 » http://www.413yy.cn/a/25101011/86875.html

更多阅读

二进制数与十六进制数之间如何互相转换 二进制转换十六进制

二进制数与十六进制数之间如何互相转换——简介二进制与十六进制之间的转换与二进制和八进制之间的转换很类似,今天我们来详细看一下:首先,我们来看一下数学关系即24=16,即用四位二进制表示一位八进制。二进制数与十六进制数之间如何互

保卫萝卜 挑战36关攻略:36 第三十六关 保卫萝卜3官网

?2013年6月28号更新保卫萝卜挑战关卡 第一时间为大家带来详尽攻略?第三十六关:说实话没想到36关以上来的布局是这么的微妙 很有点难度 有点声东击西的意思 这关算这次更新5关中最难的一关 具体攻略如下?一开始的布局异常重要 在

大宅门之三十六计 福福鼠之三十六计全集

昨天无聊,无意中在IPTV中在安徽卫视中看到了《大宅门》。其实之前断断续续看了不少,但却从来没完整看过,这下难得有了机会,就从第一集大约看了10多集吧。不得不说,《大宅门》的确是国内连续剧中不多的精品,而前面十多集中白二奶奶盘回被别

声明:《shader实例十六 GrabPass捕捉屏幕纹理 shader 纹理》为网友你是我心里的雨分享!如侵犯到您的合法权益请联系我们删除