かみのメモ

コンピュータビジョン・プログラムな話題中心の勉強メモ(記事一覧は https://kamino.hatenablog.com/archive へ)

OpenGLに入門する前に知っておきたかったこと

はじめに

最近、とある事情でOpenGL+GLSLの勉強をしていました。

目標はシェーダーを自分で書いて簡単な光路追跡法(レイトレーシング)っぽい処理を実装することだったので、とりあえずネットの情報と↓の本を使って勉強してみました。

OpenGL 4.0 シェーディング言語 -実例で覚えるGLSLプログラミング-

OpenGL 4.0 シェーディング言語 -実例で覚えるGLSLプログラミング-

が、OpenGL難しい!!

自分の環境に入っているOpenGLのバージョンを調べるとこから始めて、目標の処理を実装するまで2週間以上かかってしまいました。。。

この記事では自分が「勉強前に知っていたら捗ったのになあ」と思ったことをまとめてみたいと思います。 新しくOpenGLを勉強するときの取っ掛かりになれば幸いです。

※ 2018/09/13:項目1のタイトルを変え、中身を補足しました。項目2の用語の使い方が微妙だったので修正しました。
※ 2019/01/10:項目6を追記しました。
※ 2019/06/02:論旨はそのままに少し文章を修正しました。

もくじ

1. OpenGLは普通のライブラリとは違う

最初に思い切り騙されたポイントです。

OpenGL WikiのFAQに次のような記述があります(ざっくり翻訳)。

OpenGLとは? - OpenGLはラスタライズ方式のレンダリングシステムの挙動を示した仕様です。OpenGLレンダリングシステムをクライアントアプリから操作するためのAPIを定義します。(中略) GPUを製作するハードウェアベンダーはOpenGLレンダリングシステムを実装しなければなりません。(後略)

OpenGLオープンソースですか? - いいえ、OpenGLは一切ソースコードを含みません。OpenGLとはこのサイトで見れるような仕様のことです。OpenGLプログラマが挙動を指示するために使うインターフェースを定義するものです。(後略)

つまりOpenGLは単にAPIを規定した"仕様"であり、実際の処理はintelとかNVIDIAとかのハードウェアベンダーが独自に実装するものである、ということらしいです。

もう少し詳しく説明しましょう。 コンピュータ上でグラフィックを描画する作業はWindowsmacOSLinuxといったOSが管理しています。 そのため私達がグラフィックを描画するプログラムを書くときは、OSに「こんな画面描いて」と指示を出す必要があります。 ところが、各OSはグラフィック周りの処理を独自に実装しているので、OSへの指示の出し方も異なってきます。 OSごとに描画プログラムを書き直すのは非常に手間がかかる作業です。 そこで共通して利用できる描画指示のAPIが規格として定められました。 これがOpenGLです。

OpenGLが使えるかまたどのバージョンが利用できるかは、OSがOpenGLをサポートしているかどうかと、使っているGPU(グラボを挿していない場合はCPU内蔵のGPU)がOpenGLに対応しているかどうかに依存します。 普通のライブラリのように「インターネットからファイルをダウンロードしてくれば最新版が使えるようになる」とかそういったものではないのです。 現状ほとんどのOSとGPUOpenGLに対応しているので、ドライバーをきちんとインストールすればOpenGL 2系くらいまでのプログラムなら動くと思います。

ただし近年は少し動向が変わっています。 詳しくは6. 近年の動向(OpenGLを勉強する必要はあるのか?)で後述します。

ちなみにOpenGLはあくまでOSへの描画指示の規格の一例であり、OpenGL以外の規格も存在します。 WindowsmacOSはそれぞれDirectX、Metalという独自の規格を持っています。 これらの規格は各OSの内部処理に合わせて策定されているので、OpenGLを使った描画命令より高速に動作することが期待できます。

2. OpenGLはラスタライザー志向

CGで画像をレンダリングする手法はラスタライズ(rasterizing)によるものとサンプリング(sampling)によるものに分けられます。 そしてOpenGLは前者、ラスタライズ方式のレンダリングシステムとして使うことを前提に設計されています

ラスタライズ vs サンプリング

両者の違いをざっくり説明してみます。

ラスタライズ方式では、透視投影変換などのテクニックを使って、描画したい図形や物体を2次元平面(カメラ画像平面)に射影することで画像を生成します。 先に形状だけをカメラ画像平面に射影してから、法線やテクスチャ座標などの情報を使って色を決めるようなレンダリング手法です。

一方サンプリング方式ではシーンの中での光の反射の軌跡をシミュレートします。 そしてカメラにどのように光が入ってきてその結果それぞれの画素に何色が写り込むのかを計算することで画像を生成します。 レイキャスティング、レイトレーシング、レイマーチングなどの用語が絡むものはサンプリング方式に分類されます。

ラスタライズ方式の問題は物体相互の影響が考慮されないことです。 つまり影や鏡面反射による映り込み、間接照明などが一切反映されず、リアリティのないのっぺりした見た目になってしまいます。 これを改善するテクニックとしてシャドウマッピング、環境マッピングなどがあり、うまく活用すれば十分それらしいCGを生成できます。 ただ、リアリティを突き詰めようとすればやはり原理的な限界があります。

一方サンプリング方式の手法は現実空間の光の伝搬をシミュレートするという方法を取るので、非常にリアリティの高いCGを生成できます。 しかし、素直に全ての光路を計算していてはメモリと時間がいくらあっても足りませんので、シーンの特性に合わせて効率的に計算量を減らすためのノウハウが必要になります。

2019年現在、ゲームなどで使われるリアルタイムなレンダリングシステムのほとんどはラスタライズ手法の応用です。 ただ、リアルタイムなレイトレーシング手法も徐々に登場してきているので今後は情勢が変わってくるかもしれません。

ちなみにOpenGLで必ずしもサンプリング方式の実装ができないというわけではありません。 FragmentShaderやOpenGL4.3からGPGPU用に追加されたComputeShaderを使って工夫すれば、サンプリング方式のレンダリングシステムも構築することができます。 実際、そういうデモもよく見かけます。 ただし実装はあくまでOpenGLの流儀に則るので窮屈です。

3. GLUTとかfreeglutとかGLFWとか

OpenGLの入門記事を検索すると必ず出てくるキーワードですよね。 こいつらは一体何者なのか、明快に説明してくれている入門記事は少ないので戸惑いました。

結論から言えばこれらはOpenGLのプログラミングを簡単にするためのライブラリ(Utility Toolkit)です。 あくまでOpenGL本体からは切り離されたもので、これがなくてもOpenGLのプログラムは書けます。

なんで使うの?

これらは必須ではないものの、使わずに開発していくのはかなり面倒なのです。 というのも、最初に書いたようにOpenGLはあくまでレンダリングエンジンのAPIだけを規定したものであり、プログラム実行時にウィンドウを表示したり、そこにOpenGLのコンテキストを紐付けたり、マウスやキーボードの入力を受け付けたりといった機能は入っていません。 これらの機能は自分の環境のウィンドウシステムに合わせて個別に実装しなければなりません。

この実装を代わりにやってくれるのがGLUTなどのUtility Toolkitというわけです。 こうしたライブラリはメジャーなウィンドウシステムに一通り対応しているので、クロスプラットフォームで開発できるという利点もあります。

どれを使えばいいの?

最初に開発されたツールキットであるGLUTは多くの文献で利用されていますが、1998年移行メンテナンスされていないのでところどころ問題が出てきているようです(マウスホイールに対応していないとか、OpenGLコンテキストのプロファイル指定ができないとか)。 最近はfreeglutやGLFWなどがオープンソースで開発されているのでそちらを利用するのが一般的です。

また複数のOpenGLコンテキストを利用するなど複雑な実装をしたい場合は、どのツールキットを採用するか吟味する必要があります。

4. 2つの描画命令方法

OpenGLのサンプルコードを探しているとき、よくこの問題に行き当たりました。

OpenGLには旧式のFixed Function Pipelineによる描画方法と、新式のProgrammable Pipelineによる描画方法があります。

見分け方ですがglBegin(GL_LINE_LOOP)などから始まる方は旧式のコードです。 glGenBuffer()glDrawArrays()などを使っているのが新式のコードです。 それぞれ公式ドキュメントのFixed Function PipelineRendering Pipeline Overviewで解説されています。

もともとOpenGLは固定のレンダリングパイプラインだけを持っていました。 レンダリングパイプラインとはラスタライズ方式でレンダリングするときの一連の処理のことです。

CGの基本は、3Dオブジェクトはメッシュもしくは基本図形(プリミティブ)の集合として記述し、表面の反射特性や光源の位置を与え、カメラのパラメータを設定すると画像がレンダリングできるというものです。 OpenGLもそれに合わせて、glEnable(GL_LIGHTING)のような関数でシーンを設定し、glBegin(GL_LINE_LOOP)などの関数でプリミティブを描画させる仕様になっていました。

しかしCGの研究が進むに連れて、レンダリングパイプライン内でもっと複雑な処理を実装したいという需要が出てきました。 そこでOpenGL2.0からはGLSLという専用のシェーディング言語を使ってレンダリングパイプライン内の処理もプログラムできるように仕様が変更され、これに伴って描画命令の方法も大きく変化しました。 ここで生まれたのが新式の記法です。

OpenGL3.2以降は旧式の描画命令は互換プロファイルでのみサポートされています。 新式の描画命令はBufferやVariable TypeなどOpenGLの内部構造を意識したコードを書く必要があるので理解するまでに時間がかかりますが、プログラミングの自由度・パフォーマンスは向上します。 今後、旧式はサポートが打ち切られることも考えられるため、新しく勉強する人には新式の書き方を覚えることをおすすめします。

5. OpenGL ESとかWebGLとか

本家のOpenGLはデスクトップ・ラップトップPCで動作するOSに向けて策定された規格です。 一方、OpenGL ESはEmbedded Systemsの名前の通りスマホなどの組込みシステムで動作させることを目的に策定されたOpenGLのサブセット、簡単に言えば縮小版です。

WebGLはそのOpenGL ESの派生として策定されたJavaScript APIです。 ブラウザ上でOpenGLを動かすことを目的に作られたもので、JavaScriptOpenGLを使ってグラフィックを描画するプログラムを書くことができるようになります。

WebGLOpenGL ESとOpenGLのバージョン番号と仕様は必ずしも一致しているわけではないので、勉強するときには注意が必要です。

6. 近年の動向(OpenGLを勉強する必要はあるのか?)

最初の項で説明したようにOpenGLを使うメリットは、多くのプラットフォームでサポートされているためクロスプラットフォーム開発が可能であるという点です。 しかし、近年では少し事情が変わってきています。

OpenGLのレガシー化

項目2で説明したようにOpenGLはラスタライズ方式のレンダリングパイプラインを実装する前提で設計されているのですが、CGの研究が進むに従ってサンプリング方式のレンダリング手法や、既存のパイプラインの枠に収まらない計算手法が登場し始めました。 加えて、GPUがシミュレーションやDeep LearningなどCG以外の目的で使われるようになったことでGPUのハードウェア設計が多様化し、OpenGLの仕様ではハードウェア性能を限界まで引き出すことができなくなってきました。 つまりOpenGLの規格がレガシー化しつつあるわけです。 これを受けて近年ではVulkanという新しいグラフィックAPIの策定・普及が進んでいます。

また2018年6月にはmacOSにおいてOpenGL非推奨化されることが発表されました。 アップルはこれまでもOpenGLのバージョン追従が遅い傾向にあったのですが、今回思い切ってサポートを打ち切った形です。

参考:アップルがmacOS 10.14 MojaveでOpenGL /GL ES、OpenCLを非推奨化。Metalへの移行推奨 - Engadget 日本版

他のクロスプラットフォーム開発手法の登場

さらに近年ではUnity・Unreal EngineなどのゲームエンジンやHoudini・MayaなどのCGソフトが登場し、OpenGLやVulkanがサポートする低レイヤー処理を直接書く必要がなくなってきたという事情もあります。 これらのソフトを使えばオブジェクトのパラメータをいじるだけで多彩な質感やエフェクトを表現できますし、ゲームやアニメーションも簡単に作ることができます。 またこれらのソフトは様々なグラフィックAPIOpenGL, WebGL, DirectX, Metalなど)の上で動くように作られているため、ソフトに従ってレンダラーを実装すれば簡単にマルチプラットフォーム化できてしまいます。

OpenGLを勉強する必要はあるのか?

こうした事情の中でOpenGLを勉強する必然性があるかと言えば微妙なところだと思います。 高度なCGをレンダリングしたい、ゲームを作りたい、という人は先ほど紹介したようなソフトの勉強に力を注いだほうがいいでしょう。

ただしOpenGLは良くも悪くも古い時代に生まれた規格なので、非常に扱いやすくCGの基本に忠実です。 コンピュータがどのように画像を描画しているのかを勉強するにはちょうどよい題材だと思います(Vulkanは複雑過ぎて入門に全く向かない)。 また文献が多いので、データの可視化などちょっとしたグラフィック処理を実装するのは比較的ラクです。 加えてthree.jsなどのライブラリを使わずにWebGLを使いたい、という人は必然的にOpenGLを勉強することになると思います。

おわりに

以上、自分が勉強前に知っておきたかったと思ったことをまとめてみました。