かみのメモ

コンピュータビジョン・プログラムな話題中心の勉強メモ

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

はじめに

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

が、OpenGL難しい!!

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

ということで、この記事では自分がOpenGLに取り組んでみて「勉強前に知っていたら捗ったのになあ」と思ったことについてまとめたいと思います。 新しく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に内包されているGUIパッケージ)が管理しています。 そのため、私達がCGを描画するプログラムを書くときは、OSに「こんな画面描いて」と指示を出す必要があります。 ところが、各OSはグラフィック周りの処理を独自に実装しているので、OSへの指示の出し方も異なってきます。 OSごとに描画プログラムを書き直すのは非常に手間がかかる作業です。

そこで、共通して利用できる描画指示のAPIの規格としてOpenGLが定められました。 OpenGLAPIを利用してプログラムを書くことで、どの環境でも同じようにCGを描画できるようになるわけです。

ただし、あくまで「OpenGLAPIを受け付けるように開発していこうね」とみんなで示し合わせているだけなので、ハードウェア、ドライバー、OSのベンダーがこれを守るかどうかは自由です。 そのため、OpenGLが使えるか、またどのバージョンが利用できるかは、OSがOpenGLをサポートしているかどうかと、使っているGPU(グラボを挿していない場合はCPU内蔵のGPU)がOpenGLに対応しているかどうかに依存します。 普通のライブラリのように「インターネットからファイルをダウンロードしてくれば最新版が使えるようになる」とかそういったものではないのです

現状、ほとんどのOSとGPUOpenGLに対応しているので、ドライバーをきちんとインストールすればOpenGL 2系くらいまでのプログラムなら動くと思います。

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

ちなみに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を勉強することになると思います。

おわりに

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