正式にWebGL2.0が使えるようになってきましたので、ここでWebGL2.0に対応するGLSL ES 3.0について、まとめていきたいと思います。
自分でも調べましたが、間違った認識や情報が含まれていたり、足りない情報がある可能性が高いです。
ぜひコメントをどんどん投げていただけるとありがたいですm(_ _)m
めちゃくちゃ、読みにくいです。ゴメンなさい。
GLSL ES 1.0 から 3.0 への変更点
Version directive
#version 300 es
void main(){
...
}
- 先頭に
#version 300 es
を記述することによって、このシェーダーがGLSL ES 3.0で書かれていることを示します。この宣言が空白を除いて一番最初に来なかった場合、コンパイルエラーになってしまいます。
例えばよく使われるhtmlのscriptタグの中にシェーダを記述する以下のような場合、
<script>
タグと#version 300 es
の間に改行文字があるので、コンパイルエラーになります。
html
> なので、改行せずに`<script>`タグの真横に直接書く必要があります。
> ```html:html
<script>#version 300 es
...
</script>
- 何も書かれていなかった場合は、これまで通りGLSL ES 1.0で書かれていると認識され、中身がGLSL ES 3.0の書き方で書かれていると、コンパイルエラーになります。
- 頂点シェーダにもフラングメントシェーダにも書く必要があります
- 頂点シェーダとフラグメントシェーダでバージョンはそろえないとコンパイルエラーになります
- フラグメントシェーダーではこの後に
precision mediump float;
を持ってきます(ないとコンパイルエラー)
#version 300 es // ないとコンパイルエラー
void main(){
・・・
}
#version 300 es // ないとコンパイルエラー
precision highp float;
void main(){
・・・
}
Types
符号なし整数に対応
- リテラルが u で
uint test = 10u;
のように表します。 -
uint
・uvec2
・uvec3
・uvec4
が追加されました。
正方行列以外にも対応
- 今までは
mat2
・mat3
・mat4
のみでしたが、mat2x3
などにも対応しました -
mat2x2
やmat3x3
などは今までのmat2
やmat3
などと同じです(正確には、mat2
やmat3
は正式な型名ではなく、mat2x2
やmat3x3
が正式な型名です)
texture系
- texture系には様々な変更があって、それぞれに対応する関数などもあるので、別記します。
Qualifiers
attribute
・varying
が廃止され、in
・out
に
- attribute と varying が廃止され、使うとコンパイルエラーになります。
- その代わりに、シェーダに入ってくるもの(attribute やフラグメントシェーダの varying 変数)は
in
で表し、出て行くもの(頂点シェーダの varying 変数やgl_FragColor
)はout
で表します。 -
gl_Position
やgl_PointSize
は変更なしなので、頂点シェーダでgl_Position
ではなくout vec4 outPosition
などにしても、何も映らなくなるだけなのでご注意を。
#version 300 es
in vec3 position;
in vec4 color;
out vec4 vColor;
uniform mat4 mvpMatrix;
void main(){
gl_Position = position * mvpMatrix;
gl_PointSize = 0.2;
}
#version 300 es
precision mediump float;
in vec3 vColor;
out vec4 outColor;
void main(){
outColor = vColor;
}
最後の方に書いた、将来実装される機能のための予約語の中に
attribute
やvarying
が入っていたのですが、これは1.0との誤解を防ぐためなのか、それともこれから実装されるのかどうなんでしょうか?
見た感じGLSL ES 3.1や3.2で追加されている形跡がないので、単純に誤解を防ぐためのように思われますが。
centroid
- MSAA(アンチエイリアシングの技法の一種)で起きていた問題(テクスチャ座標が1.0を超えたりしてしまう)を解決するやつです。
- 通常はテクスチャ座標を求める時に、単純にピクセルの中心を補間するが、centroidを使った場合、重心ベースの補間をしてくれます。
- 頂点シェーダでは
centroid out
、フラグメントシェーダではcentroid in
のみ有効になります。
in vec2 textureCoord;
centroid out vec2 texCoord;
void main(){
texCoord = textureCoord;
}
centroid in vec2 texCoord;
smooth, flatに対応
- smooth はシェーダ間の受け渡しの時に、データを補間して渡してくれます。(今まで通り)
- flat はシェーダ間の受け渡しの時に、データの補間をしません。(詳しくはみんな大好きwgld.org)
- フラットシェーディングなどは flat
- centroid も smooth も flat もついていない時は、smooth で補間されます。
- int などの型に対しては補間できないので、コンパイルエラーになります。
- flat でどこの頂点のデータが次のシェーダに渡されるかは
provoking vertex
としてシステムで定義されるので変更できません。
smooth in vec2 texCoord; // smooth補間される
in vec2 texCoord; // smooth補間される
flat in vec2 texCoord; // 補間されない = flat
uniform block
- 使いまわしたりするunform変数とかをJS側でバッファーにして、送ることができるようになりました。
- その時にシェーダで受け取る役割をします。
- sampler系は使うことができません
- 中にネストでuniform blockを使うこともできません
- ブロックの中で定義したものは、そのままメインスコープとして使うことができます
in vec3 position;
uniform Transform {
mat4 mvpMatrix;
};
void main(){
gl_Position = vec4(position, 1.0) * mvpMatrix;
}
- 末尾にインスタンス名を指定することもできます
in vec3 position;
uniform Transform {
mat4 mvpMatrix;
} TransformMatrix;
void main(){
gl_Position = vec4(position, 1.0) * TransformMatrix.mvpMatrix;
}
layout
- 今まで、attribute変数をJS側でバインドする時に
glContext.BindAttribLocation
やglContext.GetAttribLocation
使ってattribute変数を使っていましたが、layout
を使うとこの処理GLSL側ですることができるようになります。
layout(location = 0) in vec3 position;
void main(){
gl_Position = vec4(position, 1.0) * TransformMatrix.mvpMatrix;
}
- UniformBlockの場合のlayoutもあり、ちょっと特殊です
- UniformBlockは普通に使おうとすると、JS側でのバインドなどの処理が多いので、ある程度GLSL側でlayoutを使うことによってそれが軽減できます。
- UniformBlockの場合特にlocationはないので、中のデータのフォーマットなどを指定します
- 何個でも同時に指定できますが、上の三つ(フォーマット系)と下の2つ(行列系)で、同じ系統のものを指定した場合、他のフォーマットはそのままで置き換えられます。
- 内部で、一つだけ
row_major
やcolumn_major
に帰ることもできます - 初期化のように最初に指定しておくこともできます。
名前 | 説明 |
---|---|
shared | デフォルト。複数のプログラムで、同じレイアウトが保障されます |
packed | コンパイラによって、中のデータのメモリなどが最適化されるのを許可します。 |
std140 | std140のフォーマットを使います。詳しくは下を参照 |
row_major | デフォルト。行列を行を優先してコンパイルします |
column_major | 行列を列を優先してコンパイルします |
layout(shared, row_major) uniform;
layout (std140) uniform Transform {
mat4 mvpMatrix;
} TransformMatrix;
layout (packed, row_major) uniform Transform2 {
mat4 mvpMatrix2;
layout(column_major) mat2 testMatrix;
} TransformMatrix2;
(できたら、UniformBufferObjectについても解説したいですが、doxasさんあたりがわかりやすい解説をしていただけると思うので僕からは省きます)
std140
とは(割とちゃんと理解できているか怪しいところなので、詳しい方教えていただけるとありがたいです)簡単に言うと、今までのAttribute変数の
getAttribLocation
などJS側でインデックスをとってきてバインドするように、UniformBufferObjectの場合も同じような処理が必要です。
しかし、GLSL3.0になって、attribute変数(今はattributeではないですが)にlayoutでインデックスをGLSL側から登録できるようになりました。同じようにUniformBlockの場合も、わざわざJS側でインデックスを調べなくてもいいように作られたのがstd140
です。
実際の所どんなものかというと、インデックスを登録しないので、GLSL側とJS側でデータのとり違いがないように、細かくフォーマットを指定しています。
細かいフォーマットについてはこちらの記事を読んでください
組み込み変数など
- 前述しましたが、gl_FragColorが廃止されました。
- その他にも廃止されたり、追加されたものがあります。
-
gl_FragColor
が廃止
→out vec4 color
のように自分で定義する -
マルチレンダーターゲットようの
gl_FragData[n]
が廃止
→layout(location = n) out vec4 color
のようにlayoutを用いて、自分で定義する今までの書き方・フラグメントシェーダprecision mediump float; varying vec4 vColor; void main(){ gl_FragColor = vColor; }
GLSLES3.0での書き方・フラグメントシェーダ#version 300 es precision mediump float; in vec4 vColor; out vec4 outColor; void main(){ outColor = vColor; }
-
フラグメントシェーダーに
gl_FragDepth
が追加- フラグメントシェーダー内で、この変数に深度値を渡すことができます。
gl_FragDepthについて、実際の使い方などがわからなかったので、誰か補足していただけるとありがたいです。
-
頂点シェーダに
gl_VertexID
やgl_InstanceID
が追加-
gl_VertexID
は現在処理している頂点のIDが格納されています - IDは各ドローコールで、1から処理される順に1ずつたされていったIntが帰ってきます
-
gl_VertexID
は必ず存在しますが、その中の値は定義されていない場合があるそうです。(どんな時に定義されないのかはわかりませんでした) - パーティクルなどで、頂点ごとに違った動きをさせることができます。
-
gl_InstanceID
はインスタンシングで、現在処理しているインスタンスのIDが格納されています。 - IDはInt型で、インスタンシングを使っていない場合は0が格納されます。
- インスタンシングでそれぞれのインスタンスの描画結果を変えることができるようになります。
-
-
その他、今まであった組み込み定数の上限が強化
| 定数名 | 2.0 | 3.0 |
|:--|:--|:--|:--|
| gl_MaxVertexAttribs | 8 | 16 |
| gl_MaxVertexUniformVectors | 128 | 256 |
| gl_MaxVertexOutputVectors | none | 16 |
| gl_MaxFragmentInputVectors | none | 15 |
| gl_MaxVertexTextureImageUnits | 0 | 16 |
| gl_MaxCombinedTextureImageUnits | 8 | 32 |
| gl_MaxTextureImageUnits | 8 | 16 |
| gl_MaxFragmentUniformVectors | 16 | 224 |
| gl_MaxDrawBuffers | 1 | 4 |
| gl_MinProgramTexelOffset | none | -8 |
| gl_MaxProgramTexelOffset | none | 7 |
| gl_MaxVaryingVectors | 8 | none |
組み込み関数
floatなど
とはfloatで構成されるvec2なども含まれます。同様にboolやint、uintも同じです。
vecなど
とはいろんな長さのvec全てを表します。vec2
・vec2x4
・vec4x3
のことです。同じようにmatなど
も行数と列数が2〜4のもの全てを指します。
-
双曲線関数
-
sinh(floatなど x)
- 双曲線正弦を返します
\frac{e^x - e^{-x} }{2.0}
- 返り値はxと同じ型
-
cosh(floatなど x)
- 双曲線正弦を返します
\frac{e^x + e^{-x} }{2.0}
- 返り値はxと同じ型
-
tanh(floatなど x)
- 双曲線正接を返します
\frac{sinh x}{cosh x}
- 返り値はxと同じ型
-
asinh(floatなど x)
- 逆双曲線正弦を返します
\ln \Bigl(x+\sqrt{x^2+1} \bigr)
- 返り値はxと同じ型
-
acosh(floatなど x)
- 逆双曲線正弦を返します
\ln \Bigl(x + \sqrt{x+1}\sqrt{x-1}\bigr)
- 返り値はxと同じ型
-
tanh(floatなど x)
- 逆双曲線正接を返します
\frac{1}{2}\ln\Bigl(\frac{z+1}{z-1})
- 返り値はxと同じ型
記述例
float res1 = sinh(float x); float res2 = cosh(float x); float res3 = tanh(float x); float res4 = asinh(float x); float res5 = acosh(float x); float res6 = atanh(float x);
-
-
一般共通関数
-
trunc(floatなど x)
- 0に近づくように小数点以下が切り捨てられます。
- xが正の時は切り捨て、負の時は切り上げになります。
x - fract(abs(x)) * sign(x)
- 返り値はxと同じ型
-
round(floatなど x)
- 四捨五入。
- ただし、0.5については端末によって、切り上げられるか切り捨てられるかが異なります。
- 返り値はxと同じ型
-
roundEven(floatなど x)
- 四捨五入。
- ただし、0.5については必ず偶数の側に切り捨て・切り上げられます
round(1.5) == round(2.5) == 2
- 返り値はxと同じ型
-
isnan(floatなど x)
- xが非数であればtrue、それ以外はfalseを返します。
- 返り値は
bool
など
-
isinf(floatなど x)
- xが無限大であればtrueを、そうでなければfalseを返します。
- 返り値は
boolなど
-
floatBitsToInt(floatなど x)
・floatBitsToUint(floatなど)
- ビット表現を維持したまま
float
などをint
などやuint
などに変換します。 - 返り値は
intなど
やuintなど
です。
- ビット表現を維持したまま
-
intBitsToFloat(intなど x)
・uintBitsToFloat(uintなど x)
- ビット表現を維持したまま
int
などやuint
などをfloat
などに変換します。 - 返り値は
float
です。
- ビット表現を維持したまま
記述例
float res1 = trunc(float x); float res2 = round(1.4); //= 1.0 float res3 = roundEven(2.5); //= 2.0 bool res4 = isnan(float x); bool res5 = ininf(float x); int res6 = floatBitsToInt(float x); float res7 = intBitsToFloat(int x);
-
-
pack・unpack関数
-
packSnorm2x16(vec2)
・packUnorm2x16(vec2)
- vec2を16bit固定小数点数に変化後に一つの整数型へパック
- 引数は
vec2
であれば何でも大丈夫です。 - 返り値は
uint
です。
-
unpackSnorm2x16(uint)
・unpackUnorm2x16(uint)
- 1でパックしたものを復元するためのものです。
- 返り値は
vec2
です。
-
packHalf2x16(vec2)
- 1の浮動小数点版です。
- 返り値はuint
です。 -
unpackHalf2x16(uint)
- 3でパックしたものを復元するためのものです。
記述例
uint res1 = packSnorm2x16(vec2 x); vec2 res2 = unpackSnorm2x16(res1); uint res3 = packHalf2x16(vec2 x); vec2 res4 = unpackHalf2x16(res3);
-
-
行列関数
-
outerProduct(vecなど c, vecなど r)
- cの列ベクトル、rの行ベクトルの外積を返します。
- cの長さ×rの長さの行列が帰ってきます。
outerProduct(vec2 c, vec3 r)
- 返り値は
matなど
です。
-
transpose(matなど m)
- 行列mの転置行列を返します。
- mat3の場合
m = \begin{pmatrix} a_1 & a_2 & a_3 \\ a_4 & a_5 & a_6 \\ a_7 & a_8 & a_9 \end{pmatrix}\qquad transpose\left(m\right) = \begin{pmatrix} a_1 & a_4 & a_7 \\ a_2 & a_5 & a_8 \\ a_3 & a_6 & a_9 \end{pmatrix}
- mは上書きされません
- 返り値はmと同じ
matなど
です。
-
determinant(正方matなど)
- 行列式を返します。
- 引数は正方行列(
mat2
・mat3
・mat4
)のみです。 - mat2・mat3の場合
\begin{align} & m2 = \begin{pmatrix} a_1 & a_2 \\ a_3 & a_4 \end{pmatrix}\qquad determinant\left(m2\right) = \begin{vmatrix} a_1 & a_2\\ a_3 & a_4 \end{vmatrix} = a_1a_4 - a_2a_3 \\ & m3 = \begin{pmatrix} a_1 & a_2 & a_3 \\ a_4 & a_5 & a_6 \\ a_7 & a_8 & a_9 \end{pmatrix}\quad determinant\left(m3\right) = \begin{vmatrix} a_1 & a_2 & a_3 \\ a_4 & a_5 & a_6 \\ a_7 & a_8 & a_9 \end{vmatrix} = a_1a_5a_9 + a_2a_6a_7 + a_3a_4a_8 - a_1a_6a_8 - a_2a_4a_9 - a_3a_5a_7 \\ \end{align}
- 返り値は
float
です。
-
inverse(matなど m)
- 行列mの逆行列を返します。
- mat2の場合
m = \begin{pmatrix} a_1 & a_2 \\ a_3 & a_4 \end{pmatrix}\qquad inverse\left(m\right) = \frac{1}{a_1a_4-a_2a_3}\begin{pmatrix} a_4 & -a_3 \\ -a_2 & a_1 \end{pmatrix}
-
-
フラグメントシェーダ関数
-
dFdx(float p)
- スクリーン空間のx座標についての偏微分
- 一般的にプロシージャテクスチャのアンチエイリアスのために使われます。
- 返り値はpと同じ
floatなど
です。
-
dFdy(float p)
- スクリーン空間のy座標についての偏微分
- 一般的にプロシージャテクスチャのアンチエイリアスのために使われます。
- 返り値はpと同じ
floatなど
です。
-
fwidth(float p)
- 絶対偏微分の合計を返します。
-
abs(dFdx(p)) + abs(dFdy(p))
を返します。
-
-
その他の既存の関数の変更
-
min関数・max関数・clamp関数の引数がint系・uint系にも対応
-
mix(floatなど x, floatなど y, boolなど a)
が追加?今までのものと何が違うのかがわかりません
わかる方教えていただけるとありがたいです。
-
Texture
後で追記します
予約語一覧
予約語 | (現在使われている変数名など) | ||
---|---|---|---|
const | uniform | ||
layout | |||
centroid | flat | smooth | |
break | continue | do | for |
while | switch | case | default |
if | else | ||
in | out | inout | |
float | int | void | bool |
true | false | ||
invariant | |||
discard | return | ||
mat2 | mat3 | mat4 | |
mat2x2 | mat2x3 | mat2x4 | |
mat3x2 | mat3x3 | mat3x4 | |
mat4x2 | mat4x3 | mat4x4 | |
vec2 | vec3 | vec4 | |
ivec2 | ivec3 | ivec4 | |
bvec2 | bvec3 | bvec4 | |
uint | uvec2 | uvec3 | uvec4 |
lowp | mediump | highp | precision |
sampler2D | sampler3D | samplerCube | |
sampler2DShadow | samplerCubeShadow | ||
sampler2DArray | |||
sampler2DArrayShadow | |||
isampler2D | isampler3D | isamplerCube | |
isampler2DArray | |||
usampler2D | usampler3D | usamplerCube | |
usampler2DArray | |||
struct |
予約語 | (将来使われる可能性がある語) | ||
---|---|---|---|
attribute | varying | ||
coherent | volatile | restrict | readonly |
writeonly | |||
resource | atomic_uint | ||
noperspective | |||
patch sample | |||
subroutine | |||
common | partition | active | |
asm | |||
class | union | enum | typedef |
template | this | packed | |
goto | |||
inline | noinline | volatile | public |
static | extern | external | interface |
long | short | double | half |
fixed | unsigned | superp | |
input | output | ||
hvec2 | hvec3 | hvec4 | |
dvec2 | dvec3 | dvec4 | |
fvec2 | fvec3 | fvec4 | |
sampler3DRect | |||
filter | |||
image1D | image2D | image3D | imageCube |
iimage1D | iimage2D | iimage3D | iimageCube |
uimage1D | uimage2D | uimage3D | uimageCube |
image1DArray | image2DArray | ||
iimage1DArray | iimage2DArray | uimage1DArray | uimage2DArray |
image1DShadow | image2DShadow | ||
image1DArrayShadow | image2DArrayShadow | ||
imageBuffer | iimageBuffer | uimageBuffer | |
sampler1D | sampler1DShadow | sampler1DArray | sampler1DArrayShadow |
isampler1D | isampler1DArray | usampler1D | usampler1DArray |
sampler2DRect | sampler2DRectShadow | isampler2DRect | usampler2DRect |
samplerBuffer | isamplerBuffer | usamplerBuffer | |
sampler2DMS | isampler2DMS | usampler2DMS | |
sampler2DMSArray | isampler2DMSArray | usampler2DMSArray | |
sizeof | cast | ||
namespace | using |