知識0からのUnityShader勉強

知識0からのUnityShader勉強

UnityのShaderをメインとして、0から学んでいくブログです。

【UnityShader】ShaderLabのプロパティ属性 【1】#77

前回の成果

ポリゴン分解シェーダーを制作した。

soramamenatan.hatenablog.com


今回やること

ShaderLabのプロパティの属性について解説します。


プロパティの属性とは

パラメーターに対して、inspector上から値を設定することが出来るものになります。

f:id:soramamenatan:20201030112944p:plain


HideInInspector

inspector上から値を非表示にすることができます。
_HideValueが非表示になっていることがわかると思います。

Properties {
    _MainTex ("Texture", 2D) = "white" {}
    [HideInInspector] _HideValue ("HideValue", int) = 0
    _ShowValue ("ShowValue", int) = 0
}

f:id:soramamenatan:20201030114318p:plain


NoScaleOffset

テクスチャデータのTilingとOffsetを非表示にすることができます。

Properties {
    [NoScaleOffset]_MainTex ("Texture", 2D) = "white" {}
}

f:id:soramamenatan:20201030114505p:plain


Normal

アタッチされているテクスチャが法線マップであることを示しています。

Properties {
    [Normal]_MainTex ("Texture", 2D) = "white" {}
}

f:id:soramamenatan:20201030115600p:plain

なお、法線マップかはテクスチャのinspectorのTexture Typeで判断しています。

f:id:soramamenatan:20201030115603p:plain


また、法線マップでは無いものをアタッチした際には警告が出ます。
試しに、Sprite(2D and UI)の元をアタッチしてみます。
f:id:soramamenatan:20201030120129p:plain

すると、このテクスチャは法線マップではありませんといった旨のメッセージと、Fix Nowのボタンが出てきます。

f:id:soramamenatan:20201030120118p:plain

Fix Nowを押下すると、アタッチされているテクスチャが自動で法線マップへと置き換わります。

f:id:soramamenatan:20201030120121p:plainf:id:soramamenatan:20201030120124p:plain


HDR

アタッチされているテクスチャがHDRテクスチャであることを示しています。

Properties {
    [HDR]_MainTex ("Texture", 2D) = "white" {}
}

f:id:soramamenatan:20201030121951p:plain


HDRとは

HDRとは、普通のテクスチャ(SDRテクスチャ)よりも明るさの表現の範囲を広げたテクスチャになります。
SDRは各色を0.0~1.0で保持しているのに対し、HDRは~65504まで保持できます。

HDRを使用することにより、白飛びや黒つぶれを防ぐことが出来ます。

白飛びしているもの

f:id:soramamenatan:20201030123039j:plain

【Unity】HDRってなんやねーん!という人のための解説 │ エクスプラボ:より引用

白飛びを防いだもの

f:id:soramamenatan:20201030123042j:plain 【Unity】HDRってなんやねーん!という人のための解説 │ エクスプラボ:より引用

HDRに関しては以下サイト様が分かりやすかったです。

ekulabo.com

hikita12312.hatenablog.com

qiita.com

なお、通常のテクスチャをアタッチしてもNormalとは違い警告はでません。

f:id:soramamenatan:20201030121954p:plain


Gamma

FloatかVectorプロパティがsRGB値で指定されていて、使用するカラースペースに応じて変換が必要なことを示しています。

Properties {
    _MainTex ("Texture", 2D) = "white" {}
    [Gamma] _GammaFloat ("Gamma Float", float) = 0
    [Gamma] _GammaVector ("Gamma Vector", Vector) = (0, 0, 0, 0)
}

f:id:soramamenatan:20201030144948p:plain


カラースペースとは

立方的に記述される色の空間である。
カラースペースともいう。
色を秩序立てて配列する形式であり、色を座標で指示できる。

色空間 - Wikipedia:より引用

Unityでは、リニア色空間とガンマ色空間の2つがあります。

2つの空間では、色の見え方が異なっています。
左がリニア色空間で、右がガンマ色空間の見え方となります。

f:id:soramamenatan:20201030145454p:plain

リニアレンダリング概要 - Unity マニュアル:より引用

リニア色空間は、数字上正しくあるためにライティングの計算などで使用されます。
ガンマ色空間は、人間の目に正しく見えるために使用されます。


リニア色空間を使用する際に、ColorプロパティはsRBGカラーで提供され、シェーダーに渡される時にリニア色空間の値へと変換されます。
しかし、FloatとVectorプロパティの場合は色空間の変換を自動で行ってくれません
理由は、Unityから見た時にFloatとVectorプロパティはColorで使用しているのかがわからないからです。
そこで、明示的にGamma属性をつけてあげることにより、色空間の変換を行ってくれるようになります。


リニア色空間、ガンマ色空間に関しては以下サイト様が分かりやすかったです。

docs.unity3d.com

