您现在的位置是:首页 >其他 >庄懂的TA笔记(十七)<特效:屏幕UV + 屏幕扰动>网站首页其他
庄懂的TA笔记(十七)<特效:屏幕UV + 屏幕扰动>
庄懂的TA笔记(十七)<特效:屏幕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; // 顶点位置 OS
float2 uv : TEXCOORD0; // UV信息
};
// 输出结构
struct VertexOutput {
float4 pos : SV_POSITION; // 顶点位置 CS
float2 uv : TEXCOORD0; // UV信息
float2 screenUV : TEXCOORD1; // 屏幕UV
};
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos(v.vertex); // 顶点位置 OS>CS
o.uv = v.uv; // UV信息
float3 posVS = UnityObjectToViewPos(v.vertex).xyz; // 顶点位置 OS>VS
float originDist = UnityObjectToViewPos(float3(0.0, 0.0, 0.0)).z; // 原点位置 OS>VS
o.screenUV = posVS.xy / posVS.z; // VS空间畸变校正
o.screenUV *= originDist; // 纹理大小按距离锁定
o.screenUV = o.screenUV * _ScreenTex_ST.xy - frac(_Time.x * _ScreenTex_ST.zw); // 启用屏幕纹理ST
return 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 Pass
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 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>CS
o.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);
// 扰动背景纹理采样UV
i.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、作业: