76
75

More than 5 years have passed since last update.

Unity Shaderの基礎 part 1

Last updated at Posted at 2016-01-24

はじめに

自分の為にUnityのシェーダの基礎から勉強をしていきます。

Unityのシェーダはざっくり分けると以下の3種類があります。

  • サーフェイスシェーダ
  • 頂点/フラグメントシェーダ
  • 固定関数シェーダ

サーフェイスシェーダは、ライティング等を自動で行ってくれます。
頂点/フラグメントシェーダは、ライティングを使わない場合などに使います。
ライティングも可能ですが、全部自力で書く必要があるので、自由度は高いですがその分難易度も高いです。
固定関数シェーダは、プログラマブルシェーダに対応していない古いハードウェア用のものなので、今回は勉強しない方向です。


簡単なサーフェイスシェーダ

いきなりですが、サーフェイスシェーダのサンプルです。

Shader "Custom/surfaceshader001" {
    SubShader {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert

        struct Input {
            float4 color : COLOR;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = half3(0.75, 1.0, 0.5);
        }
        ENDCG
    }
    FallBack "Diffuse"
}

説明

上から順に説明します。


Shader "Custom/surfaceshader001"

シェーダ自身の名前です。
Shader "グループ名/シェーダー名" という感じです。


SubShader {
 ~~
}

シェーダの実装部分です。
ちなみに、1つのシェーダ内にSubShader{}を複数記述することもできます。
その場合は、上から順に実行可能なSubShaderが選択されます。
いろんなハードで動作させるために書き方を変えたりするためです。


Tags { "RenderType"="Opaque" }

Tagsは、SubShaderが「いつ」「どのように」レンダリングされるかの情報です。
この例では、RenderTypeOpaque(不透明)に指定しています。
タグはRenderType以外にも色々ありますが、おいおい紹介していきます。


CGPROGRAM
 ~~
ENDCG

サーフェイスシェーダでは、実際の描画処理をCGPROGRAMENDCGの間に記述します(パスと呼ぶ)
また、一つのSubShaderの中に複数のCGPROGRAMENDCGを記述することもできます。
その場合、上から順に実行されていきます。
複数のSubShaderの時とは違い、順番に全て実行されます。
例えば、モデルに輪郭線を付けたい時は下記のように指定します。

  • 1パス目で、頂点を法線方向に膨らませて黒ベタで裏面描画
  • 2パス目で、通常描画

#pragma surface surf Lambert

#pragma surfaceでUnityにサーフェイスシェーダである事を宣言しています。
その後のsurfが、エントリ関数の名前です。
その後のLambertは、ライティングモデルの指定で、ランバート反射を指定しています。
ライティングモデルは、他にもスペキュラや自作のライティング関数を使ったり出来ます。
#pragmaは他にも色々オプションが指定できますが、おいおい紹介していきます。


struct Input {
    float4 color : COLOR;
};

次のsurf関数に渡す構造体の指定です。
float4は4つのfloat型がセットになった変数です。
:のあとの大文字のCOLORは、セマンティクスといって、Unityから渡される情報の意味を指定します。
COLORは、頂点カラー(頂点自体の色)を意味します。
名前の付け方やセマンティクスは決まっていますが、おいおい紹介していきます。


void surf (Input IN, inout SurfaceOutput o) {
    o.Albedo = half3(0.75, 1.0, 0.5);
}

サーフェイスシェーダのエントリ関数です。
引数のInput INは、前述のInput構造体の情報が入っています。
inout SurfaceOutput oは、入力されたデータを色々して詰め込んで出力する構造体で、下記の変数が入っています。

struct SurfaceOutput {
    half3 Albedo;   // 拡散反射光(=Diffuse)、物体の色
    half3 Normal;   // 法線ベクトル
    half3 Emission; // 発光色
    half Specular;  // スペキュラ、鏡面反射の強度
    half Gloss; // 光沢、スペキュラとの違いは今のところ不明…
    half Alpha; // 不透明度、0で透明、1で不透明
};

今回はo.Albedoに、half3(0.75, 1.0, 0.5)という色を渡しています。


FallBack "Diffuse"

最後は、全てのSubShaderの実行に失敗した時のフォールバック処理の指定です。
固定関数シェーダでDiffuseを指定しています。
省略可能です。


実行結果

上記のシェーダを実行すると下記のようになります。
001.PNG

特にライティング等の指定はしてませんが、いい感じに明るい部分と暗い部分ができています。
サーフェイスシェーダ様々です。


プロパティで色を変えてみる

Unityはシェーダの値を外部から変えることができます。
変更後のシェーダは下記になります。

Shader "Custom/surfaceshader002" {
    Properties {
        _Color("Diffuse Color",Color) = (1.0, 1.0, 1.0)
    }

    SubShader {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Lambert

        struct Input {
            float4 color : COLOR;
        };

        float4 _Color;

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = _Color.rgb;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

変更点は、3つあります。


Properties {
    _Color("Diffuse Color",Color) = (1.0, 1.0, 1.0)
}

頭のほうで、Inspector上に表示するプロパティを指定しています。
プロパティは、
変数名("Inspector上の表示名", 変数の種類) = デフォルト値
のルールで記述します。
変数の種類は、下記のものが使えます。

// 数値系
name ("display name", Range (min, max)) = number // 範囲指定型
name ("display name", Float) = number            // 浮動小数点型
name ("display name", Int) = number              // 整数型

// 色とベクトル
name ("display name", Color) = (number,number,number,number)    // 色
name ("display name", Vector) = (number,number,number,number)   // ベクトル

// テクスチャ系
name ("display name", 2D) = "defaulttexture" {}   // 2Dテクスチャ
name ("display name", Cube) = "defaulttexture" {} // キューブマップ
name ("display name", 3D) = "defaulttexture" {}   // 3Dテクスチャ

float4 _Color;

プロパティで受け取ったデータをシェーダ内で使うための定義です。


o.Albedo = _Color.rgb;

SurfaceOutput oにプロパティで受け取った_Colorのrgb値を代入しています。


実行結果

上記のシェーダを実行すると下記のようになります。

実行直後

実行直後の色は白です。
002.PNG
003.PNG

色を変えてみる

プロパティで色を赤に変えてみました。
004.PNG
005.PNG

球体の色も赤くなっています。

76
75
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
76
75