简介
径向模糊效果的原理
径向模糊在Unity下的实现
/********************************************************************
FileName: RadialBlurEffect.cs
Description: 径向模糊效果
Created: 2017/02/16
history: 16:1:2017 23:05 by puppet_master
*********************************************************************/
using UnityEngine;
public class RadialBlurEffect : PostEffectBase {
//模糊程度,不能过高
[Range(0,0.05f)]
public float blurFactor = 1.0f;
//模糊中心(0-1)屏幕空间,默认为中心点
public Vector2 blurCenter = new Vector2(0.5f, 0.5f);
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
if (_Material)
{
_Material.SetFloat("_BlurFactor", blurFactor);
_Material.SetVector("_BlurCenter", blurCenter);
Graphics.Blit(source, destination, _Material);
}
else
{
Graphics.Blit(source, destination);
}
}
}
RadialBlurShader1:
//径向模糊shader by puppet_master
//2017.2.17
Shader "ApcShader/PostEffect/RadialBlurShader1"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
}
CGINCLUDE
uniform sampler2D _MainTex;
uniform float _BlurFactor; //模糊强度(0-0.05)
uniform float4 _BlurCenter; //模糊中心点xy值(0-1)屏幕空间
#include "UnityCG.cginc"
#define SAMPLE_COUNT 6 //迭代次数
fixed4 frag(v2f_img i) : SV_Target
{
//模糊方向为模糊中点指向边缘(当前像素点),而越边缘该值越大,越模糊
float2 dir = i.uv - _BlurCenter.xy;
float4 outColor = 0;
//采样SAMPLE_COUNT次
for (int j = 0; j < SAMPLE_COUNT; ++j)
{
//计算采样uv值:正常uv值+从中间向边缘逐渐增加的采样距离
float2 uv = i.uv + _BlurFactor * dir * j;
outColor += tex2D(_MainTex, uv);
}
//取平均值
outColor /= SAMPLE_COUNT;
return outColor;
}
ENDCG
SubShader
{
Pass
{
ZTest Always
Cull Off
ZWrite Off
Fog{ Mode off }
//调用CG函数
CGPROGRAM
//使效率更高的编译宏
#pragma fragmentoption ARB_precision_hint_fastest
//vert_img是在UnityCG.cginc中定义好的,当后处理vert阶段计算常规,可以直接使用自带的vert_img
#pragma vertex vert_img
#pragma fragment frag
ENDCG
}
}
Fallback off
}
我们找一个场景,测试一下效果。没有开启径向模糊效果的原始场景如下:
径向模糊的优化
/********************************************************************
FileName: RadialBlurEffect.cs
Description: 径向模糊效果
Created: 2017/02/2-
history: 16:1:2017 23:05 by puppet_master
*********************************************************************/
using UnityEngine;
public class RadialBlurEffect2 : PostEffectBase {
//模糊程度,不能过高
[Range(0,0.1f)]
public float blurFactor = 1.0f;
//清晰图像与原图插值
[Range(0.0f, 2.0f)]
public float lerpFactor = 0.5f;
//降低分辨率
public int downSampleFactor = 2;
//模糊中心(0-1)屏幕空间,默认为中心点
public Vector2 blurCenter = new Vector2(0.5f, 0.5f);
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
if (_Material)
{
//申请两块降低了分辨率的RT
RenderTexture rt1 = RenderTexture.GetTemporary(source.width >> downSampleFactor, source.height >> downSampleFactor, 0, source.format);
RenderTexture rt2 = RenderTexture.GetTemporary(source.width >> downSampleFactor, source.height >> downSampleFactor, 0, source.format);
Graphics.Blit(source, rt1);
//使用降低分辨率的rt进行模糊:pass0
_Material.SetFloat("_BlurFactor", blurFactor);
_Material.SetVector("_BlurCenter", blurCenter);
Graphics.Blit(rt1, rt2, _Material, 0);
//使用rt2和原始图像lerp:pass1
_Material.SetTexture("_BlurTex", rt2);
_Material.SetFloat("_LerpFactor", lerpFactor);
Graphics.Blit(source, destination, _Material, 1);
//释放RT
RenderTexture.ReleaseTemporary(rt1);
RenderTexture.ReleaseTemporary(rt2);
}
else
{
Graphics.Blit(source, destination);
}
}
}
RadialBlurEffect2.shader:
//径向模糊shader by puppet_master
//2017.2.20
Shader "ApcShader/PostEffect/RadialBlurShader2"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
_BlurTex("Blur Tex", 2D) = "white"{}
}
CGINCLUDE
uniform sampler2D _MainTex;
uniform sampler2D _BlurTex;
uniform float _BlurFactor; //模糊强度(0-0.05)
uniform float _LerpFactor; //插值的强度(0-1)
uniform float4 _BlurCenter; //模糊中心点xy值(0-1)屏幕空间
float4 _MainTex_TexelSize;
#include "UnityCG.cginc"
#define SAMPLE_COUNT 6 //迭代次数
fixed4 frag_blur(v2f_img i) : SV_Target
{
//模糊方向为模糊中点指向边缘(当前像素点),而越边缘该值越大,越模糊
float2 dir = i.uv - _BlurCenter.xy;
float4 outColor = 0;
//采样SAMPLE_COUNT次
for (int j = 0; j < SAMPLE_COUNT; ++j)
{
//计算采样uv值:正常uv值+从中间向边缘逐渐增加的采样距离
float2 uv = i.uv + _BlurFactor * dir * j;
outColor += tex2D(_MainTex, uv);
}
//取平均值
outColor /= SAMPLE_COUNT;
return outColor;
}
//定义最后插值使用的结构体
struct v2f_lerp
{
float4 pos : SV_POSITION;
float2 uv1 : TEXCOORD0; //uv1
float2 uv2 : TEXCOORD1; //uv2
};
v2f_lerp vert_lerp(appdata_img v)
{
v2f_lerp o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv1 = v.texcoord.xy;
o.uv2 = v.texcoord.xy;
//dx中纹理从左上角为初始坐标,需要反向(在写rt的时候需要注意)
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv2.y = 1 - o.uv2.y;
#endif
return o;
}
fixed4 frag_lerp(v2f_lerp i) : SV_Target
{
float2 dir = i.uv1 - _BlurCenter.xy;
float dis = length(dir);
fixed4 oriTex = tex2D(_MainTex, i.uv1);
fixed4 blurTex = tex2D(_BlurTex, i.uv2);
//按照距离乘以插值系数在原图和模糊图之间差值
return lerp(oriTex, blurTex, _LerpFactor * dis);
}
ENDCG
SubShader
{
//Pass 0 模糊操作
Pass
{
ZTest Always
Cull Off
ZWrite Off
Fog{ Mode off }
//调用CG函数
CGPROGRAM
//使效率更高的编译宏
#pragma fragmentoption ARB_precision_hint_fastest
//vert_img是在UnityCG.cginc中定义好的,当后处理vert阶段计算常规,可以直接使用自带的vert_img
#pragma vertex vert_img
#pragma fragment frag_blur
ENDCG
}
//Pass 1与原图插值操作
Pass
{
ZTest Always
Cull Off
ZWrite Off
Fog{ Mode off }
//调用CG函数
CGPROGRAM
//使效率更高的编译宏
#pragma fragmentoption ARB_precision_hint_fastest
//vert_img是在UnityCG.cginc中定义好的,当后处理vert阶段计算常规,可以直接使用自带的vert_img
#pragma vertex vert_lerp
#pragma fragment frag_lerp
ENDCG
}
}
Fallback off
}
还是刚才的场景,使用新版本的后处理效果的结果如下:
UNITY_UV_STARTS_AT_TOP宏
OpenGL-like: The coordinate is 0 at the bottom and increases upward. This applies to OpenGL and OpenGL ES.
This difference tends not to have any effect on your project, other than when rendering into a Render Texture. When rendering into a Texture on a Direct3D-like platform, Unity internally flips rendering upside down. This makes the conventions match between platforms, with the OpenGL-like platform convention the standard.Image Effects and rendering in UV space are two common cases in the Shaders where you need to take action to ensure that the different coordinate conventions do not create problems in your project.
If your Image Effect is a simple one that processes one Render Texture at a time, Graphics.Blit deals with the inconsistent coordinates. However, if you’re processing more than one Render Texture together in your Image Effect, the Render Textures are likely to come out at different vertical orientations in Direct3D-like platforms and when you use anti-aliasing. To standardise the coordinates, you need to manually “flip” the screen Texture upside down in your Vertex Shader so that it matches the OpenGL-like coordinate standard.
原文地址:http://blog.youkuaiyun.com/puppet_master/article/details/54566397
2943



被折叠的 条评论
为什么被折叠?



