27
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Unity】【Shader】Blendを試してみる

Last updated at Posted at 2019-10-08

Unityのシェーダーのコードを読んでいるとBlendは当たり前のように出てくるが、重要そうな割に全然理解していなかったので、いくつかサンプルを作りながら理解してみる。

#Blend SrcFactor DstFactor

よく見るパターンはこれ。Blend SrcFactor DstFactor

公式ページには次のように説明されている。

Blend SrcFactor DstFactor: Configure and enable blending. The generated color is multiplied by the SrcFactor. The color already on screen is multiplied by DstFactor and the two are added together.

SrcFactor

The generated color is multiplied by the SrcFactor.

つまり、**"Fragmentシェーダーでreturnされた色"**にSrcFactorを乗算する。

DstFactor

The color already on screen is multiplied by DstFactor

該当Shaderが処理される前に、すでに画面に描画されている色にDstFactorを乗算する。

最終的に描画される色

上記二つの色を加算するので、次のようになる。

Shaderで計算した色 * SrcFactor + 既に画面に描画されている色 * DstFactor

検証

青(0,0,1)のPlaneの上方向に、赤(1,0,0)から緑(0,1,0)のグラデーションテクスチャをセットしたQuadを配置。このQuadのにセットしたシェーダーでBlendを変更してみる。

スクリーンショット 2019-10-08 9.58.38.png

Blend factors

公式ページによるとBlend factorは10個あって、SrcFactorとDstFactorに設定できるので、合計100通りの組み合わせがあることにある。
全部確認するのは大変なので、その内のいくつかを試してみる。

One, Zero

  • Shaderで計算した色 * One = Shaderで計算した色
  • 既に画面に描画されている色 * Zero = (0,0,0)

っといった風に各色をそのまま使用するか、あるいは黒にしてしまう。

Blend One One

赤(1,0,0) * 1 + 青(0,0,1) * 1 = (1,0,1)
から
緑(0,1,0) * 1 + 青(0,0,1) * 1 = (0,1,1)
へのグラデーションになっているっぽい

スクリーンショット 2019-10-07 9.37.33.png

Blend Zero One

シェーダーで計算された色に0を乗算するので、既にあるPlaneの色だけが描画される。

赤(1,0,0) * 0 + 青(0,0,1) * 1 = (0,0,1)
緑(0,1,0) * 0 + 青(0,0,1) * 1 = (0,0,1)

スクリーンショット 2019-10-07 9.42.14.png

Blend One Zero

既にあるPlaneの色に0をかけるので、グラーデーションの色が描画される

赤(1,0,0) * 1 + 青(0,0,1) * 0 = (1,0,0)
緑(0,1,0) * 1 + 青(0,0,1) * 0 = (0,1,0)

スクリーンショット 2019-10-07 9.46.35.png

Blend Zero Zero

シェーダーで計算された色、既にあるPlaneの色のどちらにも0を乗算するので、黒(0,0,0)になる

赤(1,0,0) * 0 + 青(0,0,1) * 0 = (0,0,0)
緑(0,1,0) * 0 + 青(0,0,1) * 0 = (0,0,0)

スクリーンショット 2019-10-07 9.48.53.png

SrcColor, DstColor

SrcColor

The value of this stage is multiplied by the source color value.

Shaderで計算された色を乗算する

DstColor

The value of this stage is multiplied by frame buffer source color value

既に描画されている(実際にはバッファに保存されている?)色を乗算する。

Blend Zero SrcColor

シェーダーで計算した色とPlaneの色は被っている要素がないので、Quadを配置した部分は黒(0,0,0)になる。

赤(1,0,0) * 0 + 青(0,0,1) * 赤(1,0,0) = (0,0,0)
緑(0,1,0) * 0 + 青(0,0,1) * 緑(0,1,0) = (0,0,0)

スクリーンショット 2019-10-08 7.28.37.png

Blend DstColor Zero

この場合もQuadは黒になる。

赤(1,0,0) * 青(0,0,1) + 青(0,0,1) * 0 = (0,0,0)
緑(0,1,0) * 青(0,0,1) + 青(0,0,1) * 0 = (0,0,0)

Blend SrcColor Zero

シェーダーで計算した色を2乗することになるので、全体的に暗くなる。
例えば(0.5, 0.5, 0)の点を考えると

