自習室

こもります

openFrameworks, Three.js, Processing のGLSL バージョン対応状況調査

はじめに

openFrameworksのセミナーでShaderに触れた

この週末、合宿で行われた openFrameworks のセミナーに参加してきました。

セミナー本体の紹介は @yumu19 さんが現場の雰囲気なども伝わってくる素敵な記事を書いて下さっています。

講義内容の紹介は、 @shu223 さんのブログが充実しています

このイベントについて、このほかにも計5本もの記事を書かれていますスゴイ!

このセミナーの中で、FrameBufferObjectの使い方、PostProcessのためのaddonの使い方など、Shaderに関わる話がたくさん出てきました。

Shader言語のバージョン対応状況について気になった

最近仕事でもThree.jsをつかったり、趣味でoFやProcessingを触っていたので、各開発環境ごとにびみょーに異なるGLの対応状況をまとめて置きたくなりました。それぞれ、

環境 GLのライブラリ プログラミング言語
Three.js WebGL Javascript
openFrameworks OpenGL C(C++)
Processing JOGL Java

という感じで、同じOpenGLではあるのですが、それぞれ違う言語ですし、さらにそれぞれのラッパでくるまれた状態になっています。 しかし、そのなかで実行時に解釈されるglslについては、おなじバージョンでさえあればほぼ同じ書き方で行けます。

これまでShaderにまじめに取り組んで来なかったので、これを機に勉強してみようかな、と思ったのですが、実は各環境ごとにどうもGLの対応状況が異なるようです。

上記3環境についてGLの対応状況を調査し、自分がどのバージョンでglslを書けば良いか判断するのが、本記事の主な目的になります。もちろん最終的には、やりたい表現や案件次第で選ぶことになりますが、手始めに手をつけて勉強するためのバージョンを選ぶ、という感じです。

前提知識

GL, GL ES, のバージョンの前後関係や glsl のバージョンとの対応は こちらのサイト様に綺麗にまとまっていましたので、参考にさせていただいております。

また、最新までは更新されていませんが、バージョンごとにどのような機能が実装されてきたか、について、こちらのサイト様が端的にまとめて下さっています。

このあたりを参考にしながら本記事を書きました。

環境

  • MacBook Air 2012 Mid
  • Xcode 6.0.1
  • openFrameworks v.0.8.4
  • Three.js r68
  • Processing 3.0a4

oF, Three, Processing については、本記事執筆時の最新リリースを利用しています。

openFrameworks v.0.8.4

glInfoExample

公式のサンプルにglのバージョンを確認する exaples/gl/glInfoExample というプロジェクトがあります。実行した後の画面はこんな感じ

f:id:AMANE:20141013205911p:plain

メインウィンドウの一番上に "opengl version: 2.1" と出ていますが、これは「このプロジェクトが」2.1で動かされました、と言う意味で、ハードウェアやライブラリの対応状況を表した物ではありません。

隣には、出力されたtxtが開かれています。これは GL の拡張機能をロードするヘルパライブラリのglew が、「私ここまでなら行けますよ」と言っている物で、このoFに含まれて居るglew的には 4.1 まではいける、ということらしいと分かります。

実際に作ってみる: 素のプロジェクトの場合

ofのプロジェクトに、以下のコードを足して、GLの対応状況を出力させます。たとえば、main.cpp でOpenGLをセットアップした後に入れると良いと思います。

// main.cpp
ofSetupOpenGL(1024,768, OF_WINDOW);   

cout << "Vendor :" << glGetString(GL_VENDOR) << '\n';
cout << "GPU : " << glGetString(GL_RENDERER) << '\n';
cout << "OpenGL ver. " << glGetString(GL_VERSION) << '\n';
cout << "GLSL ver. " << glGetString(GL_SHADING_LANGUAGE_VERSION) << '\n';

この書き方については、こちらのサイトを参考にさせていただき、最後の SHADING_LANGUAGE_VERSOIN を追加しています。

実装しているGPUのOpenGLのバージョンを調べる

ProjectGeneratorで出力した素のプロジェクトでこれをやると、以下の様な出力になります

Vendor :Intel Inc.
GPU : Intel HD Graphics 4000 OpenGL Engine
OpenGL ver. 2.1 INTEL-8.28.32
GLSL ver. 1.20

これは、glInfoExample が出力しているのと同じですね。

PCごとの最新GLを利用する

マシンが使っているGPUと、oFのバージョンによって、利用できるGLのバージョンが変わります。openFrameworksで最新のGLを使える様にするには、以下のコードを加えます

#include "ofGLProgrammableRenderer.h"

int main( ){
    ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE);
    ofSetupOpenGL(1024,768, OF_WINDOW);   

これで新しいGLに対応したレンダラーを利用するようになります。この書き方については、oF公式のShaderチュートリアルが参考になります

こうした後に、先ほどと同様にGLのバージョンを確認すると、このような出力になります。

Vendor :Intel Inc.
GPU : Intel HD Graphics 4000 OpenGL Engine
OpenGL ver. 4.1 INTEL-8.28.32
GLSL ver. 4.10

注意点としては、GL3.0 以上を使う場合、 GL2系で使われていた varying などの記述が使えなくなり、実行時にエラーが出ます。(glslコードのコンパイル時にエラーが出ます) 多くのサンプルプログラムが動かなくなります。

