一、制作磨砂效果的毛玻璃
效果图:
代码:
Shader "Unlit/FrostedGlass"
{
Properties
{
_Radius("Radius", Range(1, 255)) = 1
}
Category
{
Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }
SubShader
{
GrabPass
{
Tags{ "LightMode" = "Always" }
}
Pass
{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 frag(v2f i) : COLOR
{
half4 sum = half4(0,0,0,0);
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
sum += GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 0.1f; range <= _Radius; range += 0.1f)
{
sum += GRABXYPIXEL(range, range);
sum += GRABXYPIXEL(range, -range);
sum += GRABXYPIXEL(-range, range);
sum += GRABXYPIXEL(-range, -range);
measurments += 4;
}
return sum / measurments;
}
ENDCG
}
GrabPass
{
Tags{ "LightMode" = "Always" }
}
Pass
{
Tags{ "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
struct v2f
{
float4 vertex : POSITION;
float4 uvgrab : TEXCOORD0;
};
v2f vert(appdata_t v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
float _Radius;
half4 frag(v2f i) : COLOR
{
half4 sum = half4(0,0,0,0);
float radius = 1.41421356237 * _Radius;
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
sum += GRABXYPIXEL(0.0, 0.0);
int measurments = 1;
for (float range = 1.41421356237f; range <= radius * 1.41; range += 1.41421356237f)
{
sum += GRABXYPIXEL(range, 0);
sum += GRABXYPIXEL(-range, 0);
sum += GRABXYPIXEL(0, range);
sum += GRABXYPIXEL(0, -range);
measurments += 4;
}
return sum / measurments;
}
ENDCG
}
}
}
}
二、制作水雾效果的毛玻璃
效果图:
工作原理:
1.获得水下物体的渲染图像作为抓屏纹理
2.计算随时间变化的正弦波
3.片段位置和(二维)时变正弦波结合,形成UV坐标
4.使用上述UV坐标对噪声纹理进行采样,取得一个畸变值
5.对抓屏纹理坐标进行畸变处理
6.用畸变后的纹理坐标访问抓屏纹理获得颜色
7.与界面颜色相乘输出最终颜色
代码:
Shader "Custom/5-2"
{
Properties
{
_NormalMap("Normal Map", 2D) = "bump" {}
_Distortion("Distortion", Range(0, 100)) = 50
}
SubShader
{
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
}
GrabPass { "_GrabTex" }
LOD 200
pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _NormalMap;
float _Distortion;
sampler2D _GrabTex;
float4 _GrabTex_TexelSize;
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 scrPos : TEXCOORD1;
};
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_INSTANCING_BUFFER_END(Props)
v2f vert(appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.scrPos = ComputeGrabScreenPos(o.pos);
return o;
}
fixed4 frag(v2f i) : SV_TARGET
{
float3 bump = UnpackNormal(tex2D(_NormalMap, i.uv));
float2 offset = bump.xy * _GrabTex_TexelSize.xy * _Distortion;
fixed4 albedo = tex2D(_GrabTex, (i.scrPos.xy + offset) / i.scrPos.w);
return albedo;
}
ENDCG
}
}
}
三、制作放大镜效果
效果图:
参考:(162条消息) Unity Shader - 放大镜_长生但酒狂的博客-CSDN博客_unity放大镜
思路:
- 先实现整体放大效果;
- 最后在一定范围内(圆形)放大
- 是放大镜,就是对图像的处理, 需要用到后期处理(参考(162条消息) UnityShader 屏幕后处理效果的基类_maba007的博客-CSDN博客
在Camera上面挂一个c#脚本来捕获需要渲染的图像,然后通过shader处理后渲染。
步骤:
1.整体放大:沿着 中心点到当前像素点的方向 采样像素点即可, 采样的距离越大, 缩放率就越大。
2.限制它在一定范围内缩放:让它在一个圆的范围内缩放。
脚本代码:
// ---------------------------【放大镜特效】---------------------------
using UnityEngine;
public class Zoom : PostEffectsBase
{
// shader
public Shader myShader;
//材质
private Material mat = null;
public Material material
{
get
{
// 检查着色器并创建材质
mat = CheckShaderAndCreateMaterial(myShader, mat);
return mat;
}
}
// 放大强度
[Range(-2.0f, 2.0f), Tooltip("放大强度")]
public float zoomFactor = 0.4f;
// 放大镜大小
[Range(0.0f, 0.2f), Tooltip("放大镜大小")]
public float size = 0.15f;
// 凸镜边缘强度
[Range(0.0001f, 0.1f), Tooltip("凸镜边缘强度")]
public float edgeFactor = 0.05f;
// 遮罩中心位置
private Vector2 pos = new Vector4(0.5f, 0.5f);
void Start()
{
//找到对应的Shader文件
myShader = Shader.Find("lcl/screenEffect/Zoom");
}
// 渲染屏幕
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (material)
{
// 把鼠标坐标传递给Shader
material.SetVector("_Pos", pos);
material.SetFloat("_ZoomFactor", zoomFactor);
material.SetFloat("_EdgeFactor", edgeFactor);
material.SetFloat("_Size", size);
// 渲染
Graphics.Blit(source, destination, material);
}
else
{
Graphics.Blit(source, destination);
}
}
void Update()
{
if (Input.GetMouseButton(0))
{
Vector2 mousePos = Input.mousePosition;
//将mousePos转化为(0,1)区间
pos = new Vector2(mousePos.x / Screen.width, mousePos.y / Screen.height);
}
}
}
shader代码:
// ---------------------------【放大镜特效】---------------------------
Shader "lcl/screenEffect/Zoom"
{
// ---------------------------【属性】---------------------------
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
// ---------------------------【子着色器】---------------------------
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
// ---------------------------【渲染通道】---------------------------
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//顶点输入结构体
struct VertexInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
// 顶点输出结构体
struct VertexOutput
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
// 变量申明
sampler2D _MainTex;
float2 _Pos;
float _ZoomFactor;
float _EdgeFactor;
float _Size;
// ---------------------------【顶点着色器】---------------------------
VertexOutput vert(VertexInput v)
{
VertexOutput o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
// ---------------------------【片元着色器】---------------------------
fixed4 frag(VertexOutput i) : SV_Target
{
//屏幕长宽比 缩放因子
float2 scale = float2(_ScreenParams.x / _ScreenParams.y, 1);
// 放大区域中心
float2 center = _Pos;
float2 dir = center - i.uv;
//当前像素到中心点的距离
float dis = length(dir * scale);
// 是否在放大镜区域
// fixed atZoomArea = 1-step(_Size,dis);
float atZoomArea = smoothstep(_Size + _EdgeFactor,_Size,dis);
fixed4 col = tex2D(_MainTex, i.uv + dir * _ZoomFactor * atZoomArea);
return col;
}
ENDCG
}
}
}
屏幕 后处理效果代码:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode] //编辑状态也运行
[RequireComponent(typeof(Camera))] // 它修饰的类在需要时自动挂载在 指定的组件上
public class PostEffectsBase : MonoBehaviour
{
protected void Start()
{
CheckResources();
}
// Called when start
protected void CheckResources()
{
bool isSupported = CheckSupport();
if (isSupported == false)
{
NotSupported();
}
}
// Called in CheckResources to check support on this platform
protected bool CheckSupport()
{
if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false)
{
Debug.LogWarning("This platform does not support image effects or render textures.");
return false;
}
return true;
}
// Called when the platform doesn't support this effect
protected void NotSupported()
{
enabled = false;
}
// 子类 调用的函数
// Called when need to create the material used by this effect
protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
{
if (shader == null)
{
return null;
}
if (shader.isSupported && material && material.shader == shader)
return material;
if (!shader.isSupported)
{
return null;
}
else
{
material = new Material(shader);
material.hideFlags = HideFlags.DontSave;
if (material)
return material;
else
return null;
}
}
}