UnityでGLSLを使う

  • 38
    Like
  • 0
    Comment
More than 1 year has passed since last update.

やはりいずれはWebGLなどでも活用できるよう、基本的にUnityではGLSLを使ってシェーダを書いていこうと思います。

まずは色々と下準備をしなければならないのでその備忘録を取っていきます。
ちなみにUnityでシェーダを書くにあたってはこちらの記事がだいぶいい感じで参考になりそう。

なにはともあれGLSLを書く準備

まず、ProjectビューのCreateボタンから「Shader」を選んで新規作成します。
(あるいはメニューの「Asset」>「Shader」でも行けます)
作成したら編集します。

settings-unity-shader.png

GLSL向けに書き直す

最初はCg/HLSLのテンプレートが記述されているのでまるっと消して以下のように書き直します。(いくつかサンプル用の記述も入っています)

Shader "Custom/PointSprite" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Size ("Point sprite size", Float) = 64
    }
    SubShader {
        Pass {
            GLSLPROGRAM

uniform sampler2D _MainTex;
uniform float _Size;

#ifdef VERTEX
void main() {
    //ftransform()は固定機能パイプラインと同等の変換を行う
    gl_Position = ftransform();
}
#endif


#ifdef FRAGMENT
void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
#endif

            ENDGLSL
        }
    } 
}

さていきなりわけが分かりませんw
これはUnityが用意しているShaderの書式です。
このへんに書式の意味が載っています。

順を追って見て行きましょう。

名前を付ける

最初の行にあるのはShaderを宣言する部分です。ダブルクォーテーションで囲まれているのはシェーダの名前です。
ここに指定した文字列がMaterialに設定できるシェーダの名前一覧に登場します。

ちなみに、/を使うことで階層構造を作れるようです。

シェーダ内で使いたい要素をUnityのGUIで設定する

続いて目に入るのがPropertiesです。
これはシェーダのプロパティで、ここに色々設定しておくとUnity側のGUIで項目が設定できるようになります。

今回のサンプルではテクスチャとサイズ指定ができるようにしてみました。(特に意味はありません)
サンプルではふたつのプロパティが定義されているわけですね。
実際にUnityのInspector側では以下のように表示されます。

シェーダのプロパティ

Base (RGB)など、プロパティのところに記載されている内容がInspectorに表示されているのが分かります。

シェーダで使う

さて、GUI側で設定することができました。
これをシェーダで使用するにはuniform変数として宣言してやることで使うことができるようになります。
具体的には以下です。

uniform sampler2D _MainTex;
uniform float _Size;

変数名はプロパティで指定したものそのままで宣言します。
これでシェーダ内でGUIから設定された値などを参照することができるようになります。

Propeticesの書式

さて、いくつかのPropetyがありますがこれらの書式は以下の意味を持ちます。

Properties { Property [Property …] }

文法は以下。(多分、宣言できるのはこれだけ?)

name("display name"), Range(min, max)) = number
name("display nmae"), Color) = (number, number, number, number)
name("display nmae"), 2D) = "name" { options }
name("display nmae"), Rect) = "name" { options }
name("display nmae"), Cube) = "name" { options }
name("display nmae"), Float) = number
name("display nmae"), Vector) = (number, number, number, number)

冒頭のnameはプロパティ名です。Unityではこのプロパティ名をアンダースコアから始めるのが一般的なようです。

2D textureの"name"はデフォルトテクスチャを名前で指定します。

実際の例は以下です。

_MainTex ("Base (RGB)", 2D) = "white" {}

nameが _MainTex で、Inspectorに表示される説明が Base (RGB) ですね。
テクスチャなのでタイプが 2D になっています。
そしてデフォルトテクスチャを white にし、ここではoptionは設定していません。
分かってしまえばむずかしくないですね。

SubShaderを指定する

SubShaderは複数定義することができます。
理由としてはUnityはたくさんのプラットフォームに対応しているため、いくつかのシェーダを事前に用意しておいて、使えるシェーダを自動判別して利用するようです。