shop-0761.hatenablog.com


PerRendererData

テクスチャデータをMaterialPropertyBlockクラスのインスタンス時の値で初期化します。
inspector上では、非表示となります。

Properties {
    [PerRendererData]_MainTex ("Texture", 2D) = "white" {}
}

f:id:soramamenatan:20201030152834p:plain


MaterialPropertyBlockクラス

このクラスは同一マテリアルのプロパティをインスタンスせずに変えることができるクラスとなっています。

実際に実装してみます。

まず、簡単に色を変えるシェーダーを制作します。

Shader "Unlit/materialPropertyBlock" {
    Properties {
        _Color ("Color", Color) = (1, 1, 1, 1)
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex : POSITION;
            };

            struct v2f {
                float4 vertex : SV_POSITION;
            };

            fixed4 _Color;

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

            fixed4 frag (v2f i) : SV_Target {
                return _Color;
            }
            ENDCG
        }
    }
}

そして、このシェーダーを適当な2つのオブジェクトへとアタッチします。

オブジェクトAのinspector

f:id:soramamenatan:20201030162615p:plain

オブジェクトBのinspector

f:id:soramamenatan:20201030162618p:plain

同じマテリアルなので、見た目も同じとなります。

Scene上

f:id:soramamenatan:20201030162621p:plain

オブジェクトAのみ赤色に変更しようとします。
オブジェクトAのマテリアルのColorプロパティを変更してみます。

オブジェクトAのinspector

f:id:soramamenatan:20201030162854p:plain

しかし先程も説明した通り、同じマテリアルを使用しているためBも赤色となってしまいます。

Scene上

f:id:soramamenatan:20201030162857p:plain

今回は色を変えたいだけなのに、わざわざマテリアルを複製するのも手間です。
2つ程度なら良いですが、100個、10000個となってくると話が変わってきます。
そこで、MaterialPropertyBlockの出番となります。


まずは以下のScriptを各オブジェクトにアタッチします。

using UnityEngine;

public class MaterialPropertyBlockTest : MonoBehaviour {
    [SerializeField]
    private Color _color;

    void Start() {
        MeshRenderer renderer = GetComponent<MeshRenderer>();
        MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock();
        materialPropertyBlock.SetColor("_Color", _color);
        renderer.SetPropertyBlock(materialPropertyBlock);
    }
}

そしてColorも各オブジェクトで変更してみます。

オブジェクトAのinspector

f:id:soramamenatan:20201030163417p:plain

オブジェクトBのinspector

f:id:soramamenatan:20201030163421p:plain

実行すると同一マテリアルなのに、各オブジェクトで色が異なっていることを確認できます。

Scene上

f:id:soramamenatan:20201030163518p:plain

オブジェクトAのinspector

f:id:soramamenatan:20201030163522p:plain

オブジェクトBのinspector

f:id:soramamenatan:20201030163526p:plain


MainTexture

対象のプロパティが、マテリアルのメインテクスチャであることを示します。
デフォルトでは、プロパティ名が_MainTexのものをメインテクスチャとしています。
なお、複数回この属性が呼ばれた場合には一番最初のプロパティをメインテクスチャにし、後のプロパティは無視されます。

Properties {
    _MainTex ("Texture", 2D) = "white" {}
    [MainTexture]_SubTex1 ("Sub Texture1", 2D) = "white" {}
    // MainTextureと見なされない
    [MainTexture]_SubTex2 ("Sub Texture2", 2D) = "white" {}
}

f:id:soramamenatan:20201030165423p:plain


MainColor

対象のプロパティが、マテリアルのメインカラーであることを示します。
デフォルトでは、プロパティ名が_Colorのものをメインカラーとしています。
なお、複数回この属性が呼ばれた場合には一番最初のプロパティをメインカラーにし、後のプロパティは無視されます。

Properties {
    _MainTex ("Texture", 2D) = "white" {}
    _Color ("Color", Color) = (1, 1, 1, 1)
    [MainColor]_SubColor1 ("Sub Color1", Color) = (1, 1, 1, 1)
    // MainColorと見なされない
    [MainColor]_SubColor2 ("Sub Color2", Color) = (1, 1, 1, 1)
}

f:id:soramamenatan:20201030170116p:plain


Space

対象のプロパティの上部にスペースを入れます。
また、値を入れることでスペースの幅を調整することができます。

Properties {
    _MainTex ("Texture", 2D) = "white" {}
    _NotSpace ("Not Space", int) = 0
    [Space] _SpaceA ("Space A", int) = 0
    [Space(50)] _SpaceB ("Space B", int) = 0
    [Space(100)] _SpaceC ("Space C", int) = 0
}

f:id:soramamenatan:20201101091011p:plain


今回は以上となります。
ここまでご視聴ありがとうございました。


参考サイト様

qiita.com

baba-s.hatenablog.com

docs.unity3d.com