(0.5, 0.5, 0) * (0.5, 0.5, 0) + 青(0,0,1) * 0 = (0.25, 0.25 ,0)

スクリーンショット 2019-10-08 8.30.22.png

OneMinusSrcColor, OneMinusDstColor

OneMinusSrcColor

The value of this stage is multiplied by (1 - source color).

(1 - Shaderで計算された色)を乗算する。仮に計算された色が(0.3, 0.3, 0.3)だとしたら、(0.7, 0.7, 0.7)が乗算される。

OneMinusDstColor

The value of this stage is multiplied by (1 - destination color).

Blend Zero OneMinusSrcColor

Planeの青だけになる。

赤(1,0,0) * 0 + 青(0,0,1) * (1 - (1,0,0))
= 0 + (0,0,1) * (0,1,1)
= (0,0,1)

緑(0,1,0) * 0 + 青(0,0,1) * (1 - (0,1,0))
= 0 + (0,0,1) * (1,0,1)
= (0,0,1)

スクリーンショット 2019-10-08 8.54.21.png

Blend OneMinusSrcColor Zero

(0.5,0.5,0)点で考えると、
(0.5,0.5,0) * (1 - (0.5,0.5,0)) + 青(0,0,1) * 0
= (0.5,0.5,0) * (0.5,0.5,1) + 0
= (0.25,0.25,0)

画像はちょっと分かりにくいが、暗い黄色のグラデーションになる。

スクリーンショット 2019-10-08 9.39.03.png

アルファも試してみる

アルファによる変化がわかりやすいようにPlaneのテクスチャを以下のような画像に変更。

スクリーンショット 2019-10-09 13.44.14.png

SrcAlpha

The value of this stage is multiplied by the source alpha value.

Shaderで計算されたアルファを乗算する。

DstAlpha

The value of this stage is multiplied by frame buffer source alpha value.

フレームバッファに保存されたアルファを乗算する。

OneMinusSrcAlpha

The value of this stage is multiplied by (1 - source alpha).

OneMinusDstAlpha

The value of this stage is multiplied by (1 - destination alpha).

Blend SrcAlpha OneMinusSrcAlpha

公式によるとこれば一般的な透過設定とのこと。
アルファを以下の様にフラグメントシェーダーで変更した場合を考えてみる。

アルファを指定.glsl
fixed4 frag (v2f i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    col.a = ここを変更;
    return col;
}
前提

フラグメントシェーダーで計算された色は赤(1,0,0)、Planeの色は白(1,1,1)の点を例にとって考えてみる。

アルファを0.1とした場合

col.a = 0.1の場合は以下のように計算して、ブレンド後の色は白に近くなる。

赤(1,0,0) * 0.1 + 白(1,1,1) * (1 - 0.1)
= (0.1, 0, 0) + (0.9, 0.9, 0.9)
= (1, 0.9, 0.9)

スクリーンショット 2019-10-09 12.25.02.png
アルファを0.9とした場合

col.a = 0.9の場合は以下のように計算して、ブレンド後の色はほぼ赤となる。

赤(1,0,0) * 0.9 + 白(1,1,1) * (1 - 0.9)
= (0.9, 0, 0) + (0.1, 0.1, 0.1)
= (1, 0.1, 0.1)

スクリーンショット 2019-10-09 12.24.52.png

Blend SrcAlpha SrcAlpha

こんな設定をすることは無いだろうけど、確認のためにこの設定もためしてみる。

アルファを0.1とした場合

赤(1,0,0) * 0.1 + 白(1,1,1) * 0.1
= (0.1, 0, 0) + (0.1, 0.1, 0.1)
= (0.2, 0.1, 0.1)

黒に近くなる。

スクリーンショット 2019-10-09 13.56.08.png
アルファを0.9とした場合

白に近くなる。

赤(1,0,0) * 0.9 + 白(1,1,1) * 0.9
= (0.9, 0, 0) + (0.9, 0.9, 0.9)
= (1.0, 0.9, 0.9)

スクリーンショット 2019-10-09 13.58.06.png

今回のコード

コード自体は新規作成したUnlitシェーダーに以下の変更をしただけ。

  • Fogの記述を削除
  • Tagを変更
  • Blendを追加
.glsl
Shader "Unlit/SH_GradientColor"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue" = "Transparent" }
        LOD 100

//        Blend One One

        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;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

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

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

参考

27
19
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
27
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?