3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unity カラーパレットとノイズによる絵作り

Posted at

作ったもの

以下のようなエフェクトを作りました。
元画像
image.png

image.png

これだけならシンプルなカラーパレットなので、ノイズを加える事で印刷感を足しました。

image.png

上記のシーンは以下のアセットをお借りしました。
https://assetstore.unity.com/packages/3d/environments/free-medieval-room-131004

アルゴリズム

1枚目の単純なカラーパレットを適用するシェーダは以下の通りです。

Shader "Hidden/ColorPalette"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color1 ("Color1", Color) = (1,1,1,1)
        _Color2 ("Color2", Color) = (1,1,1,1)
        _Color3 ("Color3", Color) = (1,1,1,1)
        _Color4 ("Color4", Color) = (1,1,1,1)
        _Color5 ("Color5", Color) = (1,1,1,1)
        _Color6 ("Color6", Color) = (1,1,1,1)
        _Color7 ("Color7", Color) = (1,1,1,1)
        _Color8 ("Color8", Color) = (1,1,1,1)
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

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

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            float4 _Color1;
            float4 _Color2;
            float4 _Color3;
            float4 _Color4;
            float4 _Color5;
            float4 _Color6;
            float4 _Color7;
            float4 _Color8;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                float distances[8] = {
                    distance(col, _Color1),
                    distance(col, _Color2),
                    distance(col, _Color3),
                    distance(col, _Color4),
                    distance(col, _Color5),
                    distance(col, _Color6),
                    distance(col, _Color7),
                    distance(col, _Color8),
                };

                float4 colors[8] = {
                    _Color1,
                    _Color2,
                    _Color3,
                    _Color4,
                    _Color5,
                    _Color6,
                    _Color7,
                    _Color8
                };

                fixed4 resultCol = colors[0];
                float minDistance = distances[0];

                for(int i = 1; i < 8; i++){
                    resultCol = minDistance > distances[i] ? colors[i] : resultCol;
                    minDistance = minDistance > distances[i] ? distances[i] : minDistance;
                }

                return resultCol;
            }
            ENDCG
        }
    }
}

ここでは、8色によるパレットを使用しています。
パレットは以下をお借りしました。

image.png

パレットに加えてノイズを付加するシェーダは以下の通りです。

Shader "Hidden/Dithering"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color1 ("Color1", Color) = (1,1,1,1)
        _Color2 ("Color2", Color) = (1,1,1,1)
        _Color3 ("Color3", Color) = (1,1,1,1)
        _Color4 ("Color4", Color) = (1,1,1,1)
        _Color5 ("Color5", Color) = (1,1,1,1)
        _Color6 ("Color6", Color) = (1,1,1,1)
        _Color7 ("Color7", Color) = (1,1,1,1)
        _Color8 ("Color8", Color) = (1,1,1,1)

        _DitheringThreshold ("DitheringThreshold", Float) = 0.5
        _RandomFactor ("RandomFactor", Float) = 5000
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

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

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            float4 _Color1;
            float4 _Color2;
            float4 _Color3;
            float4 _Color4;
            float4 _Color5;
            float4 _Color6;
            float4 _Color7;
            float4 _Color8;

            float _DitheringThreshold;
            float _RandomFactor;

            fixed4 quantize(float4 col){
                float distances[8] = {
                    distance(col, _Color1),
                    distance(col, _Color2),
                    distance(col, _Color3),
                    distance(col, _Color4),
                    distance(col, _Color5),
                    distance(col, _Color6),
                    distance(col, _Color7),
                    distance(col, _Color8),
                };

                float4 colors[8] = {
                    _Color1,
                    _Color2,
                    _Color3,
                    _Color4,
                    _Color5,
                    _Color6,
                    _Color7,
                    _Color8
                };

                fixed4 resultCol = colors[0];
                float minDistance = distances[0];

                for(int i = 1; i < 8; i++){
                    resultCol = minDistance > distances[i] ? colors[i] : resultCol;
                    minDistance = minDistance > distances[i] ? distances[i] : minDistance;
                }

                return resultCol;
            }

            float rand(float f){
                return (frac(sin(f) * _RandomFactor) - 0.5) * 2;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                
                float randomX = rand(i.uv.x);
                float randomY = rand(i.uv.y);
                float random = rand(randomX + randomY + rand(col.r) + rand(col.g) + rand(col.b));
                if(random < _DitheringThreshold){
                    return quantize(col);
                }

                return quantize(col + rand(random) / 2.0);
            }
            ENDCG
        }
    }
}

冒頭のスクショのパラメータは以下の通りです。

image.png

乱数の生成は以下の記事を参考にさせていただきました。

シード値にピクセルのUVと色を使用しているので、カメラを動かすとノイズのかかり方も変わります。

最初に float random を計算し、その値が閾値以上かどうかでそのピクセルにノイズが入るかどうかが決まります。
その値をそのままピクセルに加えると明るい色だけが入ってきてしまうので、再度その random をシードとして乱数を再計算することで、ノイズの色をランダムにしています。
2で割る事で、ノイズの影響を抑えています。

パレットを変えると暗視ゴーグル風の見た目とかもできます。
image.png

(以下のパレットをベースに色を足しています)

image.png

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?