Edited at
WebGLDay 10

WebGL2.0のためのGLSL ES 3.0

More than 1 year has passed since last update.

正式にWebGL2.0が使えるようになってきましたので、ここでWebGL2.0に対応するGLSL ES 3.0について、まとめていきたいと思います。


自分でも調べましたが、間違った認識や情報が含まれていたり、足りない情報がある可能性が高いです。

ぜひコメントをどんどん投げていただけるとありがたいですm(_ _)m

めちゃくちゃ、読みにくいです。ゴメンなさい。



GLSL ES 1.0 から 3.0 への変更点


Version directive


vert.vs

   #version 300 es

void main(){
...
}


  • 先頭に#version 300 esを記述することによって、このシェーダーがGLSL ES 3.0で書かれていることを示します。この宣言が空白を除いて一番最初に来なかった場合、コンパイルエラーになってしまいます。


例えばよく使われるhtmlのscriptタグの中にシェーダを記述する以下のような場合、<script>タグと#version 300 esの間に改行文字があるので、コンパイルエラーになります。


html

 <script>// (ここに改行文字がある)

#version 300 es
...
</script>
<!-- コンパイルエラー -->

なので、改行せずに<script>タグの真横に直接書く必要があります。


html

 <script>#version 300 es

...
</script>



  • 何も書かれていなかった場合は、これまで通りGLSL ES 1.0で書かれていると認識され、中身がGLSL ES 3.0の書き方で書かれていると、コンパイルエラーになります。

  • 頂点シェーダにもフラングメントシェーダにも書く必要があります

  • 頂点シェーダとフラグメントシェーダでバージョンはそろえないとコンパイルエラーになります

  • フラグメントシェーダーではこの後にprecision mediump float;を持ってきます(ないとコンパイルエラー)


vert.vs

   #version 300 es // ないとコンパイルエラー

void main(){
・・・
}


frag.fs

   #version 300 es // ないとコンパイルエラー

precision highp float;
void main(){
・・・
}


Types


符号なし整数に対応


  • リテラルが uuint test = 10u;のように表します。


  • uintuvec2uvec3uvec4が追加されました。


正方行列以外にも対応


  • 今までは mat2mat3mat4 のみでしたが、mat2x3 などにも対応しました


  • mat2x2mat3x3 などは今までの mat2mat3 などと同じです(正確には、mat2mat3 は正式な型名ではなく、mat2x2mat3x3 が正式な型名です)


texture系


  • texture系には様々な変更があって、それぞれに対応する関数などもあるので、別記します。


Qualifiers


attributevarying が廃止され、inout


  • attribute と varying が廃止され、使うとコンパイルエラーになります。

  • その代わりに、シェーダに入ってくるもの(attribute やフラグメントシェーダの varying 変数)は in で表し、出て行くもの(頂点シェーダの varying 変数や gl_FragColor)は out で表します。


  • gl_Position や gl_PointSize は変更なしなので、頂点シェーダで gl_Position ではなく out vec4 outPosition などにしても、何も映らなくなるだけなのでご注意を。


vert.vs

   #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;
}


frag.fs

   #version 300 es

precision mediump float;
in vec3 vColor;
out vec4 outColor;
void main(){
outColor = vColor;
}


最後の方に書いた、将来実装される機能のための予約語の中に attributevarying が入っていたのですが、これは1.0との誤解を防ぐためなのか、それともこれから実装されるのかどうなんでしょうか?

見た感じGLSL ES 3.1や3.2で追加されている形跡がないので、単純に誤解を防ぐためのように思われますが。



centroid


  • MSAA(アンチエイリアシングの技法の一種)で起きていた問題(テクスチャ座標が1.0を超えたりしてしまう)を解決するやつです。

  • 通常はテクスチャ座標を求める時に、単純にピクセルの中心を補間するが、centroidを使った場合、重心ベースの補間をしてくれます。

  • 頂点シェーダでは centroid out、フラグメントシェーダでは centroid in のみ有効になります。


vert.vs

in vec2 textureCoord;

centroid out vec2 texCoord;

