自習室

こもります

Unity の Shader (ShaderLab) 知識ざっくりメモ

はじめに

普通の書き方をする上で、よく使うことについてメモします。 随時追記予定

事前知識

ShaderLabの概要

ShaderLab は、Cgを用いたUnity独自のShader文法。マテリアルに .shader ファイルを登録します。

突然自作の前に、まずはビルトインのものから

基本的な構文

まずはここから

Properties{...}

http://docs-jp.unity3d.com/Documentation/Components/SL-Properties.html

Properties{} に入れると、インスペクタから各値を指定できるようになる。

  • Range : スライドバー
  • Color : 色
  • 2D : テクスチャ

等。これらの値は glslの uniform変数的にこのマテリアルが適用されるメッシュの頂点すべてに適用されることになります。

  • テクスチャ座標の取得の仕方
// Unity公式のtextureを用いるsurface shaderのサンプルより
// http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderExamples.html
Shader "Example/Diffuse Texture" {
Properties {
  _MainTex ("Texture", 2D) = "white" {}
}
SubShader {
  // 中略
  struct Input {
      float2 uv_MainTex;
  };
  sampler2D _MainTex;
  void surf (Input IN, inout SurfaceOutput o) {
      o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
  }
  // 後略

という感じで、Propertiesで登録されるテクスチャのテクスチャ座標をシェーダの引数として使いたい場合は、float2 uv_MainTex と名乗れば、自動で代入してくれて、tex2D関数の引数として使えるようになります。

参考:(2) テクスチャを貼る

その3 サーフェイスシェーダ

Tags{...}

http://docs-jp.unity3d.com/Documentation/Components/SL-SubshaderTags.html

  • Queueタグ:
    アルファテストするかとか、透明化とか、オーバーレイ優先かとか、描画の順番に関わる指定

  • RenderTypeタグ:
    とりあえず、"Opaque"(不透明) か"Transparent"(透明)か、を教えてあげるくらいの認識。いくつか試してみたけど、これを指定しなければならないと言うわけではない様子。

Pass{...}

Pass1個で、オブジェクト形状を1回レンダリングする。マルチパスも可能。

メモ:
後述する Surfce Shaderでは、コンパイラがPassを生成するため、Pass{} は存在しない。

ShaderLabのレンダリング設定項目(ステートメント)

http://docs-jp.unity3d.com/Documentation/Components/SL-Pass.html

OpenGLの固定パイプラインで、カリングやります、ブレンドします、アルファテストします、的なglEnable()をやっていきますが、それのイメージ。

  • Material,
  • Lighting on|off,
  • cull Back|Front|off,
  • Blend src dst,

的な感じ。固定機能シェーダで使うのが一般的だけど、

ちなみにPassの外(SubShader直下) に書くことも出来て、その場合SubShader内全パス共通設定になる。 (CommonState) この点については、下のページに説明あり。

http://docs-jp.unity3d.com/Documentation/Components/SL-SubShader.html

シェーダの書き方3種

違いは、このページの最下部に分かりやすくまとめてあります

その1 UnityにおけるShaderとは?

以下、個人的な追記。

固定機能 (fixed function) シェーダ

http://docs-jp.unity3d.com/Documentation/Components/SL-Shader.html

ShaderLab のステートメント「のみ」を用いて記述すると、固定の関数に好みの変数をセットしてシェーダを作り上げることになります。

  • マテリアルのDiffuseはこの色で、
  • マテリアルのShininess はこのくらいの強さで
  • マテリアルのテクスチャはこれを使って
  • Alphaテストはこんな式で
  • Blending はこんなタイプで

とか何とか、設定していきます。

固定パイプラインのイメージはこのページの上図。

ShaderLabの固定パイプラインの設定項目(ステートメント)はこちらが詳しい

その2 ShaderLabでUnityシェーダの下地作り

Surface Shader サーフェスシェーダ

ポリゴンに着色するのに特化したシェーダ。Unityのシーン中のライティングも自動で適用される。それだけがしたいなら簡単に書けるぜ、と言う物。(と思った)

Vertex and Fragment Shader (Programmable Shader)

頂点を変形させたり、色を変化させながら塗ったりしたい場合はこちらを利用。 GLSLに慣れていたら、こっちの方が自然に感じると思われます。1ファイルに全部書いちゃうけど。

公式曰く

Unityのライトで反応しないシェーダについて言及します。(例:スペシャルエフェクト、Image Effects 等)

詳細な部分

Shaderのinput/output構造体のメンバに付けるセマンティクス

「この変数はシェーダ内では位置を意味するって決まってるよ、だからその値下さい」等とグラボ(パイプライン)に伝達する為の、意味(セマンティック)の指定。Vertex and Fragment Shader で、input や output の構造体を定義する際に利用する。

struct vertexInput {
    float4 vertex : POSITION;
    float4 texcoord0 : TEXCOORD0;
};

struct fragmentInput{
    float4 position : SV_POSITION;
    float4 texcoord0 : TEXCOORD0;
};
  • COLOR
  • SV_POSITION(プロジェクション後の座標)
  • POSITION(空間中の座標)
  • TEXCOORD
  • NORMAL(法線)
  • TANGENT(接線)
  • WPOS(Fragmentシェーダで、いま扱っているピクセルの座標)

※ これの正式な一覧が欲しいのだけど見つからない… これで全部ではないかも。

VertexFragmentShader のサンプルをみると、セマンティクスたくさん出てきます。
http://docs-jp.unity3d.com/Documentation/Components/SL-VertexFragmentShaderExamples.html

ShaderLabのビルトイン便利変数・構造体・関数など

のうち、よく使われているとおもう物メモ。

#include UnityCG.cgincして利用する。

公式のリストはこちら
http://docs-jp.unity3d.com/Documentation/Components/SL-BuiltinValues.html

  • float4x4 UNITY_MATRIX_MVP :
    一般的な物体描画の時に利用。Unityのシーンから算出される変換行列は、このほかにもたくさん。

  • _ScreenParams :
    現在描き込もうとしているスクリーンの大きさ

  • float4 _Time, _SinTime, _CosTime, unity_DeltaTime
    便利な時間関係の値が取得できる。

_SinTimeの使い方がおもしろい。 _SinTime.x は sin(t/8) を意味する。 以下、 yの時は t/4, z で t/2 w で t このあたりはこちらで実践的に解説されています
(Cg)シェーダ内で sin の値を使い、時間と共に色を変化させる - 強火で進め

など。UnityCG.cgincを読みましょう、ってことですな。

Cgのよく使う関数群

ShaderLab特有というわけでは無いけど、メモ。abs() とか clamp() とか lerp() とか。便利っす。公式なのはこちらの、Cg Standard Library 参照。

http://developer.download.nvidia.com/cg/Cg_3.1/Cg-3.1_April2012_ReferenceManual.pdf