赞
踩
通过这里,你会学习到怎么获取当前屏幕的贴图以及UV,通常用于屏幕的后处理。
开发环境:Unity5.0或者更高
1. 获取屏幕贴图
2. 获取屏幕UV
3. 完整代码
Unity 内置GrabPass
来获取屏幕贴图,语法如下,代码写在SubShader
里面。
GrabPass{"自定义贴图名称"}
此Pass的作用是获取当前帧缓冲的内容。我们可以打开FrameDebugger看到
Unity提供了一个接口用于获取物体在屏幕上的uv坐标
ComputeGrabScreenPos (float4 clipPos)
ComputeGrabScreenPos 官方说明
他需要传入一个float4的坐标,这个坐标是裁剪空间的坐标,在shader可以通过UnityObjectToClipPos()
接口获取
该函数定义在UnityCG.cginc, 使用之前需要引入这个文件
#include "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;
#ifdef UNITY_SINGLE_PASS_STEREO
o.xy = TransformStereoScreenSpaceTex(o.xy, pos.w);
#endif
o.zw = pos.zw;
return o;
}
代码说明
- #if UNITY_UV_STARTS_AT_TOP 因为在DX平台和OpenGl平台,坐标轴不一样,DX定义(0,0)为左上角,而OpenGl的定义(0,0)在左下角。防止图像翻转加上这个代码
- 我们首先要了解如何将坐标从裁剪空间转换到屏幕空间。中间过程有两步,先进行透视除法,将xyz值都除以w分量,让x,y,z的范围都处于[-1,1]之间,
所谓透视除法主要是针对透视投影,对于正交投影这个w=1
。之后将这个[-1,1]的坐标转换到屏幕空间,x坐标由[-1,1]->[0,屏幕宽度] ,y坐标由[-1,1]->[0,屏幕高度],这两步可以归结为以下公式
但我们需要的是UV坐标,只需要转换到[0,1]即可,相当于上述公式的pixelWidth = 1,pixelHeight = 1,
当相机为正交投影时:上述公式clipw = 1 则带入可得到Unity源码中的float4 o = pos * 0.5f; o.xy = float2(o.x, o.y*scale) + o.w;
,
当相机为透视投影时 源码使用TransformStereoScreenSpaceTex(o.xy, pos.w);
进行处理,里面的代码是
float2 TransformStereoScreenSpaceTex(float2 uv, float w)
{
float4 scaleOffset = unity_StereoScaleOffset[unity_StereoEyeIndex];
return uv.xy * scaleOffset.xy + scaleOffset.zw * w;
}
原理是将透视投影的相机平头截体向中间缩放挤压,变成和正交投影一样,在和正交投影一样处理。
最后我们需要再采样的时候将uv.xy / uv.w 因为我们再上面假设clipw =1了
Shader "Toturial/ScreenGrab" { Properties { _MainTex("MainTex",2D) = "white"{} } SubShader { GrabPass{"_bTexture"} Tags{"Queue"="Transparent"} Pass { CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag sampler2D _MainTex; sampler2D _bTexture; struct a2v { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; float4 grabPos : TEXCOORD1; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.grabPos = ComputeScreenPos(o.pos); return o; } fixed4 frag(v2f i) : SV_TARGET { fixed4 screenColor = tex2D(_bTexture, i.grabPos.xy / i.grabPos.w); return screenColor * 2; } ENDCG } } }
最终得到效果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。