Unity1Bit抖色后处理Shader

1.效果

img后处理使用前

img后处理使用后

此处应该有个视频

2.原理

2.1 什么是1bit像素画

1bit像素画只有2种颜色,最常见的是黑+白。1个颜色画阳形(通常是你要画的主题),1个颜色画阴形(通常代表画面中的空白)。

虽然只有2种颜色,但是我们可以混合黑白,产生灰色。这是像素画技巧抖动的原理。(实际上利用的人眼的视觉补偿机制,人眼和大脑会将相邻的黑白像素点混合变成灰色)

img来自:像素画高级教程:1bit像素画画法|白色|灰色_网易订阅 (163.com)

本教程使用的是第二个分段画法

2.2 实现思路

根据1bit像素画的定义,我们只需要先获取到屏幕的图像,然后转化成灰度图,再根据颜色的灰度值来替换成对应的像素图就行了

(明)灰度公式:0.2125R +0.7154G +0.0721*B; (该公式仅适用于unity,在其他平台可能会有颜色上的偏差)

2.3.视频教程

3.代码

3.1 1btpost.shader

Shader "Unlit/1btpost"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _SplitTex1 ("Texture", 2D) = "white" {}
        _SplitTex2 ("Texture", 2D) = "white" {}
        _SplitTex3 ("Texture", 2D) = "white" {}
        _SplitTex4 ("Texture", 2D) = "white" {}
        _SplitTex5 ("Texture", 2D) = "white" {}
        _Split1To2 ("Split1To2",float) = 0.2
        _Split2To3 ("Split2To3",float) = 0.4
        _Split3To4 ("Split3To4",float) = 0.6
        _Split4To5 ("Split4To5",float) = 0.8
        
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
           

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float2 uv1 : TEXCOORD1;
               
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _SplitTex1;
            float4 _SplitTex1_ST;
            sampler2D _SplitTex2;
            float4 _SplitTex2_ST;
            sampler2D _SplitTex3;
            float4 _SplitTex3_ST;
            sampler2D _SplitTex4;
            float4 _SplitTex4_ST;
            sampler2D _SplitTex5;
            float4 _SplitTex5_ST;

            float _Split1To2;
            float _Split2To3;
            float _Split3To4;
            float _Split4To5;
        

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv1 = TRANSFORM_TEX(v.uv, _SplitTex1);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                fixed4 col1 = tex2D(_SplitTex1, i.uv1);
                fixed4 col2 = tex2D(_SplitTex2, i.uv1);
                fixed4 col3 = tex2D(_SplitTex3, i.uv1);
                fixed4 col4 = tex2D(_SplitTex4, i.uv1);
                fixed4 col5 = tex2D(_SplitTex5, i.uv1);
                //明亮度计算公式
                float luminance  = 0.2125*col.r+0.7154*col.g+0.0721*col.b;
                if(luminance<=_Split1To2)
                {
                //col = float4(luminance,luminance,luminance,col.a);
                col = col1;
                }
                if(luminance<=_Split2To3&&luminance>_Split1To2)
                {
                //col = float4(luminance,luminance,luminance,col.a);
                col = col2;
                }
                if(luminance<=_Split3To4&&luminance>_Split2To3)
                {
                //col = float4(luminance,luminance,luminance,col.a);
                col = col3;
                }
                if(luminance<=_Split4To5&&luminance>_Split3To4)
                {
                //col = float4(luminance,luminance,luminance,col.a);
                col = col4;
                }
                if(luminance>_Split4To5)
                {
                //col = float4(luminance,luminance,luminance,col.a);
                col = col5;
                }


               // col = float4(luminance,luminance,luminance,col.a);
                return col;
            }
            ENDCG
        }
    }
}

对以下两个脚本更详尽的讲解,请访问我的这篇文章:Unity:实现反相后处理效果

3.2 PostEffectsBase.cs

//
//  PostEffectsBase.cs
//  qi_SteamVR_0.1
//
//  Created by YX on 2022/4/8.
//
//
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
/// <summary>
/// 后处理基类,需要放置在camera上
/// </summary>
public class PostEffectsBase : MonoBehaviour
{
    #region Field

    #endregion

    #region Property

    #endregion

    #region UnityOriginalEvent
    void Start()
    {
        CheckResources();
    }