oFの場合、最新を使うべきか、GL2系にとどまるべきか

oFでシェーダを活かしたナイスなAddonに ofxPostGlith や ofxPostEffect を、参加したOFセミナーで教えていただきました。これらは共に GL2系のglsl で書かれています。

oF公式のShaderチュートリアルでは、GL2、GL3、ES2 がすべて添付されて、実行環境ごとに最適な物に切り替えられるようサンプルが作られています。

常に最新についていった方が将来幸せですし、最近話題のMRTを使ったDeferred Renderingなんかも視野に入れると、早めにGL4.0な書き方に移行していくのが望ましいのですが、学習中の身としては、サンプルの多いGL2.0系が捨てがたいです。

Three.js r68

WebGLOpenGL ES 2.0 をベースにしています。GL ES 2.0 はOpenGL本筋で言うと GL2.0 相当なので、2004年リリースと、結構古いです。OpenGLの歴史についてはWikipedia参照。

OpenGL - Wikipedia

このことは以下の様な手順で確認出来ます

  1. Three.js のサンプルから適当なページを開いて
  2. Developer Tools を開き
  3. rendererの初期化後の箇所にブレイクポイントをはってリロードして止めて、
  4. Consoleで以下の様なコマンドを叩くことで確認出来ます
_gl = renderer.context; // WebGLのコンテキストを取得する
//WebGLRenderingContext {drawingBufferHeight: 150, drawingBufferWidth: 300, canvas: canvas, activeTexture: function, attachShader: function…}

_gl.getParameter(_gl.VERSION); // WebGLのバージョンを確認する
//"WebGL 1.0 (OpenGL ES 2.0 Chromium)"

_gl.getParameter(_gl.SHADING_LANGUAGE_VERSION); //シェーディング言語のバージョンを確認する
//"WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium)"

実際にやるときはこんな画面です

f:id:AMANE:20141013214708p:plain

ちなみに、上記のやりかたを見つける上で、この資料が役に立ちました。WebGLで利用できる関数や定数が一覧になっています。

WebGLリファレンス(PDF)

WebGLでは今のところ選択肢無し

WebGL 2.0 で GLES 3.0 相当になる、と言うのが、ドラフトで発表されていますが、それも今年8月の話なので、(少なくともThree.jsは) しばらくはWebGL 1 (つまりES2.0相当) のつもりでいれば良いかな、という認識です。

WebGL 2 Specification

Three.js のシェーダのサンプルが非常に充実している件

Three.js のShaderをつかったサンプルは、ただシェーディングだけでは無く、gpgpu的な使い方をした物もあり、非常に参考になります。これらを教材(やパクリ元)として使わない手は無いので、その点で ES2.0 にとどまる大きなメリットがあると言えます。

three.js - examples

Processing 3.0a4

Processing follows the specification set by OpenGL ES,

公式にはこのように書いてあります。 Processing 3.0 として配布されているサンプルをいくつか覗いてみたところ、varying や texture2D といった記述があるところから、 たしかにES 2.0 つまり glsl 1.0 相当であることが確認出来ます。

ただし、GL3.0 以降に対応していないと言うわけではなさそうです。

Processing で GL3.0 以降を使ってみる

このフォーラムが参考になりました

このフォーラム下の方に記載されているサンプルは、そのままでは動きません。PJOGLのプロファイル(詰まり、利用するGLのバージョン)を切り替える必要があって、そのためには、以下のコードが必要です。

// glsl150test.pde 
import javax.media.opengl.GL3;
{PJOGL.PROFILE = 3; } // PJOGL内部でProfile=3と指定すると、GLES3.0が利用される

Pshader shader;

void setup()
{
// 以下略

グラデーション出塗りつぶすだけの超簡単な物ですが、実働するサンプルを github に上げました。

f:id:AMANE:20141014230157p:plain

ナイスな作例

こちらで実際にgithubに上げられている作例は非常に良い感じです。

  • ジオメトリシェーダで分割をするサンプル

このあたりは、ES 3.0 を利用して実現しているようです。

しかしやはりES2.0がまだまだ隆盛

とまぁProcessingでも ES3.0 が使えることは確認出来たのですが、公式のサンプルや下記のイケてるチュートリアルも ES 2.0 系で書かれているので、 3.0以降に移行するメリットは今のところ(僕には)少なさそう、という印象。

おまけのAndroid

実際にAndroidでGLばりばりな開発をしているわけでは無いのではっきりとしたことは言えませんが、Android の次のバージョン Android L で、OpenGL ES 3.1 をサポートすることになっているようです。 OpenGL ES 3.1 は、本家OpenGL 出言うと OpenGL 4.4 / GLSL 4.4. 相当のようです。

iOS はよくわからないっす

まとめ

結論としては、私は暫く、GL 2.1 / glsl #version 120 な書き方をしようと決めました。理由は、多くのサンプル・公開されている作品が、未だGL 2.1 , ES 2.0 系なシェーダ言語で書かれているからです。しかし一方で、あれこれ読んでみた結果、多少の接頭辞を変換すれば 3.0 以上へ対応するのも、めちゃくちゃ大変というわけではなさそうな印象を持ちました。

まずは、Vertex Shader, Fragment Shaderの基本を、2.1系で学び、MRTやテッセレーションなどの技術が必要になったら、改めて 3.0 以上に移行していこうと思います。