LoginSignup
54
48

More than 3 years have passed since last update.

Unityの超基礎的なShader

Last updated at Posted at 2017-03-17

主に凹みtips からのコピペですが、自分用にまとめます。

先の記事は情報が多くて理解するのが難しいので、ここでは頂点シェーダー・フラグメントシェーダーの基礎的なコードを書いておきます。

単色シェーダー

Shader "Custom/SolidColor" {
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            float4 vert(float4 v:POSITION) : POSITION {
                return mul (UNITY_MATRIX_MVP, v);
            }
            fixed4 frag() : COLOR {
                return fixed4(1.0,0.0,0.0,1.0);
            }
            ENDCG
        }
    }
}
  • #pragmaはよくわからないんですが、ここではvertex,fragmentの関数を指定するものらしい。
  • UNITY_MATRIX_MVP というのはあらかじめ定義されている値であり、MVP行列(モデル・ビュー・プロジェクション行列)のこと。そのほかの組み込み変数はここに書いてある。
  • 「:POSITION」 とはセマンティクスと呼ばれ、その変数が何に使われるかを示す。

セマンティックの種類は、こんなものがある

  • float4 vertex : POSITION
  • float3 normal : NORMAL
  • float4 texcoord : TEXCOORD0
  • float4 texcoord1 : TEXCOORD1
  • float4 tangent : TANGENT
  • float4 color : COLOR

セマンティック参考

単色シェーダー + 構造体を自分で定義

頂点シェーダー,フラグメントシェーダーの引数には構造体が使える。自分で定義したり、すでにあるものを使ったりできるようだ。#include "UnityCG.cginc"と書くと、あらかじめ用意されてるものが使える。ちなみにUnityCg.incの中身はこんな感じらしい

以下では、単に頂点シェーダーの入力に自分で定義した構造体を指定している。

Shader "Custom/SolidColor2" {
    SubShader {
        Pass {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            struct appdata_base {
                float4 vertex   : POSITION;
                float3 normal   : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            float4 vert(appdata_base v) : SV_POSITION {

                float4 p = v.vertex;
                return mul (UNITY_MATRIX_MVP, p);

            }

            fixed4 frag() : COLOR {
                return fixed4(1.0,0.0,0.0,1.0);
            }

            ENDCG
        }
    }
}

UnityCG.cgincで定義されてる構造体appdataは以下

struct appdata_base {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct appdata_tan {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct appdata_full {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    float4 texcoord1 : TEXCOORD1;
    fixed4 color : COLOR;
};

テクスチャをつけてみる

Propetiesという所に変数を宣言するとインスペクタより選択できるようになる。以下ではテクスチャを設定できるようにしている。
インスペクタからテクスチャを設定したら、フラグメントシェーダーの中でtex2D関数とuvから色を取得している。

あと頂点シェーダーでreturn(出力)した変数はfragmentへ送られるようだ。以下ではfragmentInputという構造体。glslのvarying変数のように頂点シェーダーからフラグメントシェーダーに値を渡せる。

Shader "Custom/TexColor" {
    Properties {
        //インスペクタに表示する,uniform
        _MainTex("Base (RGB)", 2D) = "white" {}
    }
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct vertexInput {
                float4 vertex : POSITION;
                float2 uv     : TEXCOORD0;
            };

            struct fragmentInput {
                float4 position : SV_POSITION;
                float2 uv       : TEXCOORD0;
            };

            //uniform として宣言
            uniform sampler2D _MainTex;

            fragmentInput vert(vertexInput v) {
                fragmentInput o;
                o.position = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                return o;
            }

            float4 frag(fragmentInput i) : COLOR {
                //インスペクタから入力された _MainTex を使ってる
                return tex2D(_MainTex, i.uv);
            }

            ENDCG
        }
    }
}

外部からuniform変数をいじる(インスペクタから)

上記サンプルで書いたように、インスペクタからいじりたい場合、Properties というところに定義する。使える種類は以下。

  • 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" {}
  • name ("display name", Cube) = "defaulttexture" {}
  • name ("display name", 3D) = "defaulttexture" {}

外部からuniform変数をいじる(Scriptから)

「material.Setなんとか」でuniformを設定できる。

たとえば、こんなふうに

uniform float _Rad;

が、定義されてたら、

var mat = GetComponent<Renderer>().material;
mat.SetFloat("_Rad", 3.14);

あるいは配列もいける。(情報があまりなくてちょっと迷った)

uniform float _Hoge[32];
var hoge = new float[32];
_mat.SetFloatArray("_Hoge",f);

HLSLの組み込み関数

ここを見る。
https://msdn.microsoft.com/ja-jp/library/bb509611(v=vs.85).aspx

glslとの対応表
https://qiita.com/kitasenjudesign/items/89297f239059662cd38e

Unityですでに定義されている変数

  • _Time = 時間
  • _ScreenParams = xyはピクセル幅、高さ

など便利。

サーフェイスシェーダーとは。

頂点・フラグメント(ピクセル)シェーダーは、なんとなくわかった。で、サーフェイスシェーダーとは何なのか。

シェーダーをお手軽に書くもので、細かいことはできないけど、面倒なことは自分で書かなくてすんだりもする。結局最終的にコンパイルされて頂点・フラグメントシェーダーになるようだ。だいたいのブログの情報は先にサーフェイスシェーダーが書いてあって謎で混乱してしまった。

54
48
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
54
48