    void Update()
    {
        
    }
    #endregion

    #region Function

    /// <summary>
    /// 检查东西当前平台是否支持图像处理
    /// </summary>
    /// <returns>可以返回ture,不可以返回false</returns>
    protected bool CheckSupport()
    {
        //检查当前平台是否支持图像后处理,现在基本所有的平台都支持,所以可以不判断
        if (SystemInfo.supportsImageEffects == false)
        {
            Debug.LogWarning("This platform does not support image effects.");
            return false;
        }

        return true;
    }

    /// <summary>
    /// 检查环境
    /// </summary>
    protected void CheckResources()
    {
        //当当前平台不支持图像后处理时,将该脚本关闭
        if (CheckSupport() == false)
        {
            enabled = false;
        }
    }


    /// <summary>
    /// 使用shader创建材质
    /// </summary>
    /// <param name="shader">使用的sheder</param>
    /// <param name="material">最终创建的材质</param>
    /// <returns></returns>
    protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
    {
        
        if (shader == null)
        {
            return null;
        }

        if (shader.isSupported && material && material.shader == shader)
            return material;

        if (!shader.isSupported)
        {
            return null;
        }
        else
        {
            material = new Material(shader);
            //设置meaterial为不可见,且在转换场景时不会被删除
            material.hideFlags = HideFlags.DontSave;
            if (material)
                return material;
            else
                return null;
        }
    }
    #endregion
}

3.3 ShakeColor.cs

//
//  Invert.cs
//  qi_SteamVR_0.1
//
//  Created by YX on 2022/4/8.
//
//
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 实现反相shader后处理
/// </summary>
public class ShakeColor : PostEffectsBase
{
    #region Field
    public Shader briSatConShader;
    private Material briSatConMaterial;
    public Vector2 uv;
    public Texture _SplitTex1;
    public Texture _SplitTex2;
    public Texture _SplitTex3;
    public Texture _SplitTex4;
    public Texture _SplitTex5;

    [Range(0,1)]
    public float _Split1To2 = 0.2f;
    [Range(0, 1)]
    public float _Split2To3 = 0.4f;
    [Range(0, 1)]
    public float _Split3To4 = 0.6f;
    [Range(0, 1)]
    public float _Split4To5 = 0.8f;
    #endregion

    #region Property
    /// <summary>
    /// 后处理shader生成的材质
    /// </summary>
    public Material material
    {
        get
        {
            briSatConMaterial = CheckShaderAndCreateMaterial(briSatConShader, briSatConMaterial);
            return briSatConMaterial;
        }
    }
    #endregion

    #region UnityOriginalEvent

    private void Update()
    {
        if (_Split1To2>=_Split2To3)
        {
            _Split1To2 = _Split2To3 - 0.001f;
        }
        if (_Split2To3 >= _Split3To4)
        {
            _Split2To3 = _Split3To4 - 0.001f;
        }
        if (_Split3To4 >= _Split4To5)
        {
            _Split3To4 = _Split4To5 - 0.001f;

        }
    }

    //这个方法会在所有渲染完成后调用
    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (material != null)
        {
            //使用着色器将源纹理复制到目标渲染纹理。
           
            material.SetTexture("_SplitTex1", _SplitTex1);
            material.SetTexture("_SplitTex2", _SplitTex2);
            material.SetTexture("_SplitTex3", _SplitTex3);
            material.SetTexture("_SplitTex4", _SplitTex4);
            material.SetTexture("_SplitTex5", _SplitTex5);
            material.SetTextureScale(Shader.PropertyToID("_SplitTex1"), uv);

            material.SetFloat("_Split1To2", _Split1To2);
            material.SetFloat("_Split2To3", _Split2To3);
            material.SetFloat("_Split3To4", _Split3To4);
            material.SetFloat("_Split4To5", _Split4To5);
            
     

    Graphics.Blit(src, dest, material);
        }
        else
        {
            Graphics.Blit(src, dest);
        }
    }
    #endregion

    #region Function

    #endregion

}

3.4 本教程所用到的文件:

像素图下载

4.参考

像素画高级教程:1bit像素画画法|白色|灰色_网易订阅 (163.com)

最后修改:2023 年 10 月 19 日
如果觉得我的文章对你有用,请随意赞赏