void main(){
texCoord = textureCoord;
}



frag.fs

centroid in vec2 texCoord;



smooth, flatに対応


  • smooth はシェーダ間の受け渡しの時に、データを補間して渡してくれます。(今まで通り)

  • flat はシェーダ間の受け渡しの時に、データの補間をしません。(詳しくはみんな大好きwgld.org)

  • フラットシェーディングなどは flat

  • centroid も smooth も flat もついていない時は、smooth で補間されます。

  • int などの型に対しては補間できないので、コンパイルエラーになります。

  • flat でどこの頂点のデータが次のシェーダに渡されるかは provoking vertex としてシステムで定義されるので変更できません。


frag.fs

smooth in vec2 texCoord; // smooth補間される

in vec2 texCoord; // smooth補間される
flat in vec2 texCoord; // 補間されない = flat


uniform block


  • 使いまわしたりするunform変数とかをJS側でバッファーにして、送ることができるようになりました。

  • その時にシェーダで受け取る役割をします。

  • sampler系は使うことができません

  • 中にネストでuniform blockを使うこともできません

  • ブロックの中で定義したものは、そのままメインスコープとして使うことができます


frag.vs

in vec3 position;

uniform Transform {
mat4 mvpMatrix;
};

void main(){
gl_Position = vec4(position, 1.0) * mvpMatrix;
}



  • 末尾にインスタンス名を指定することもできます


vert.vs

in vec3 position;

uniform Transform {
mat4 mvpMatrix;
} TransformMatrix;

void main(){
gl_Position = vec4(position, 1.0) * TransformMatrix.mvpMatrix;
}



layout


  • 今まで、attribute変数をJS側でバインドする時にglContext.BindAttribLocationglContext.GetAttribLocation使ってattribute変数を使っていましたが、layoutを使うとこの処理GLSL側ですることができるようになります。


vert.vs

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_majorcolumn_majorに帰ることもできます

  • 初期化のように最初に指定しておくこともできます。

名前
説明

shared
デフォルト。複数のプログラムで、同じレイアウトが保障されます

packed
コンパイラによって、中のデータのメモリなどが最適化されるのを許可します。

std140
std140のフォーマットを使います。詳しくは下を参照

row_major
デフォルト。行列を行を優先してコンパイルします

column_major
行列を列を優先してコンパイルします


vert.vs

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が廃止されました。

  • その他にも廃止されたり、追加されたものがあります。



  1. gl_FragColorが廃止
    out vec4 colorのように自分で定義する


  2. マルチレンダーターゲットようの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;
    }




  3. フラグメントシェーダーにgl_FragDepthが追加


    • フラグメントシェーダー内で、この変数に深度値を渡すことができます。
      > gl_FragDepthについて、実際の使い方などがわからなかったので、誰か補足していただけるとありがたいです。




  4. 頂点シェーダにgl_VertexIDgl_InstanceIDが追加



    • gl_VertexIDは現在処理している頂点のIDが格納されています

    • IDは各ドローコールで、1から処理される順に1ずつたされていったIntが帰ってきます


    • gl_VertexIDは必ず存在しますが、その中の値は定義されていない場合があるそうです。(どんな時に定義されないのかはわかりませんでした)

    • パーティクルなどで、頂点ごとに違った動きをさせることができます。


    • gl_InstanceIDインスタンシングで、現在処理しているインスタンスのIDが格納されています。

    • IDはInt型で、インスタンシングを使っていない場合は0が格納されます。

    • インスタンシングでそれぞれのインスタンスの描画結果を変えることができるようになります。



  5. その他、今まであった組み込み定数の上限が強化


