(转)GrabPass捕捉屏幕纹理
转自: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(-i.uv.x , -i.uv.y));
// 颜色反相,便于观察效果
return - 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 - 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, );
m_camera.targetTexture = m_tex;
} void OnPreCull()
{
mat.SetTexture("_MainTex", m_tex); // 给shader的主材质赋值,为屏幕纹理
}
void OnPostRender()
{
mat.SetTexture("_MainTex", null);
}
}
(转)GrabPass捕捉屏幕纹理的更多相关文章
- 写shader小细节——这个会不断更新
这个是因为自己被自己蠢哭了动笔的,里面大概记录自己所犯的错,和一些小知识. 1.有一个错误我经常犯:内部定义的字段没对应开放到编辑器的字段.这个是由于我有点依赖ide写代码的习惯导致,而shader的 ...
- Unity3d之Shader编程:子着色器、通道与标签的写法 & 纹理混合
一.子着色器 Unity中的每一个着色器都包含一个subshader的列表,当Unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器. 我们知道,子着色器 ...
- Unity3d Shader开发(四)UsePass ,GrabPass ,SubShader Tags
(一)UsePass 命令 使用 来自另一个着色器的命名通道. Syntax 语法 UsePass "Shader/Name" 插入所有来自给定着色器中的给定名字的通道.Shade ...
- 关于Unity中GrabPass截屏的使用和Shader的组织优化
GrabPass截屏 可以用来截屏,截屏后把纹理传给下一个通道使用. 1:使用抓屏通道, GrabPass {} 或 GrabPass { “ 纹理名称”}; 使用GrabPass {}后,可以用_G ...
- 【Unity Shader】(九) ------ 高级纹理之渲染纹理及镜子与玻璃效果的实现
笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ----- ...
- 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...
- Unity Shader入门精要学习笔记 - 第10章 高级纹理
转载自 冯乐乐的 <Unity Shader入门精要> 立方体纹理 在图形学中,立方体纹理是环境映射的一种实现方法.环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层 ...
- OpenGL: 纹理采样 texture sample
Sampler (GLSL) Sampler通常是在Fragment shader(片元着色器)内定义的,这是一个uniform类型的变量,即处理不同的片元时这个变量是一致不变的.一个sampler和 ...
- CSharpGL(10)两个纹理叠加
CSharpGL(10)两个纹理叠加 本文很简单,只说明如何用shader实现叠加两个纹理的效果. 另外,最近CSharpGL对渲染框架做了修改,清理一些别扭的内容(DoRender()前后的事件都去 ...
随机推荐
- JS基础:(一)
开发了很多项目,感觉javascript脚本语言用处太大了,所以,把一些心得写出来,尤其是调试的技巧. 本次开发工具:Webstorm 1. 官网:http://www.jetbrains.com/ ...
- python全栈开发day38-css三种引入方式、基础选择器、高级选择器、补充选择器
一.昨日内容回顾 div:分割整个网站,很多块 (1)排版标签 (2)块级标签 独占一行 可以设置高和宽,如果不设置宽高,默认是父盒子的宽 span: (1) 小区域 (2)文本标签 (3)在一行内显 ...
- python全栈开发day29-网络编程之socket常见方法,socketserver模块,ftp作业
一.昨日内容回顾 1.arp协议含义 2.子网,子网掩码 3.两台电脑在网络中怎么通信的? 4.tcp和udp socket编码 5.tcp和udp协议的区别 6.tcp三次握手和四次挥手,syn洪攻 ...
- springmvc中登录过滤器使用
前言 一般的javaWeb项目中我们肯定会使用过滤器来实现对一些请求的过滤,通过过滤来实现对一些请求参数的设置和校验,比如我们比较熟悉的CharacterEncodingFilter就是一个字符编 ...
- Codeforces Round #428 (Div. 2)
终于上蓝名了,hahahahaha,虽然这场的 B 题因为脑抽了,少考虑一种情况终判错了,还是很可惜的.. B题本来过来1500个人,终判之后只剩下了200多个,真的有毒!!!! A - Arya a ...
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1036 题意概括 一个树,每个节点有一个权值.3种操作. 1:修改某一个节点的权值. 2:询问某两个 ...
- Mistwald POJ
一开始看不出来是快速幂矩阵的题目 先要把整个地图离散化为1,2,3,4,.... 连成一个有向图 邻接矩阵的平方意为:假如a->b 且b->c 那么一次平方后 a->c ...
- 1.HTTP协议|web框架
1.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式C/S.B/S.C/S是客户端 ...
- 【Java】 剑指offer(32) 从上往下打印二叉树
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 (一)从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺 ...
- 007 关于Spark下的第二种模式——standalone搭建
一:介绍 1.介绍standalone Standalone模式是Spark自身管理资源的一个模式,类似Yarn Yarn的结构: ResourceManager: 负责集群资源的管理 NodeMan ...