Unity3D像素化滤镜shader的实现

实现思路

像素化就是使许多相邻像素都变成一个像素,自然看上去就会有像素化的效果了。
根据这个思路,马上可以想到一种做法就是将屏幕分成若干个区域,每个区域由若干个相邻的像素组成,每个区域都是一个正方形,然后计算正方形的卷积作为这个区域的颜色。
这种做法会稍微麻烦一些,今天我们写的这个shader单纯采样了这个区域里的一个像素代表这整个区域的颜色。
可能听上去有些不靠谱,但是实际看起来还是效果不错的,毕竟都是像素化效果了,有些误差说不定还会更好看一些。

代码实现

编写一个函数传入uv返回颜色,我们这个先把uv转化为屏幕坐标方便计算,之后除以我们需要的像素块大小,再使用floor函数向下取整,之后再乘回像素块大小,就可以得到某一块区域的颜色都相同的效果了。这样一个像素化shader就完成了,没错就是这么简单。

    half4 pixel(half2 uv)
    {
        half2 screenPos = floor(uv * _ScreenParams.xy / _PixelSize) * _PixelSize;
        return tex2D(_MainTex, screenPos / _ScreenParams.xy);
    }

原图在这里插入图片描述
像素化之后在这里插入图片描述
我们最后再增加一个条纹效果。使屏幕上可以出现45度的斜线条纹。
这个计算也是根据简单的线性函数y=x+nk ,其中x,y为坐标,n为像素大小,k为任意整数。我们的目标是是把满足这个函数的x,y坐标涂黑。
变换该式之后可以发现(y-x)%n=0
我们根据该式进行测试就可以了,还有一个y=-x+nk也是同理

    half2 stitch(half2 uv)
    {
        half2 screenPos = floor(uv * _ScreenParams.xy);
        half2 reminder;
        reminder.y = (screenPos.y - screenPos.x) % _PixelSize;
        reminder.x = (screenPos.y + screenPos.x) % _PixelSize;
        return reminder;
    }

最后在片元着色器里判断余数是不是0

 return (reminder.y == 0 || reminder.x == 0)&&_AddStrip==1 ? half4(0, 0, 0, 1) : color;

添加条纹之后的效果
在这里插入图片描述

完整代码

c#代码

namespace Colorful
{
    using UnityEngine;

    [ExecuteInEditMode]
    public class Pixelate : MonoBehaviour
    {
        public Shader shader;
        public int    PixelSize = 8;
        public bool   AddStrip;

        protected void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            Material material = new Material(shader);
            material.SetInt("_PixelSize", PixelSize);
            material.SetInt("_AddStrip", AddStrip ? 1 : 0);
            Graphics.Blit(source, destination, material);
        }
    }
}

shader代码

Shader "LX/Pixelate"
{
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }

    CGINCLUDE
    #include "UnityCG.cginc"

    sampler2D _MainTex;
    int _PixelSize;
    int _AddStrip;

    half2 stitch(half2 uv)
    {
        half2 screenPos = floor(uv * _ScreenParams.xy);
        half2 reminder;
        reminder.y = (screenPos.y - screenPos.x) % _PixelSize;
        reminder.x = (screenPos.y + screenPos.x) % _PixelSize;
        return reminder;
    }

    half4 pixel(half2 uv)
    {
        half2 screenPos = floor(uv * _ScreenParams.xy / _PixelSize) * _PixelSize;
        return tex2D(_MainTex, screenPos / _ScreenParams.xy);
    }

    half4 frag(v2f_img i) : SV_Target
    {
        half2 reminder = stitch(i.uv);
        half4 color = pixel(i.uv);
        return (reminder.y == 0 || reminder.x == 0)&&_AddStrip==1 ? half4(0, 0, 0, 1) : color;
    }
    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

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值