本文主要是介绍庄懂的TA笔记(十七)<特效:屏幕UV + 屏幕扰动>,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
庄懂的TA笔记(十七)<特效:屏幕UV + 屏幕扰动>
大纲:
目录
庄懂的TA笔记(十七)<特效:屏幕UV + 屏幕扰动>
大纲:
正文:
一、屏幕UV:
二、屏幕扰动:
三、任务委托:
正文:
一、屏幕UV:
1、案例展示:
屏幕UV在过往案例使用中,出现了 镜头畸变,纹理大小不能锁定等问题,这节内容就把屏幕UV的使用全部讲完。
这个效果中是 没有边缘畸变的,到边缘是完完整整的平铺上去的。所以屏幕UV 的重点就在这两个部分。
畸变解决:
纹理大小锁定:
2、实现思路:
主图透贴纹理UV + 屏幕纹理UV流动 = 最终ScreenUV效果;
3、代码实现:
①、面板参数定义:
_MainTex : (RGB : 颜色 A : 透贴 ,2d)="gray"{}
_Opacity :("透明",range(0,1))=0.5
这里屏幕坐标纹的Tillng 和 offset是要用到的,所以需要追加_ST。
_ScreenTex : ("屏幕纹理" , 2d) = "black"{}
②、输出结构:
因为需要用到 主图UV 和 屏幕UV ,所以这里要定义出,uv,和 screenUV.
③、顶点shader输入输出:
float3 posVS = UnityObjectToViewPos(v.vertex).xyz; // 获取顶点位置到摄像机位置的xyz。
o.ScreenUV1 = posVS.xy;//赋值给屏幕UV 。
像素shader: (中间输出测试监测)
float3 var_ScreenTex = tex2D(_ScreenTex,i.ScreenUV1);
return float4(var_ScreenTex,1);
重点:屏幕UV 位置,畸变修正,纹理大小锁定。
取屏幕空间UV位置,取xyz三个轴,
如何理解Vive空间呢?Vive空间相当于以摄像机平面为基准的空间,XY轴对应UV,Z轴对应深度。
但是,正常我们将 XY轴向的UV采样后,会发现贴图在模型表面会有畸变,
如图:
解决方法: 也很简单,直接xy ➗ z 深度 就好了。
o.screenUV = posVS.xy / posVS.z; // VS空间畸变校正
但矫正过后,还会有一个问题,就是你的屏幕UV纹理,相对于你的屏幕Tiling大小是不随距离改变的,正常是模型纹理,会随距离,近大远小的,所以这里我们需要对屏幕UV纹理进行锁定。
如图;
解决方法:得到观察空间的距离,第一个就需要获得模型的原点.
UnityObjectToVivePos float3(0,0,0).z
声明一个orignDist存 模型原点,到 距离摄像机的距离。
float3 orignDist = UnityObjectToVivePos(float3(0,0,0)).z;
然后 在将 屏幕UV * 距离(模型到相机的距离) = 锁定后的屏幕UV.(锁定屏幕UV);
o.screenUV = posVS.xy / posVS.z; // VS空间畸变校正
o.screenUV *= originDist; // 纹理大小按距离锁定
o.screenUV * = orignDist; or o.screenUV = o.screenUV * orignDist(两种方式等价)
综上所属,主要问题就解决了。
如图:
④、屏幕UV滚动:
这里就控制Tiling和offset 流动起来,
ScreenTex_ST. X Y 对应 Tiling的 X Y ;
ScreenTex_ST. Z W 对应 offset的 Z W ;
o.screenUV = o.screenUV * _ScreenTex_ST.X Y - frac(_Time * _ScreenTex_ST.Z W);
(这里 的 + - 都可以用,主要是控制 流动方向的)
o.screenUV=o.screenUV*_ScreenTex_ST.xy - frac(_Time.x * _ScreenTex_ST.zw)启用屏幕纹理ST
如图:
⑤、像素shader:
采样 两张图,两个UV ,主贴图,屏幕空间贴图。
混合透明 = 主图var_MainTex.a * 不透明_Opacity * 屏幕贴图var_ScreenTex;
float3 FinalRGB = var_MainTex.rgb ;
float opacity = var_MainTex.a * _Opacity * var_ScreenTex;
return float4 (FinalRGB * opacity , opacity);
4、核心代码:
重要的就是这一段, (屏幕UV 矫正 和 锁定)
5、屏幕UV 代码示例:
Shader "AP01/L17/ScreenUV" {Properties {_MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}_Opacity ("透明度", range(0, 1)) = 0.5_ScreenTex ("屏幕纹理", 2d) = "black" {}}SubShader {Tags {"Queue"="Transparent" // 调整渲染顺序"RenderType"="Transparent" // 对应改为Cutout"ForceNoShadowCasting"="True" // 关闭阴影投射"IgnoreProjector"="True" // 不响应投射器}Pass {Name "FORWARD"Tags {"LightMode"="ForwardBase"}Blend One OneMinusSrcAlpha // 混合方式CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#pragma multi_compile_fwdbase_fullshadows#pragma target 3.0// 输入参数uniform sampler2D _MainTex;uniform half _Opacity;uniform sampler2D _ScreenTex; uniform float4 _ScreenTex_ST;// 输入结构struct VertexInput {float4 vertex : POSITION; // 顶点位置 OSfloat2 uv : TEXCOORD0; // UV信息};// 输出结构struct VertexOutput {float4 pos : SV_POSITION; // 顶点位置 CSfloat2 uv : TEXCOORD0; // UV信息float2 screenUV : TEXCOORD1; // 屏幕UV};// 输入结构>>>顶点Shader>>>输出结构VertexOutput vert (VertexInput v) {VertexOutput o = (VertexOutput)0;o.pos = UnityObjectToClipPos(v.vertex); // 顶点位置 OS>CSo.uv = v.uv; // UV信息float3 posVS = UnityObjectToViewPos(v.vertex).xyz; // 顶点位置 OS>VSfloat originDist = UnityObjectToViewPos(float3(0.0, 0.0, 0.0)).z; // 原点位置 OS>VSo.screenUV = posVS.xy / posVS.z; // VS空间畸变校正o.screenUV *= originDist; // 纹理大小按距离锁定o.screenUV = o.screenUV * _ScreenTex_ST.xy - frac(_Time.x * _ScreenTex_ST.zw); // 启用屏幕纹理STreturn o;}// 输出结构>>>像素half4 frag(VertexOutput i) : COLOR {half4 var_MainTex = tex2D(_MainTex, i.uv); // 采样 基本纹理 RGB颜色 A透贴half var_ScreenTex = tex2D(_ScreenTex, i.screenUV).r; // 采样 屏幕纹理// FinalRGB 不透明度half3 finalRGB = var_MainTex.rgb;half opacity = var_MainTex.a * _Opacity * var_ScreenTex;// 返回值return half4(finalRGB * opacity, opacity);}ENDCG}}
}
二、屏幕扰动:
1、案例展示:
2、实现思路:
屏幕扰动(玻璃效果)
背景信息获取:
MainTex 红或蓝通道扭曲:
①、面板参数定义:
_MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}
_Opacity ("不透明度", range(0, 1)) = 0.5
_WarpMidVal ("扰动中间值", range(0, 1)) = 0.5
_WarpInt ("扰动强度", range(0, 5)) = 1
这里的中间值 扭曲度,因为我们用的是主图自带的通道中的信息,RGB中不同通道的像素可能偏亮,可能偏暗,会影响扭曲的强弱, 因为不像 法线的中间值是正常的0.5,偏移扭曲的正常的数值,所以这里声明了一个 用于矫正的 "扰动中间值"(_WarpMidVal)
②、追加GrabPass 获取扭曲背景_BGTex==背景纹理采样坐标(现成黑盒):
产生这张图:
获取背景纹理,他的含义为:渲染主体物前,将背景存成一张图,名字就叫 _BGTex.
实际上就是,扰动前,把背景图存起来,然后再用屏幕坐标UV把 背景图(_BGTex)贴回去。
GrabPass {
"_BGTex"
}
获取这张图:
uniform sampler2D _BGTex; // 拿到背景纹理
输出结构中 : (VertexOutput)
float4 grabPos : TEXCOORD1; // 背景纹理采样坐标(4维的)
顶点shader输入输出结构中 :
o.grabPos = ComputeGrabScreenPos(o.pos); // 背景纹理采样坐标
像素shader中采样:
half3 var_BGTex = tex2Dproj(_BGTex, i.grabPos).rgb;// 采样背景
③、像素shader下 采样和计算:
获取主贴图 通道信息作为源,来扭曲背景图(grabPos)采样坐标XY;
// 采样 基本纹理 RGB颜色 A透贴
half4 var_MainTex = tex2D(_MainTex, i.uv);
<这里用主图的B蓝通道,减去中间值,减去是什么意思呢,相当于有正有负,在乘强度(_WarpInt) 在乘 透明度(_Opacity),就得到透明的扰动效果>。
// 扰动背景纹理采样UV
i.grabPos.xy+=(var_MainTex.b - _WarpMidVal) * _WarpInt * _Opacity;
// 采样背景
half3 var_BGTex = tex2Dproj(_BGTex, i.grabPos).rgb;
用_Opacity控制 1 到 主图透明 的插值,并乘以 透明的背景信息,得到 带透贴的扰动主图。
// FinalRGB 不透明度
half3 finalRGB = lerp(1.0, var_MainTex.rgb, _Opacity) * var_BGTex;
half opacity = var_MainTex.a;
// 返回值
return half4(finalRGB * opacity, opacity);
3、代码实现:
4、核心代码
5、屏幕扰动 代码示例:
Shader "AP01/L17/ScreenWarp" {Properties {_MainTex ("RGB:颜色 A:透贴", 2d) = "gray"{}_Opacity ("不透明度", range(0, 1)) = 0.5_WarpMidVal ("扰动中间值", range(0, 1)) = 0.5_WarpInt ("扰动强度", range(0, 5)) = 1}SubShader {Tags {"Queue"="Transparent" // 调整渲染顺序"RenderType"="Transparent" // 对应改为Cutout"ForceNoShadowCasting"="True" // 关闭阴影投射"IgnoreProjector"="True" // 不响应投射器}// 获取背景纹理GrabPass {"_BGTex"}// Forward PassPass {Name "FORWARD"Tags {"LightMode"="ForwardBase"}Blend One OneMinusSrcAlpha // 混合方式CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#pragma multi_compile_fwdbase_fullshadows#pragma target 3.0// 输入参数uniform sampler2D _MainTex;uniform half _Opacity;uniform half _WarpMidVal;uniform half _WarpInt;uniform sampler2D _BGTex; // 拿到背景纹理// 输入结构struct VertexInput {float4 vertex : POSITION; // 顶点位置 总是必要float2 uv : TEXCOORD0; // UV信息 采样贴图用};// 输出结构struct VertexOutput {float4 pos : SV_POSITION; // 顶点位置 总是必要float2 uv : TEXCOORD0; // UV信息 采样贴图用float4 grabPos : TEXCOORD1; // 背景纹理采样坐标};// 输入结构>>>顶点Shader>>>输出结构VertexOutput vert (VertexInput v) {VertexOutput o = (VertexOutput)0;o.pos = UnityObjectToClipPos( v.vertex); // 顶点位置 OS>CSo.uv = v.uv; // UV信息o.grabPos = ComputeGrabScreenPos(o.pos); // 背景纹理采样坐标return o;}// 输出结构>>>像素half4 frag(VertexOutput i) : COLOR {// 采样 基本纹理 RGB颜色 A透贴half4 var_MainTex = tex2D(_MainTex, i.uv);// 扰动背景纹理采样UVi.grabPos.xy += (var_MainTex.b - _WarpMidVal) * _WarpInt * _Opacity;// 采样背景half3 var_BGTex = tex2Dproj(_BGTex, i.grabPos).rgb;// FinalRGB 不透明度half3 finalRGB = lerp(1.0, var_MainTex.rgb, _Opacity) * var_BGTex;half opacity = var_MainTex.a;// 返回值return half4(finalRGB * opacity, opacity);}ENDCG}}
}
三、任务委托:
1、作业:
这篇关于庄懂的TA笔记(十七)<特效:屏幕UV + 屏幕扰动>的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!