趣旨
うちの会社では、シェーダ等の案件が多いので、メンバーの教育のため
UNITYを使ってシェーダを勉強しよう!
という目的だったのだが
UNITYのシェーダは、組み込み関数など、独自に覚えることも多かったので
その部分を 勉強しながらまとめていく
とりあえず 今回は去年のUNITY
UNITY2017.1.0f3
なので 今は少しコードが変わっているかもしれない
シェーダーの種類
UNITYでは
- お手軽な SurfaceShader
- 本格的な UnlitShader
- ポストプロセス用 ImageEffectShader
- GPGPU ComputeShader
- シェーダーのプリロードを行う ShaderVariantCollection
があるが、とりあえずは通常使う UnlitShaderから覚える
ただし、SurfaceShaderも簡単にふれておく
SurfaceShaderを試す
概要
本来は シェーダーでは 最低2つのシェーダ、頂点シェーダと フラグメントシェーダが必要である
が、SurfaceShaderでは、頂点シェーダーだけ記述し、フラグメントシェーダはビルトインを指定するだけで書かなくていい
もちろん フラグメントシェーダも、カスタムライティングを使えば 独自に作る事ができるが
個人的には それなら あとで話す UnlitShaderで 頂点シェーダとフラグメントシェーダを作ればいいと思う
サンプルのモデル読み込み
今回は中野シスターズを使う(UnityChanをあえて使わない)
http://nakasis.com/
ファイルをダウンロードしてUNITYにインポートし、Sceneに貼り付ける
シェーダの確認
中野シスターズには Standardというビルトインシェーダーが使われている
ビルトインシェーダーは下記からダウンロードできる
https://unity3d.com/jp/get-unity/download/archive
Standardシェーダの中身は
Shader "Custom/NewSurfaceShader" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_CBUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_CBUFFER_END
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
解析
シェーダー名
Shader "Custom/NewSurfaceShader" {
シェーダー名。UNITYからはこの名前で呼べる
Properties
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
インスペクターで設定する値(パラメータ)
シェーダ内で識別する名前 ("インスペクターに表示する名前", 型 ) = デフォルト値
という形式だ
条件
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
SubShaderは複数作れる。
TagsやLODに条件を指定しており
SubShaderを上から順番に 最初に一致したSubShaderを実行する
全てに一致しない場合は 下記のFallbackが実行される
FallBack "Diffuse"
コンパイルディレクティブ
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
UNITYマニュアルによると
# pragma surface surfaceFunction lightModel [optionalparams]
上記の場合は
サーフェースシェーダは surf という関数
ライトモデルは Standard
Optionは fullforwardshadows
ということになる
ライトモデルは 下記の4つがビルトインで用意されている
- Standard: 物理ベースレンダリング
- StandardSpecular: 物理ベース with スペキュラー
- Lambert: 非物理ベース
- BlinnPhong: 非物理ベース with スペキュラー
ちなみに fullforwardshadows のオプションは
フォワードレンダリング時の 影(ドロップシャドウ)を 通常はディレクショナルライト以外は表示しないが
このオプションがあれば スポットライトやポイントライトでも影がつくらしい
変数部
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
UNITY_INSTANCING_CBUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_CBUFFER_END
変数(uniform)部分
_MainTex 等は 上記のインスペクターの値をここで定義してはじめて使えるようになる
UNITY_INSTANCING_CBUFFER_START
は c_bufferを使う時に使うマクロ
struct Input
は、SurfaceShaderにわたす入力構造体(attribute)だ
セマンティクスがないのも特徴だ
Surfaceシェーダ本体
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
中身はパット見でわかるとおもうが、構造体に各パラメータを渡している
struct SurfaceOutputStandard
{
fixed3 Albedo; // ベース (ディフューズかスペキュラー) カラー
fixed3 Normal; // 書き込まれる場合は、接線空間法線
half3 Emission;
half Metallic; // 0=非メタル, 1=メタル
half Smoothness; // 0=粗い, 1=滑らか
half Occlusion; // オクルージョン (デフォルト 1)
fixed Alpha; // 透明度のアルファ
};
今回は ライトモデルに Standardを使っているので SurfaceOutputStandardを returnする
また
StandardSpecula、Lambert、BlinnPhong の場合は
struct SurfaceOutputStandardSpecular
{
fixed3 Albedo; // ディフューズ色
fixed3 Specular; // スペキュラー色
fixed3 Normal; // 書き込まれる場合は、接線空間法線
half3 Emission;
half Smoothness; // 0=粗い, 1=滑らか
half Occlusion; // オクルージョン (デフォルト 1)
fixed Alpha; // 透明度のアルファ
};
struct SurfaceOutput
{
fixed3 Albedo; // ディフューズ色
fixed3 Normal; // 書き込まれる場合は、接線空間法線
fixed3 Emission;
half Specular; // 0..1 の範囲のスペキュラーパワー
fixed Gloss; // スペキュラー強度
fixed Alpha; // 透明度のアルファ
};
の構造体になる