定数名
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全てを表します。vec2vec2x4vec4x3のことです。同じようにmatなども行数と列数が2〜4のもの全てを指します。




  • 双曲線関数



    1. sinh(floatなど x)


      • 双曲線正弦を返します

          \frac{e^x - e^{-x} }{2.0}
      


      • 返り値はxと同じ型




    2. cosh(floatなど x)


      • 双曲線正弦を返します

          \frac{e^x + e^{-x} }{2.0}
      


      • 返り値はxと同じ型




    3. tanh(floatなど x)


      • 双曲線正接を返します

          \frac{sinh x}{cosh x}
      


      • 返り値はxと同じ型




    4. asinh(floatなど x)


      • 逆双曲線正弦を返します

          \ln \Bigl(x+\sqrt{x^2+1} \bigr)
      


      • 返り値はxと同じ型




    5. acosh(floatなど x)


      • 逆双曲線正弦を返します

          \ln \Bigl(x + \sqrt{x+1}\sqrt{x-1}\bigr)
      


      • 返り値はxと同じ型




    6. 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);



  • 一般共通関数



    1. trunc(floatなど x)


      • 0に近づくように小数点以下が切り捨てられます。

      • xが正の時は切り捨て、負の時は切り上げになります。

      x - fract(abs(x)) * sign(x)
      


      • 返り値はxと同じ型




    2. round(floatなど x)


      • 四捨五入。

      • ただし、0.5については端末によって、切り上げられるか切り捨てられるかが異なります。

      • 返り値はxと同じ型




    3. roundEven(floatなど x)


      • 四捨五入。

      • ただし、0.5については必ず偶数の側に切り捨て・切り上げられます

      round(1.5) == round(2.5) == 2
      


      • 返り値はxと同じ型




    4. isnan(floatなど x)


      • xが非数であればtrue、それ以外はfalseを返します。

      • 返り値はboolなど




    5. isinf(floatなど x)


      • xが無限大であればtrueを、そうでなければfalseを返します。

      • 返り値はboolなど




    6. floatBitsToInt(floatなど x)floatBitsToUint(floatなど)


      • ビット表現を維持したままfloatなどをintなどやuintなどに変換します。

      • 返り値はintなどuintなどです。




    7. 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関数



    1. packSnorm2x16(vec2)packUnorm2x16(vec2)


      • vec2を16bit固定小数点数に変化後に一つの整数型へパック

      • 引数はvec2であれば何でも大丈夫です。

      • 返り値はuintです。




    2. unpackSnorm2x16(uint)unpackUnorm2x16(uint)


      • 1でパックしたものを復元するためのものです。

      • 返り値はvec2です。




    3. packHalf2x16(vec2)
         - 1の浮動小数点版です。
         - 返り値はuintです。


    4. unpackHalf2x16(uint)
         - 3でパックしたものを復元するためのものです。


    記述例

    uint res1 = packSnorm2x16(vec2 x);
    
    vec2 res2 = unpackSnorm2x16(res1);
    uint res3 = packHalf2x16(vec2 x);
    vec2 res4 = unpackHalf2x16(res3);



  • 行列関数



    1. outerProduct(vecなど c, vecなど r)


      • cの列ベクトル、rの行ベクトルの外積を返します。

      • cの長さ×rの長さの行列が帰ってきます。

      outerProduct(vec2 c, vec3 r)
      


      • 返り値はmatなどです。




    2. 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などです。




    3. determinant(正方matなど)


      • 行列式を返します。

      • 引数は正方行列(mat2mat3mat4)のみです。

      • 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です。




    4. 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}





  • フラグメントシェーダ関数



    1. dFdx(float p)


      • スクリーン空間のx座標についての偏微分

      • 一般的にプロシージャテクスチャのアンチエイリアスのために使われます。

      • 返り値はpと同じfloatなどです。




    2. dFdy(float p)


      • スクリーン空間のy座標についての偏微分

      • 一般的にプロシージャテクスチャのアンチエイリアスのために使われます。

      • 返り値はpと同じfloatなどです。




    3. fwidth(float p)


      • 絶対偏微分の合計を返します。


      • abs(dFdx(p)) + abs(dFdy(p))を返します。






  • その他の既存の関数の変更


    1. min関数・max関数・clamp関数の引数がint系・uint系にも対応


    2. 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


参考

OpenGL ES - Wikipedia


texture

OpenGL でテクスチャ配列を使う

テクスチャ配列の活用について (OpenGL)