書式はSubShader { Pass { } }となります。Passの部分に実際のシェーダを記述していきます。

書き始める

書き始めるにあたって、GLSLシェーダ自体のコードの前後にGLSLPROGRAM 〜 ENDGLSLと書きます。

頂点シェーダとフラグメントシェーダは同じ場所に書く

普通はそれぞれのシェーダのファイルは個別に用意し、それをリンクして使いますが、Unityでは#ifdef VERTEX#ifdef FRAGMENTを使ってひとつの場所にふたつのシェーダを書きます。
あとは通常のGLSLと同様に記述していきます。

実際にコンパイルが通る構成は以下です。

GLSLPROGRAM

#ifdef VERTEX
void main() {
}
#endif


#ifdef FRAGMENT
void main() {
}
#endif

ENDGLSL

上記を、SubShader { Pass { 【ここ】 } }に書いていきます。

Unityが準備してくれる変数

行列などUnity側で変数に渡してくるものには以下のものがあるようです。詳細については下のリンク先にあるので、そちらを参考にしてください。

attribute変数

// position (in object coordinates, i.e. local or model coordinates)
attribute vec4 gl_Vertex;

// color (usually constant)
attribute vec4 gl_Color;

// surface normal vector (in object coordinates; usually normalized to unit length)
attribute vec3 gl_Normal;

//0th set of texture coordinates (a.k.a. “UV”; between 0 and 1) 
attribute vec4 gl_MultiTexCoord0;

//1st set of texture coordinates (a.k.a. “UV”; between 0 and 1)
attribute vec4 gl_MultiTexCoord1;

uniform変数

// The following built-in uniforms (except _LightColor0 and 
// _LightMatrix0) are also defined in "UnityCG.glslinc", 
// i.e. one could #include "UnityCG.glslinc" 
uniform vec4 _Time, _SinTime, _CosTime; // time values from Unity

uniform vec4 _ProjectionParams;
// x = 1 or -1 (-1 if projection is flipped)
// y = near plane; z = far plane; w = 1/far plane

uniform vec4 _ScreenParams; 
// x = width; y = height; z = 1 + 1/width; w = 1 + 1/height

uniform vec4 unity_Scale; // w = 1/scale; see _World2Object
uniform vec3 _WorldSpaceCameraPos;
uniform mat4 _Object2World; // model matrix
uniform mat4 _World2Object; // inverse model matrix 
// (all but the bottom-right element have to be scaled 
// with unity_Scale.w if scaling is important) 

uniform vec4 _LightPositionRange; // xyz = pos, w = 1/range
uniform vec4 _WorldSpaceLightPos0; 

// position or direction of light source
uniform vec4 _LightColor0; // color of light source 
uniform mat4 _LightMatrix0; // matrix to light space
uniform mat4 gl_ModelViewMatrix;
uniform mat4 gl_ProjectionMatrix;
uniform mat4 gl_ModelViewProjectionMatrix;
uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];
uniform mat3 gl_NormalMatrix; 
 // transpose of the inverse of gl_ModelViewMatrix
uniform mat4 gl_ModelViewMatrixInverse;
uniform mat4 gl_ProjectionMatrixInverse;
uniform mat4 gl_ModelViewProjectionMatrixInverse;
uniform mat4 gl_TextureMatrixInverse[gl_MaxTextureCoords];
uniform mat4 gl_ModelViewMatrixTranspose;
uniform mat4 gl_ProjectionMatrixTranspose;
uniform mat4 gl_ModelViewProjectionMatrixTranspose;
uniform mat4 gl_TextureMatrixTranspose[gl_MaxTextureCoords];
uniform mat4 gl_ModelViewMatrixInverseTranspose;
uniform mat4 gl_ProjectionMatrixInverseTranspose;
uniform mat4 gl_ModelViewProjectionMatrixInverseTranspose;
uniform mat4 gl_TextureMatrixInverseTranspose[gl_MaxTextureCoords];

struct gl_LightModelParameters { vec4 ambient; };
uniform gl_LightModelParameters gl_LightModel;
...

参考リンク