Unity毛玻璃特效
特效可以用于一般物体,也可以应用于UI。一直想在UI中实现这么个效果,现在终于实现了。
效果如下:
应用于场景中的屏物体![毛玻璃效果物体](https://i-blog.csdnimg.cn/blog_migrate/9b082bdeeb47e74470bd7da1a3bc7e23.png)
应用于UI
调节Shader的参数,可以调整背景模糊和扭曲的程度,也可以调整毛玻璃的颜色,还可也换法线和纹理贴图。
原理
用到是CommandBuffer
,其实就是拿官方的案例过来稍微一改就行了。关键是CommandBuffer
啊,Custom Pass
啊,这些东东,一直都是一知半解的,看文档吧又TM全是鸟语,硬着头皮看,到现在还是一知半解,呵呵。算球,能实现就行啊。
using UnityEngine;
using UnityEngine.Rendering;
[ExecuteInEditMode]
public class CommandBufferBlurRefraction : MonoBehaviour
{
[SerializeField] private Camera cameraMain;
[SerializeField] private Shader blurShader;
private Material _material = null;
private CommandBuffer _commandBuffer = null;
private void Cleanup()
{
if (!_material)
{
cameraMain.RemoveCommandBuffer(CameraEvent.AfterSkybox, _commandBuffer);
DestroyImmediate(_material);
_material = null;
}
}
public void OnDisable()
{
Cleanup();
}
private readonly int screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");
private readonly int blurredID = Shader.PropertyToID("_Temp1");
private readonly int blurredID2 = Shader.PropertyToID("_Temp2");
public void OnEnable()
{
if (!cameraMain)
cameraMain = Camera.main;
if (cameraMain == null)
return;
_material ??= new Material(blurShader) {hideFlags = HideFlags.HideAndDontSave};
_commandBuffer ??= new CommandBuffer() {name = "Grab screen and blur"};
// copy screen into temporary RT
_commandBuffer.GetTemporaryRT(screenCopyID, -1, -1, 0, FilterMode.Bilinear);
_commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, screenCopyID);
// get two smaller RTs
_commandBuffer.GetTemporaryRT(blurredID, -2, -2, 0, FilterMode.Bilinear);
_commandBuffer.GetTemporaryRT(blurredID2, -2, -2, 0, FilterMode.Bilinear);
// downsample screen copy into smaller RT, release screen RT
_commandBuffer.Blit(screenCopyID, blurredID);
_commandBuffer.ReleaseTemporaryRT(screenCopyID);
// horizontal blur
_commandBuffer.SetGlobalVector("offsets", new Vector4(2.0f / Screen.width, 0, 0, 0));
_commandBuffer.Blit(blurredID, blurredID2, _material);
// vertical blur
_commandBuffer.SetGlobalVector("offsets", new Vector4(0, 2.0f / Screen.height, 0, 0));
_commandBuffer.Blit(blurredID2, blurredID, _material);
// horizontal blur
_commandBuffer.SetGlobalVector("offsets", new Vector4(4.0f / Screen.width, 0, 0, 0));
_commandBuffer.Blit(blurredID, blurredID2, _material);
// vertical blur
_commandBuffer.SetGlobalVector("offsets", new Vector4(0, 4.0f / Screen.height, 0, 0));
_commandBuffer.Blit(blurredID2, blurredID, _material);
_commandBuffer.SetGlobalTexture("_GrabBlurTexture", blurredID);
cameraMain.AddCommandBuffer(CameraEvent.AfterSkybox, _commandBuffer);
}
}
其实,这大体的原理就是,在摄像机上加一个CommandBuffer
,相当于在渲染过程中添加了额外的处理指令,就是,在渲染这个毛玻璃物体之前,先把已经渲染好的屏幕拿过来模糊一下,扭曲一下,然后以屏幕空间作为UV再贴到这个物体上。
扭曲和模糊屏幕的Shader:
毛玻璃Shader: