Unity Shaders——屏幕特效老电影效果(Old Movie Screen Effect)

Posted 御雪妃舞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity Shaders——屏幕特效老电影效果(Old Movie Screen Effect)相关的知识,希望对你有一定的参考价值。

本文参考《Unity Shaders and Effects CookBook》。


很多时候我们游戏需要带入不同的场景,比如老电影的那种效果



像这种效果我们怎么实现呢?


下面分析下结构图:




这也是这个效果的思路图,虚光照,尘土,划痕都是通过图片混合的,然后深褐色Shader直接处理,再让尘土和划痕的uv动起来,最终就能达到老电影的效果。


下面我们看下我们需要的三张图片:


虚光照:



灰尘:



划痕:



然后脚本跟前面的屏幕特效的模式类似,就是略微复杂些:


shader脚本:

Shader "MyShaders/OldFilmEffectShader"
 
	Properties 
	
		_MainTex ("Base (RGB)", 2D) = "white" 
		_VignetteTex ("Vignette Texture", 2D) = "white"
		_ScratchesTex ("Scartches Texture", 2D) = "white"
		_DustTex ("Dust Texture", 2D) = "white"
		_SepiaColor ("Sepia Color", Color) = (1,1,1,1)
		_EffectAmount ("Old Film Effect Amount", Range(0,1)) = 1.0
		_VignetteAmount ("Vignette Opacity", Range(0,1)) = 1.0
		_ScratchesYSpeed ("Scratches Y Speed", Float) = 10.0
		_ScratchesXSpeed ("Scratches X Speed", Float) = 10.0
		_dustXSpeed ("Dust X Speed", Float) = 10.0
		_dustYSpeed ("Dust Y Speed", Float) = 10.0
		_RandomValue ("Random Value", Float) = 1.0
		_Contrast ("Contrast", Float) = 3.0
		
		_distortion ("Distortion", Float) = 0.2
		_cubicDistortion ("Cubic Distortion", Float) = 0.6
		_scale ("Scale (Zoom)", Float) = 0.8
	
	
	SubShader 
	
		Pass
		
			CGPROGRAM
			#pragma vertex vert_img
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest
			#include "UnityCG.cginc"
			
			uniform sampler2D _MainTex;
			uniform sampler2D _VignetteTex;
			uniform sampler2D _ScratchesTex;
			uniform sampler2D _DustTex;
			fixed4 _SepiaColor;
			fixed _VignetteAmount;
			fixed _ScratchesYSpeed;
			fixed _ScratchesXSpeed;
			fixed _dustXSpeed;
			fixed _dustYSpeed;
			fixed _EffectAmount;
			fixed _RandomValue;
			fixed _Contrast;
			
			float _distortion;
			float _cubicDistortion;
			float _scale;

			float2 barrelDistortion(float2 coord) 
			

				float2 h = coord.xy - float2(0.5, 0.5);
				float r2 = h.x * h.x + h.y * h.y;
				float f = 1.0 + r2 * (_distortion + _cubicDistortion * sqrt(r2));

				return f * _scale * h + 0.5;
			

			fixed4 frag(v2f_img i) : COLOR
			
				//Get the colors from the RenderTexture and the uv's
				//from the v2f_img struct
				half2 distortedUV = barrelDistortion(i.uv);
				distortedUV = half2(i.uv.x, i.uv.y + (_RandomValue * _SinTime.z * 0.005));
				fixed4 renderTex = tex2D(_MainTex, i.uv);
				
				//Get the pixels from the Vignette Texture
				fixed4 vignetteTex = tex2D(_VignetteTex, i.uv);
				
				//Process the Scratches UV and pixels
				half2 scratchesUV = half2(i.uv.x + (_RandomValue * _SinTime.z * _ScratchesXSpeed),
										 i.uv.y + (_Time.x * _ScratchesYSpeed));
				fixed4 scratchesTex = tex2D(_ScratchesTex, scratchesUV);
				
				//Process the Dust UV and pixels
				half2 dustUV = half2(i.uv.x + (_RandomValue * (_SinTime.z * _dustXSpeed)), 
									i.uv.y + (_RandomValue * (_SinTime.z * _dustYSpeed)));
				fixed4 dustTex = tex2D(_DustTex, dustUV);
				
				// get the luminosity values from the render texture using the YIQ values.
				fixed lum = dot (fixed3(0.299, 0.587, 0.114), renderTex.rgb);

				
				//Add the constant color to the lum values
				fixed4 finalColor = lum + lerp(_SepiaColor, _SepiaColor +
											    fixed4(0.1f,0.1f,0.1f,1.0f), _RandomValue);
				finalColor = pow(finalColor, _Contrast);
				
				//Create a constant white color we can use to adjust opacity of effects
				fixed3 constantWhite = fixed3(1,1,1);
				
				//Composite together the different layers to create finsl Screen Effect
				finalColor = lerp(finalColor, finalColor * vignetteTex, _VignetteAmount);
				finalColor.rgb *= lerp(scratchesTex, constantWhite, (_RandomValue));
				finalColor.rgb *= lerp(dustTex.rgb, constantWhite, (_RandomValue * _SinTime.z));
				finalColor = lerp(renderTex, finalColor, _EffectAmount);
				
				return finalColor;
			
	
			ENDCG
		
	 
	FallBack off


