主に凹み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はピクセル幅、高さ
など便利。
サーフェイスシェーダーとは。
頂点・フラグメント(ピクセル)シェーダーは、なんとなくわかった。で、サーフェイスシェーダーとは何なのか。
シェーダーをお手軽に書くもので、細かいことはできないけど、面倒なことは自分で書かなくてすんだりもする。結局最終的にコンパイルされて頂点・フラグメントシェーダーになるようだ。だいたいのブログの情報は先にサーフェイスシェーダーが書いてあって謎で混乱してしまった。