赞
踩
当然PS那个径向模糊比我实现的这个效果要好(我这个也不能实现太好的效果,运行在手机上会受不了),毕竟PS是离线编辑,且针对一帧图像处理的,不存在什么性能不性能的问题,怎么炫就怎么来。
从PS上的径向模糊不难理解,就是对指定某个径向点后,如下图中的绿色点C是径向点,红色的P,Q两点别分与C点直线上的前前后后都用采样点,就那些蓝色点,越是靠近C点,采样距离越小,所以模糊程度响度来说会比较小的(意思就会相对边缘的来说会比较清晰)。
来看看运行中,我们将其他参数调整一下,只看采样距离
注意查看远处的三颗球,红色圆圈是球的原始位置,黄色箭头是前前后后分别采样的位置,越靠近径向点,采样距离就越近。
还看不出来的话,你就直接看人物的头部,中间部分是最清晰的。
在代码上只要控制好采样步长就可以了:
float2 stepDir = normalize(vec) * _SampleDistance; // 每次的采样步长方向
float stepLenFactor = len * 0.1 * _Intensity; // len : 0~0.5 再乘上 0.1 就是0~0.05,越是靠近中心开,采样距离会越小,模糊度就会相对边缘来说更小
stepDir *= stepLenFactor; // 控制步长值,stepLenFactor=len * 0.1 * _Intensity中的:0.1是经验数值可以不管,或是外部公开控制也是可以的
fixed4 sum = 0;
for (int it = 0; it < sampleCount; it++) {
float2 appliedStep = stepDir * it;
sum += tex2D(_DownSampleRT, i.uv + appliedStep); // 正向采样
sum += tex2D(_DownSampleRT, i.uv - appliedStep); // 反向采样
}
主要看这么一句:
float stepLenFactor = len * 0.1 * _Intensity; // len : 0~0.5 再乘上 0.1 就是0~0.05,越是靠近中心开,采样距离会越小,模糊度就会相对边缘来说更小
就可以控制越径向点月经采样距离越小
完整代码如下:
// jave.lin 2020.03.21 径向模糊 - Radial Blur Shader "Custom/RadialBlur" { CGINCLUDE #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; float _Intensity; // 径向效果的强度 float _FadeRadius; // 淡出径向效果的半径范围 float _SampleDistance; // 每次采样的距离 sampler2D _DownSampleRT; // 原图降采样后的图 sampler2D _SrcTex; // 原始图像纹理 v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag(v2f i) : SV_Target { const int sampleCount = 5; // 单想采样次数,乘以2就是真的总次数 const float invSampleCount = 1.0 / ((float)sampleCount * 2); float2 vec = i.uv - 0.5; float len = length(vec); float fade = smoothstep(0, _FadeRadius, len); // 平滑淡出的径向效果值 float2 stepDir = normalize(vec) * _SampleDistance; // 每次的采样步长方向 float stepLenFactor = len * 0.1 * _Intensity; // len : 0~0.5 再乘上 0.1 就是0~0.05,越是靠近中心开,采样距离会越小,模糊度就会相对边缘来说更小 stepDir *= stepLenFactor; // 控制步长值,stepLenFactor=len * 0.1 * _Intensity中的:0.1是经验数值可以不管,或是外部公开控制也是可以的 fixed4 sum = 0; for (int it = 0; it < sampleCount; it++) { float2 appliedStep = stepDir * it; sum += tex2D(_DownSampleRT, i.uv + appliedStep); // 正向采样 sum += tex2D(_DownSampleRT, i.uv - appliedStep); // 反向采样 } sum *= invSampleCount; // 均值模糊 return lerp(tex2D(_SrcTex, i.uv), sum, fade * _Intensity); } ENDCG SubShader { Cull Off ZWrite Off ZTest Always Pass { NAME "RADIA_BLUR" CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } }
完整的Shader中,也可以看到,我也采样的是均值模糊sum *= invSampleCount; // 均值模糊
,性能上也是比较高的方式。
接下来我们再对采样图做了downSample(就是对径向模糊的数据源采样图做了降低分辨率),最后就只有58 x 27左右的尺寸,在移动端上性能是很可观的,而且降低采样图尺寸后除了占用VRAM(显存)少了,就连模糊的效果也提升了,实在是一举两得。
using UnityEngine; /// <summary> /// jave.lin 2020.03.21 径向模糊 Radial Blur /// </summary> public class RadialBlurScript : MonoBehaviour { private static int _Intensity_hash = Shader.PropertyToID("_Intensity"); private static int _FadeRadius_hash = Shader.PropertyToID("_FadeRadius"); private static int _SampleDistance_hash = Shader.PropertyToID("_SampleDistance"); private static int _SrcTex_hash = Shader.PropertyToID("_SrcTex"); private static int _DownSampleRT_hash = Shader.PropertyToID("_DownSampleRT"); public Material mat; [Header("Radial Blur")] [Range(0, 1)] public float intensity = 1; // 效果强度 [Range(0f, 1f)] public float fadeRadius = 0.38f; // 半径范围内的都淡出 [Range(0f, 1f)] public float sampleDistance = 0.25f; // 径向模糊每次采样的距离 [Range(1, 40)] public int blurDownSample = 40; // 模糊降低输出采样率 private Camera cam; private void Start() { cam = GetComponent<Camera>(); cam.depthTextureMode |= DepthTextureMode.Depth; } private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (!mat) { Graphics.Blit(source, destination); return; } var rw = Screen.width / blurDownSample; var rh = Screen.height / blurDownSample; RenderTexture downSampleRT = RenderTexture.GetTemporary(rw, rh, 0); downSampleRT.filterMode = FilterMode.Bilinear; downSampleRT.name = "downSampleRT"; Graphics.Blit(source, downSampleRT); mat.SetFloat(_Intensity_hash, intensity); mat.SetFloat(_FadeRadius_hash, fadeRadius); mat.SetFloat(_SampleDistance_hash, sampleDistance); mat.SetTexture(_DownSampleRT_hash, downSampleRT); mat.SetTexture(_SrcTex_hash, source); Graphics.Blit(null, destination, mat, 0); RenderTexture.ReleaseTemporary(downSampleRT); } }
backup : UnityShader_RadialBlurTesting_2018.3.0f2
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。