unity屏幕shader之油画屏幕

本篇博客仅仅供本人参考学习,转载自浅墨shader。

本实例本人在unity5.3上能使用,在unity4.6.6中不能使用。

油画屏幕shader:

Shader "Custom/oilScreen" {
//------------------------------------【属性值】------------------------------------
	Properties
	{
		_MainTex("Base (RGB)", 2D) = "white" {}
		_Distortion("_Distortion", Range(0.0, 1.0)) = 0.3
		_ScreenResolution("_ScreenResolution", Vector) = (0., 0., 0., 0.)
		_ResolutionValue("_ResolutionValue", Range(0.0, 5.0)) = 1.0
		_Radius("_Radius", Range(0.0, 5.0)) = 2.0
	}

	//------------------------------------【唯一的子着色器】------------------------------------
	SubShader
	{
		//--------------------------------唯一的通道-------------------------------
		Pass
		{
			//设置深度测试模式:渲染所有像素.等同于关闭透明度测试(AlphaTest Off)
			ZTest Always

			//===========开启CG着色器语言编写模块===========
			CGPROGRAM

			//编译指令: 指定着色器编译目标为Shader Model 3.0
			#pragma target 3.0

			//编译指令:告知编译器顶点和片段着色函数的名称
			#pragma vertex vert
			#pragma fragment frag

			//包含辅助CG头文件
			#include "UnityCG.cginc"

			//外部变量的声明
			uniform sampler2D _MainTex;
			uniform float _Distortion;
			uniform float4 _ScreenResolution;
			uniform float _ResolutionValue;
			uniform int  _Radius;

			//顶点输入结构
			struct vertexInput
			{
				float4 vertex : POSITION;//顶点位置
				float4 color : COLOR;//颜色值
				float2 texcoord : TEXCOORD0;//一级纹理坐标
			};

			//顶点输出结构
			struct vertexOutput
			{
				half2 texcoord : TEXCOORD0;//一级纹理坐标
				float4 vertex : SV_POSITION;//像素位置
				fixed4 color : COLOR;//颜色值
			};


			//--------------------------------【顶点着色函数】-----------------------------
			// 输入:顶点输入结构体
			// 输出:顶点输出结构体
			//---------------------------------------------------------------------------------
			vertexOutput vert(vertexInput Input)
			{
				//【1】声明一个输出结构对象
				vertexOutput Output;

				//【2】填充此输出结构
				//输出的顶点位置为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口
				Output.vertex = mul(UNITY_MATRIX_MVP, Input.vertex);
				//输出的纹理坐标也就是输入的纹理坐标
				Output.texcoord = Input.texcoord;
				//输出的颜色值也就是输入的颜色值
				Output.color = Input.color;

				//【3】返回此输出结构对象
				return Output;
			}

			//--------------------------------【片段着色函数】-----------------------------
			// 输入:顶点输出结构体
			// 输出:float4型的颜色值
			//---------------------------------------------------------------------------------
			float4 frag(vertexOutput Input) : COLOR
			{
				//【1】根据设置的分辨率比值,计算图像尺寸
				float2 src_size = float2(_ResolutionValue / _ScreenResolution.x, _ResolutionValue / _ScreenResolution.y);
				
				//【2】获取坐标值
				float2 uv = Input.texcoord.xy;

				//【3】根据半径,计算出n的值
				float n = float((_Radius + 1) * (_Radius + 1));;

				//【4】定义一些参数
				float3 m0 = 0.0;  float3 m1 = 0.0;
				float3 s0 = 0.0;  float3 s1 = 0.0;
				float3 c;

				//【5】按半径Radius的值,迭代计算m0和s0的值
				for (int j = -_Radius; j <= 0; ++j)
				{
					for (int i = -_Radius; i <= 0; ++i)
					{
						c = tex2D(_MainTex, uv + float2(i, j) * src_size).rgb; 
						m0 += c; 
						s0 += c * c;
					}
				}

				//【6】按半径Radius的值,迭代计算m1和s1的值
				for (int j = 0; j <= _Radius; ++j)
				{
					for (int i = 0; i <= _Radius; ++i)
					{
						c = tex2D(_MainTex, uv + float2(i, j) * src_size).rgb; 
						m1 += c;
						s1 += c * c;
					}
				}

				//【7】定义参数,准备计算最终的颜色值
				float4 finalFragColor = 0.;
				float min_sigma2 = 1e+2;

				//【8】根据m0和s0,第一次计算finalFragColor的值
				m0 /= n;
				s0 = abs(s0 / n - m0 * m0);

				float sigma2 = s0.r + s0.g + s0.b;
				if (sigma2 < min_sigma2) 
				{
					min_sigma2 = sigma2;
					finalFragColor = float4(m0, 1.0);
				}

				//【9】根据m1和s1,第二次计算finalFragColor的值
				m1 /= n;
				s1 = abs(s1 / n - m1 * m1);

				sigma2 = s1.r + s1.g + s1.b;
				if (sigma2 < min_sigma2) 
				{
					min_sigma2 = sigma2;
					finalFragColor = float4(m1, 1.0);
				}

				//【10】返回最终的颜色值
				return finalFragColor;
			}

			ENDCG
		}

	}
}

