unity屏幕shader之油画屏幕

来源:互联网 发布:儿童乳液面霜知乎 编辑:程序博客网 时间:2024/04/26 19:29

本篇博客仅仅供本人参考学习,转载自浅墨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 MaterialGetAndSetMaterial 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 framevoid Update () {//若程序在运行,进行赋值if (Application.isPlaying){//赋值ResolutionValue = ChangeValue;RadiusValue=ChangeValue2;}//若程序没有在运行,去寻找对应的Shader文件#if UNITY_EDITORif (Application.isPlaying!=true){            CurShader = Shader.Find("Custom/oilScreen");}#endif}//-----------------------------------------【OnDisable()函数】---------------------------------------  // 说明:当对象变为不可用或非激活状态时此函数便被调用  //--------------------------------------------------------------------------------------------------------void OnDisable (){if(CurMaterial){//立即销毁材质实例DestroyImmediate(CurMaterial);}}}










0 0