前言
对上一篇中实现的shader进行优化
一、在之前顶点着色器的输入中,放弃了使用结构体传入,而是直接从应用程序阶段传入参数,这样写的话,对于程序来说,不方便扩张,所以需要对其进行修改
实现
1、定义结构体用于传入顶点坐标系
struct appdata
{
float4 vertex : POSITION;
//从应用程序阶段的输入,多加一个uv,用于对扭曲纹理的采样
float2 uv : TEXCOORD;
};
2、因为UnityObjectToClipPos是从本地空间转换到裁剪空间,但是没有进行透视除法,所以需要对其进行透视除法,用转化后的结果的 xyz / w 就可以进行透视除法
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv,_DistortTex) + _Distort.xy * _Time.y;
//把本地空间转化到其次裁剪空间后的结果,进行透视除法后, 传给 screenUV
o.screenUV.xyz = o.pos.xyz / o.pos.w;
return o;
}
3、因为屏幕坐标的原点一般在左上角(DirectX) 或 左下角(OpenGL) (我的是DirectX平台,所以在左上角。),会造成显示的位置,和我们需要的位置不同,所以需要对其进行计算平移缩放处理
DirectX平台:fixed2 uv = fixed2(i.screenUV.x * 0.5,i.screenUV.y * -0.5) + 0.5;
OpenGL平台:fixed2 uv = i.screenUV * 0.5 + 0.5;
改到顶点着色器中计算
DirectX平台:
o.screenUV.x = o.screenUV.x * 0.5 + 0.5;
o.screenUV.y = o.screenUV.y * -0.5 + 0.5;
OpenGL平台:
o.screenUV.x = o.screenUV * 0.5 + 0.5;
但是这样是插值计算的会有误差瑕疵,所以还是改在片元着色器中计算
DirectX平台:
fixed2 uv = i.screenUV.xy / i.screenUV.w;
uv.x = uv.x * 0.5 +0.5;
uv.y = uv.y * -0.5 + 0.5;
二、改用Unity内置提供的方法(平台间互通)
ComputeScreenPos(float4 pos)
pos为裁剪空间下的坐标位置,返回的是某个投影点下的屏幕坐标位置
由于这个函数返回的坐标值并未除以齐次坐标,所以如果直接使用函数的返回值的话,需要使用:tex2Dproj(_ScreenTexture, uv.xyw);
也可以自己处理其次坐标,使用:tex2D(_ScreenTexture, uv.xy / uv.w);
在顶点着色器:o.screenUV = ComputeScreenPos(o.pos);
在片元着色器:fixed4 grabTex = tex2Dproj(_GrabTex,i.screenUV);文章来源:https://www.toymoban.com/news/detail-772587.html
三、最后加上扭曲
Shader "MyShader/P0_10_5"
{
Properties
{
//实现扭曲,就需要传入贴图来实现扰度
_DistortTex("DistortTex",2D) = "white"{}
_Distort("SpeedX(X) SpeedY(y) Distort(Z)",vector) = (0,0,0,0)
}
SubShader
{
Tags{"Queue" = "Transparent"}
//屏幕抓取需要单独使用一个Pass —— GrabPass{} 里面什么都不写,或者GrabPass{"_GrabTex"}
GrabPass{"_GrabTex"}
//使用Cull off 让两面都有扭曲
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
//从应用程序阶段的输入,多加一个uv,用于对扭曲纹理的采样
float2 uv : TEXCOORD;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float4 screenUV:TEXCOORD1;
};
//在使用抓取的屏幕前,需要像使用属性一样定义一下,_GrabTexture这个名字是Unity定义好的
sampler2D _GrabTex;
sampler2D _DistortTex;float4 _DistortTex_ST;
float4 _Distort;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv,_DistortTex) + _Distort.xy * _Time.y;
//pos为裁剪空间下的坐标位置,返回的是某个投影点下的屏幕坐标位置
o.screenUV = ComputeScreenPos(o.pos);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//DirectX平台:
/*fixed2 uv = i.screenUV.xy / i.screenUV.w;
uv.x = uv.x * 0.5 +0.5;
uv.y = uv.y * -0.5 + 0.5;*/
fixed4 distortTex = tex2D(_DistortTex,i.uv);
//使用线性插值来控制UV的扭曲程度
float2 uv = lerp(i.screenUV.xy/i.screenUV.w,distortTex,_Distort.z);
//对抓取的屏幕进行采样
fixed4 grabTex = tex2D(_GrabTex,uv);
return grabTex;
}
ENDCG
}
}
}
效果:
文章来源地址https://www.toymoban.com/news/detail-772587.html
到了这里,关于Unity中Shader抓取屏幕并实现扭曲效果(优化)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!