应用脚本:

using UnityEngine;
using System.Collections;

//设置在编辑模式下也执行该脚本
[ExecuteInEditMode]
//添加选项到菜单中

public class oilScreen : MonoBehaviour 
{
	//-------------------变量声明部分-------------------
	#region Variables
	
	//着色器和材质实例
	public Shader CurShader;
	private Material CurMaterial;
	
	//两个参数值
	[Range(0, 5),Tooltip("分辨率比例值")]
	public float ResolutionValue = 0.9f;
	[Range(1, 30),Tooltip("半径的值,决定了迭代的次数")]
	public int RadiusValue = 5;
	
	//两个用于调节参数的中间变量
	public static float ChangeValue;
	public static int ChangeValue2;
	#endregion
	
	//-------------------------材质的get&set----------------------------
	#region MaterialGetAndSet
	Material material
	{
		get
		{
			if(CurMaterial == null)
			{
				CurMaterial = new Material(CurShader);
				CurMaterial.hideFlags = HideFlags.HideAndDontSave;	
			}
			return CurMaterial;
		}
	}
	#endregion
	
	//-----------------------------------------【Start()函数】---------------------------------------------  
	// 说明:此函数仅在Update函数第一次被调用前被调用
	//--------------------------------------------------------------------------------------------------------
	void Start () 
	{
		//依次赋值
		ChangeValue = ResolutionValue;
		ChangeValue2 = RadiusValue;
		
		//找到当前的Shader文件
        CurShader = Shader.Find("Custom/oilScreen");
		
		//判断当前设备是否支持屏幕特效
		if(!SystemInfo.supportsImageEffects)
		{
			enabled = false;
			return;
		}
	}
	
	//-------------------------------------【OnRenderImage()函数】------------------------------------  
	// 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果
	//--------------------------------------------------------------------------------------------------------
	void OnRenderImage (RenderTexture sourceTexture, RenderTexture destTexture)
	{
		//着色器实例不为空,就进行参数设置
		if(CurShader != null)
		{
			//给Shader中的外部变量赋值
			material.SetFloat("_ResolutionValue", ResolutionValue);
			material.SetInt("_Radius", RadiusValue);
			material.SetVector("_ScreenResolution", new Vector4(sourceTexture.width, sourceTexture.height, 0.0f, 0.0f));
			
			//拷贝源纹理到目标渲染纹理,加上我们的材质效果
			Graphics.Blit(sourceTexture, destTexture, material);
		}
		
		//着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的
		else
		{
			//直接拷贝源纹理到目标渲染纹理
			Graphics.Blit(sourceTexture, destTexture);
		}
		
		
	}
	
	
	//-----------------------------------------【OnValidate()函数】--------------------------------------  
	// 说明:此函数在编辑器中该脚本的某个值发生了改变后被调用
	//--------------------------------------------------------------------------------------------------------
	void OnValidate()
	{
		//将编辑器中的值赋值回来,确保在编辑器中值的改变立刻让结果生效
		ChangeValue = ResolutionValue;
		ChangeValue2 = RadiusValue;
	}
	// Update is called once per frame
	void Update () 
	{
		//若程序在运行,进行赋值
		if (Application.isPlaying)
		{
			//赋值
			ResolutionValue = ChangeValue;
			RadiusValue=ChangeValue2;
		}
		//若程序没有在运行,去寻找对应的Shader文件
		#if UNITY_EDITOR
		if (Application.isPlaying!=true)
		{
            CurShader = Shader.Find("Custom/oilScreen");
		}
		#endif
		
	}
	
	//-----------------------------------------【OnDisable()函数】---------------------------------------  
	// 说明:当对象变为不可用或非激活状态时此函数便被调用  
	//--------------------------------------------------------------------------------------------------------
	void OnDisable ()
	{
		if(CurMaterial)
		{
			//立即销毁材质实例
			DestroyImmediate(CurMaterial);	
		}
		
	}
}










  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值