cs脚本:


using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class OldFilmEffect : MonoBehaviour 

	
	#region Variables
	public Shader oldFilmShader;
	
	public float OldFilmEffectAmount = 1.0f;
	public float contrast = 3.0f;
	public float distortion = 0.2f;
	public float cubicDistortion = 0.6f;
	public float scale = 0.8f;
	
	public Color sepiaColor = Color.white;
	public Texture2D vignetteTexture;
	public float vignetteAmount = 1.0f;
	
	public Texture2D scratchesTexture;
	public float scratchesYSpeed = 10.0f;
	public float scratchesXSpeed = 10.0f;
	
	public  Texture2D dustTexture;
	public float dustYSpeed = 10.0f;
	public float dustXSpeed = 10.0f;
	
	private Material curMaterial;
	private float randomValue;
	#endregion
	
	#region Properties
	Material material
	
		get
		
			if(curMaterial == null)
			
				curMaterial = new Material(oldFilmShader);
				curMaterial.hideFlags = HideFlags.HideAndDontSave;
			
			return curMaterial;
		
	
	#endregion
	
	void Start()
	
		if(!SystemInfo.supportsImageEffects)
		
			enabled = false;
			return;
		
		
		if(!oldFilmShader && !oldFilmShader.isSupported)
		
			enabled = false;
		
	
	
	void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
	
		if(oldFilmShader != null)
			
			material.SetColor("_SepiaColor", sepiaColor);
			material.SetFloat("_VignetteAmount", vignetteAmount);
			material.SetFloat("_EffectAmount", OldFilmEffectAmount);
			material.SetFloat("_Contrast", contrast);
			material.SetFloat("_cubicDistortion", cubicDistortion);
			material.SetFloat("_distortion", distortion);
			material.SetFloat("_scale",scale);
			
			if(vignetteTexture)
			
				material.SetTexture("_VignetteTex", vignetteTexture);
			
			
			if(scratchesTexture)
			
				material.SetTexture("_ScratchesTex", scratchesTexture);
				material.SetFloat("_ScratchesYSpeed", scratchesYSpeed);
				material.SetFloat("_ScratchesXSpeed", scratchesXSpeed);
			
			
			if(dustTexture)
			
				material.SetTexture("_DustTex", dustTexture);
				material.SetFloat("_dustYSpeed", dustYSpeed);
				material.SetFloat("_dustXSpeed", dustXSpeed);
				material.SetFloat("_RandomValue", randomValue);
			
			
			Graphics.Blit(sourceTexture, destTexture, material);
		
		else
		
			Graphics.Blit(sourceTexture, destTexture);
		
	
	
	void Update()
	
		vignetteAmount = Mathf.Clamp01(vignetteAmount);
		OldFilmEffectAmount = Mathf.Clamp(OldFilmEffectAmount, 0f, 1.5f);
		randomValue = Random.Range(-1f,1f);
		contrast = Mathf.Clamp(contrast, 0f, 4f);
		distortion = Mathf.Clamp(distortion, -1f,1f);
		cubicDistortion = Mathf.Clamp(cubicDistortion, -1f, 1f);
		scale = Mathf.Clamp(scale, 0f, 1f);
	
	
	void OnDisable()
	
		if(curMaterial)
		
			DestroyImmediate(curMaterial);
		
	


最终运行结果如图:




贴图素材下载


以上是关于Unity Shaders——屏幕特效老电影效果(Old Movie Screen Effect)的主要内容,如果未能解决你的问题,请参考以下文章

Unity Shaders——屏幕灰度效果(Screen Effect)

Unity Shader——夜晚视觉屏幕特效(night vision Screen Effect)

Aura #01 (Unity 大气特效插件)

Unity Shaders and Effects Cookbook (D-1) 设置 ZTest 来实现遮挡半透效果

Unity Shaders and Effects Cookbook (3-6) 创建各向异性高光类型(Anisotropic) 模拟金属拉丝效果

unity制作一个特效转换到屏幕里