layout 修飾子によるロケーション指定

実行結果

今回のサンプルの実行結果

自動的な割当てと任意割当て

前回は WebGL 2.0 で利用することが可能になった GLSL ES 3.0 について解説しました。

従来の GLSL ES 1.0 と比較すると、かなり基本的な部分からルールが変わっているところが多いので、ちょっと戸惑ってしまったという人もいたかもしれません。ただ、前回の最後のまとめにも書いたように、WebGL 2.0 の機能をしっかりと引き出していくためには、GLSL についても新しいバージョンを使わなくてはならなくなります。最初は難しく感じる部分もあるかと思いますが、少しずつ慣れていきましょう。

さて今回ですが、前回同様に GLSL ES 3.0 で使えるようになった機能のひとつである layout 修飾子 について見ていきましょう。

これを利用することによって、大幅に記述するコードの量が減るとか、極端に実行が最適化されて速くなるといったことはないのですが、せっかくの新しい機能ですので簡単に概要だけでも理解しておきましょう。

個人的には、これを利用することのメリットはあまり思い浮かばない部分もあるのですが、他人のコードを読む際などに突然出てくるとびっくりすると思いますし、使い方だけでも知っておいて損はないでしょう。

WebGL とロケーション

WebGL には、ロケーションと呼ばれるものがいくつかあります。既に WebGL 1.0 をスクラッチで実装したことがある方であれば、耳にしたことがあると思います。

GLSL は GPU 側で動作するプログラムなので、これらと CPU 側で動作する JavaScript がやりとりするためには、一種のポインタのようなアドレスに関する情報が必要になります。これがいわゆる ロケーション と呼ばれているやつですね。従来の WebGL 1.0 の場合は、こういったロケーションの類に関しては GPU 側での割当て状態を、JavaScript 側からメソッドをコールして取得する方法が使われていました。

たとえば、以下のようにします。

attribute のロケーションを取得する例

// attribute 変数のロケーションを取得する
var attLocation = gl.getAttribLocation(program, 'position');

attribute 変数は頂点属性を定義する場合に必要となるものでしたね。GLSL 側には attribute 変数であることを示す attribute 修飾子を用いた変数宣言を行っておき、JavaScript 側からプログラムオブジェクト経由でロケーション情報を取得します。

この attribute 変数のロケーション情報は、GPU 側で自動的に割当てが行われ、整数値としてインデックス情報が返却されてくる仕組みになっています。通常は、0 や 1 などといったような、本当に普通の整数が取得できます。万が一 gl.getAttribLocation に指定した名前の attribute 変数がシェーダのコード側で定義されていない場合は、−1 が返却されてくるようになっていました。

このインデックス値こそがまさにロケーション情報に相当するのですが、今回のテーマである layout 修飾子を使うと、このロケーションのインデックス値をシェーダ側から固定することができるようになります。

ロケーションを任意固定する

ここで一応確認ですが layout 修飾子は GLSL ES 3.0 で新しく追加された概念なので、当然のことながら GLSL ES 3.0 モードで GLSL を記述しなければなりません。

これは必然、attribute 修飾子は使えないということでもあるので注意しましょう。前回の GLSL ES 3.0 の概要を解説したときに書きましたが、GLSL ES 3.0 では attribute 修飾子は廃止されており使えません。その代わりに使うのが in 修飾子でしたね。今回の layout を使う場合は 3.0 モードで書くわけですから、当然 in 修飾子のほうを使って記述していくことになります。

layout 修飾子を使った attribute 定義

#version 300 es
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec4 color;

これを見るとわかるように、原則として layout 修飾子を用いる場合、同時にロケーション番号をしっかりと指定してやらなくてはなりません。ロケーション番号は整数で指定することになっているので、誤って 1.0 などというように、小数点を含む値として定義しないように気をつけましょう。

とは言え、使う上で必要になる知識はこれだけです。まったく難しいことはないですね。

シェーダ側でこのようにロケーション番号を指定した場合には、JavaScript 側でわざわざ gl.getAttribLocation をコールしなくても、あらかじめロケーションのインデックスが明確です。つまり、不要なメソッドの呼び出しを省略することができるわけですね。

まとめ

さて、ロケーションのインデックス値を固定できる layout 修飾子について見てきましたが、いかがでしたでしょうか。

実際には難しいことはほとんど無く、また同時に、あまり強力なメリットがあるというわけでもありません。

強いてメリットを挙げるとすれば、それはシェーダとアプリケーション側のデータの紐付けの概念がより強固になるということが言えると思います。定義しているんだかしていないんだか微妙な状態でロケーションを取得しようとするケースが減って、結果的にシェーダの実装とアプリケーションの実装をしっかりと意識して実装することになると思います。心理的な部分ではあるのですが、これは結構重要だと考えることもできるでしょう。

ただ、冒頭でも書いたように、これを用いたからといって速度が上がるとか、GPU の内部の処理が効率化されるとか、そういったことはありません。むしろ、効率的かつ自動的に行われる GPU のロケーションレイアウトに干渉することになるので、どちらかというと GPU のロジックに割り込んでいく処理であるというふうに言えると思います。

一応ベンチしてみた感じでは、これを使ったとしても極端に速度が落ちるようなことは無いようです。JavaScript 側の記述量、あるいはメソッドの呼び出し回数が減ることは確かですが、これも初期化時に行う類の処理内容であることを考えれば、それほど大きなメリットとは言えないでしょう。

いずれにしても、これを利用するかどうかで初期化ロジックを若干変更する必要があるので、自分が利用するスタンスにするのかしないのか、その点だけしっかり意識しておきましょう。

実際に layout 修飾子を使ったサンプルを置いておきます。動作確認などに、利用してみてください。

entry

PR

press Z key