Photoshop でアルファ付き PNG ファイルを正確に作る

**50% グレーでアルファ出力したら 50% にならないんだが？**
そんな問題に対する解決！
結論だけ知りたい人は [まとめ節](#まとめ) までジャンプ！


# はじめに
アルファ付きテクスチャは Unity や Blender などでの 3DCG 製作上、しばしば扱うアセットです。
半透明の不透明度や、PBR といったシェーダのパラメータ値などを表現するために使用されます。
現代では Substance 3D Painter などのツールで製作してアルファ付きテクスチャを生成することも多いでしょう。
一方で昔ながらの Adobe Photoshop で手描きをして製作することもまだまだ多いと思います。

しかし Photoshop はあくまで写真編集・印刷にルーツを持つソフトウェアです。
それとは用途を異にする 3DCG 用アセット製作においては、思わぬ落とし穴が存在します。

では実際に製作してみましょう。

# まずは普通に製作してみる

1. Photoshop で新規ファイルを作成
2. 新規レイヤー A を作成
3. 背景レイヤーを削除
4. レイヤー A を黒 (#000000) で塗りつぶす
5. レイヤー A に対してレイヤーマスクを作成
6. レイヤーマスクを 50% グレー (#808080) で塗りつぶす
7. ファイル -> 書き出し -> PNG としてクイック書き出し

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/bb095ba7-a770-d50e-544f-f55de0e6493c.png">

いいですね！ RGB が黒 (#00000) でアルファが 50% の PNG ファイルが製作できたはずです。
ではこのファイルを Unity に放り込んで、自作のシェーダで表示してみましょう。
このシェーダはアルファチャンネルの値に応じてその高さに直線を引いて図示してくれます。

<details><summary>ShowAlpha.shader</summary>

```hlsl
Shader "Unlit/ShowAlpha"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    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;
                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
            {
                float alpha = tex2D(_MainTex, i.uv).a;
                float y = i.uv.y;
                float distance = abs(alpha - y);

                float value = saturate(distance * 50);
                return float4(value.xxx, 1);
            }
            ENDCG
        }
    }
}
```

</details>

アルファは 50% なので、真ん中に直線が引かれるはずです……！

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/91d9b031-0d8b-578f-b365-cccc52967f63.png">

あれ？なんだか 30% 付近に直線が引かれていますね……
50% ではないようです。

このように何も考えずに Photoshop でアルファ付き PNG ファイルテクスチャを製作すると、意図しない値になってしまいます。
こんなことでは、「この UI 画像はアルファ 50% にしよう！」といった調整に支障をきたしてしまいます。

# なにが間違っているのか
結論から言います。
この問題は **Photoshop の作業カラースペース** に起因するものです。
カラースペースを誤認していたため、先の製作工程で **50% グレーだと思っていた色はそうではなかった** のです。

最初に述べたように Photoshop は写真編集・印刷用途にルーツがあります。
グレーカラーといえばモノクロオフセット印刷用途であり、そういった印刷機は点描のようなトーン印刷がなされます。
したがって Photoshop の初期設定では **グレーカラーはトーン印刷での見た目の評価に適した色空間になっています**。
先の制作工程で 50% グレーだと思っていた色はあくまで **トーン印刷時に 50% グレーになる色だった** のです。

実際に Photoshop のカラー設定を見てみましょう。
上のメニューから `編集` -> `カラー設定` を開きます。

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/b7f1229f-279d-ce24-db34-a736144afae9.png">

`作業用スペース` の `グレー` の項目が `Dot Gain 15%` になっています。
下の `説明` に書かれているように、これはドットゲイン、つまりトーン印刷に適した色空間です。

# 解決する
では実際に解決しましょう。

ただし以下の解決方法は Photoshop アプリケーション自体の設定変更になります。
**普段印刷物を製作する方は、用途に応じて設定を切り替えないと、逆に印刷物の見た目が悪くなる可能性があります。** 注意してください。

左上の `設定` から `Web・インターネット用 - 日本` プリセットを選択しましょう。
そうすると `グレー` の `作業用スペース` が `Gray Gamma 2.2` になったのが分かると思います。

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/ec6e2c90-17e1-b299-727f-ac2c04c691b2.png">

そして `OK` を押し、設定を適用します。

ではさきほど製作したファイルの 50% グレーだと思っていた色をスポイトで拾ってみましょう。

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/1f83ec30-eafa-c643-c17f-99af7d98ccba.png">

なんと 36% グレーです！
さきほど **50% グレーだと思っていた色は 36% グレーだった** のです。
Unity のシェーダで図示された結果とも合致しますね。

ではこの作業用カラースペースのまま、カラーピッカで 50% グレーを選び、塗りつぶしましょう。

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/355dbded-56bc-3ca0-a0da-40bbab3cdffb.png">

先ほどより若干明るくなりましたね。
この状態で再度 PNG としてクイック書き出しを行います。
そして Unity で再度、アルファチャンネルの値を確認してみます。

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/c8d9d271-b3ee-ce54-8620-c34c09b795d1.png">

**やりました！** 直線が真ん中に引かれています。 **50% のアルファ値です！**
詳細は割愛しますが、シェーダ内部の値も正しく `0.5` が渡ってきていることは確認できました。

これにて解決です。

# まとめ

- Photoshop で作業用カラースペースを意識せずアルファ値を製作すると、意図しない値になる
- Photoshop の初期設定は印刷用の作業用カラースペースになっている
- アルファ作業用には Photoshop のグレー向け作業用カラースペースを `Gray Gamma 2.2` にする (下図参照)
- 作業用カラースペースはアプリの設定なので、印刷物用に Photoshop を使用する人はこの設定を都度切り替える必要がある

<img width="600px" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48638/ec6e2c90-17e1-b299-727f-ac2c04c691b2.png">