Unity3D旧电视滤镜shader Unity3D旧电视滤镜shader的实现示例
Marco&GalaxyDragon 人气:0实现思路
既然是要实现旧电视的后处理效果,那么只要回忆一下那些古旧的电视的显示效果然后进行模拟就可以了。
1.首先那种大头电视一般屏幕有一些曲率,并不是完全的一个平面,而且一般是向外凸起,这种凸起会造成中间的显示区域会比原来更近一些,边缘的显示区域会比原来更远一些。这种效果我们直接用简单的二次函数来实现。
2.那种老旧电视会有不断运动的噪声,我们直接使用噪声函数加上时间变量来实现。
3.屏幕上会有一些条纹效果,这种周期性的条纹效果一般用三角函数来实现。
当然不可能模拟的完全准确。。也没有完全准确一说。毕竟每个人对老电视的印象也是不同的,我这里也只是把我印象里的效果来实现一下,看起来差不多就行了。
实现代码
首先实现第一点,实现屏幕的曲率。
我们采用的方法是先计算该uv坐标离(0.5,0.5)的距离,这个(0.5,0.5)的uv坐标其实可以看成屏幕的中心点。计算出距离之后根据这个距离的大小来对uv进行偏移,这其中用到了一个参数_Expand 为偏移的距离。
需要注意的是dot函数里填入两次同样的向量,算出的是向量模的平方而不是向量的模,不过这正是我们需要的,可以达到平方衰减的效果。
float d2 = dot(i.uv - half2(0.5, 0.5), i.uv - half2(0.5, 0.5)); half2 coord = (i.uv - half2(0.5, 0.5)) * (_Expand + d2 * (1 - _Expand)) + half2(0.5, 0.5);
接下来用这个偏移后的uv坐标来对纹理进行采样。
half4 color = tex2D(_MainTex, coord);
调整参数后就会出现一些屏幕凸出的效果,当然这里整个显示范围也变小了,这里是因为如果要显示原范围的话,需要的公式太复杂了,我们这里简单起见使用了简单的公式。
原图
添加shader后
接下来添加噪声,我们用一个变量控制噪声强度,同时传入时间变量来得到噪声一直变化的效果。
float n = simpleNoise(coord.xy * _Time.x); half3 result = color.rgb * (1-_NoiseIntensity) + _NoiseIntensity * n;
而噪声函数具体的实现如下
至于为什么这个函数就可以得到噪声,其实也不好解释。大致就是sin函数倍增之后加上取小数的frac函数可以近似得到一种随机数的效果吧。
float simpleNoise(float2 uv) { return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453); }
效果如下
最后添加上条纹效果
这个公式也不是什么经过精心推导的公式,只是因为我们需要一个周期出现的条纹效果,然后就想到用sin和cos函数,然后随便调整一下看起来有点样子就可以了
half2 sc = half2((sin(coord.y * _StripeIntensity) + 1) / 2, (cos(coord.y * _StripeIntensity) + 1) / 2); result += color.rgb * sc.xyx;
添加条纹之后
效果2
完整代码
c#代码
namespace Colorful { using UnityEngine; [ExecuteInEditMode] public class OldTV : MonoBehaviour { public Shader shader; [Range(0, 1)] public float Expand = 0.7f; [Range(0, 1)] public float NoiseIntensity = 0.3f; public int StripeIntensity = 500; protected void OnRenderImage(RenderTexture source, RenderTexture destination) { Material material = new Material(shader); material.SetFloat("_Expand", Expand); material.SetFloat("_NoiseIntensity", NoiseIntensity); material.SetInt("_StripeIntensity", StripeIntensity); Graphics.Blit(source, destination, material, 0); } } }
shader代码
Shader "LX/OldTV" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex; float _Expand; float _NoiseIntensity; int _StripeIntensity; float simpleNoise(float2 uv) { return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453); } half4 frag(v2f_img i) : SV_Target { float d2 = dot(i.uv - half2(0.5, 0.5), i.uv - half2(0.5, 0.5)); half2 coord = (i.uv - half2(0.5, 0.5)) * (_Expand + d2 * (1 - _Expand)) + half2(0.5, 0.5); half4 color = tex2D(_MainTex, coord); float n = simpleNoise(coord.xy * _Time.x); half3 result = color.rgb * (1-_NoiseIntensity) + _NoiseIntensity * n; half2 sc = half2((sin(coord.y * _StripeIntensity) + 1) / 2, (cos(coord.y * _StripeIntensity) + 1) / 2); result += color.rgb * sc.xyx; return half4(result, color.a); } ENDCG SubShader { ZTest Always Cull Off ZWrite Off Fog { Mode off } Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag ENDCG } } FallBack off }
另外代码也传到github仓库里了,大家也可以关注一下哦~
我的github
加载全部内容