第2回 OpenGL ESを用いた簡単な図形の描画

カンデラの開発者による連載コラムです。 第2回は、「OpenGL ESを用いた簡単な図形の描画」の基礎編です。

OpenGL ESは組み込み系のグラフィック用のミドルウェアとしてメジャーなものとして挙げられます。OpenGL ESは3DのGPUを搭載したターゲットにライブラリ提供されていることが多く、スマートフォン向けのゲームなどのグラフィック表現も、こちらを使って実現されています。今回と次回の2回に渡り、OpenGL ESを使って簡単な図形を描画してみましょう。

OpenGL ESに関する基礎知識

実際に図形を描画してみる前に、OpenGL ESにまつわる基本的な知識をご紹介します。

構成

OpenGL ESやOpenVGなどの描画APIを用いたアプリケーションを開発する場合図1のような構成図となります。こちらにある通り、描画APIは単体で動作させることができず、EGLというライブラリのAPIも合わせてコールする必要があります。

EGL

描画APIの呼び出し自身は、プラットフォーム依存はありません。しかし、描画APIと実際の描画先( ウィンドウシステムなど )はプラットフォームによって実装が異なります。この間を取り持つ役割として、EGLというAPIが存在しています。EGLのAPIの実装はプラットフォーム毎に異なりますが、呼び出し方法は統一されているため、図1のような構成で、プラットフォーム依存部分を必要最低限として、アプリケーションを実装することができます。

OpenGL ES

OpenGL ESは、現在、1.1、2.0、3.0、3.1、3.2というバージョンが存在します。現在組み込み機器向けで主流となっているGPUでは、バージョン2.0以上の対応となっていることが多いです。バージョンの数字によって、対応している機能が異なりますが、本稿ではバージョン2.0以上を対象としたいと思います。

画面に何かを描画するとは

ここまでの内容で、OpenGL ESを用いたアプリケーションを開発する場合は、EGLのAPIとOpenGL ESのAPIを呼び出すアプリケーションソフトウェアを実装すればよいという感覚を持たれたかと思います。では、次に、OpenGL ESを使って画面に何かを描画する際の仕組みについて、簡単にご説明します。

描画先とは

最終的な出力先は液晶ディスプレイですが、ソフトウェアとして、その出力先を扱える論理的な場所が存在していなければ、描画を行うことはできません。それは、画面サイズ分の色の情報などの集合で、プログラミングなどでよく使われる用語で表すとメモリの領域やバッファというこになります。この領域は、グラフィック用のミドルウェアの実装に依存して、CPUから操作できるメモリ、GPUから操作できるメモリ、そのいずれからも操作できるメモリに存在する可能性があります。この領域のことをフレームバッファと言います。ここで、色の情報「など」と記載していることには理由がありますが、簡単な図形を一つだけ描画する場合は特に気にする必要はありませんので、割愛します。

OpenGL ESを使った描画

OpenGL ESはEGLと協調動作し、描画コマンドを処理し、それをフレームバッファに描画するという役割を担っています。ですので、何かを描画したい場合は、OpenGL ESが解釈することのできるコマンドを作成し、それをOpenGL ES側に伝えるという処理をアプリケーションソフトウェア側で実装することになります。以下は、そのコマンドを生成するために必要な知識の説明となります。

頂点

これは一般的な幾何学における頂点と意味としては同じです。何らかの形状を作るためにはそれがどの位置に存在している点を結んでできるものかを表さなければなりません。例えば、三角形の場合は3点、四角形の場合は4点の頂点が必要になります。

フラグメント

グラフィック用のミドルウェアの種類によっては、ピクセルと呼ばれることもあります。描画面( フレームバッファ )における1点のことです。後述するフラグメントシェーダにて、最終的な描画色を決定するときの単位です。

シェーダ

GPU側で動作するプログラムです。なぜGPUでプログラムを動作させなければならないかというと、OpenGL ESのバージョン2.0以降で何かを描画する場合、図2のようなパイプラインで動作するからです。何を描画するにもこの流れになるため、シェーダが必須となります。必要最低限のシェーダの種類は、図2の通り、頂点シェーダとフラグメントシェーダの2種類になります。頂点シェーダでは各頂点に対しての変形( 入力されてきた、頂点に対して行列をかけて変形させるなど )を行い、フラグメントシェーダではフラグメント毎の色の決定を行います。OpenGL ESにおけるシェーダの記述言語はGLSLと呼ばれるもので、文法については、C言語に似た書式となります。アプリケーションプログラム中に、文字列として記述し、アプリケーションプログラムからコンパイルする方法と、予めコンパイルしたものをアプリケーションプログラム側からロードする方法があります。本稿では、前者の方法を採用しますが、具体的な記述方法等につきましては、次回、ご紹介したいと思います。

画面ではないフレームバッファ

通常の描画では、EGL側で作成した描画面( Surface )がフレームバッファとなります。一方で、OpenGL ESでは、Surfaceでない描画先( フレームバッファ )を作ることができます。これはFBO( Framebuffer Object )と呼ばれています。図3は通常のフレームバッファへの描画とFBOを使った場合の描画の流れを示しています。FBOを使った場合、まずFBOに対しての描画を行います。しかしこの処理だけでは、実際の描画面( フレームバッファ )にはまだ何も描画されていません。FBOの内容をフレームバッファに描画するためには、FBOの内容を画像として、フレームバッファに描画しなければなりません。一見回りくどいだけでメリットがなさそうですが、例えばFBOの内容をフレームバッファに描画する際のフラグメントシェーダに何らかの効果を記述しておくと、画像編集ソフトなどで使われる、フィルタやエフェクトといった効果を実装することができます。こういった、実際のフレームバッファ外に描画する方法のことをオフスクリーンレンダリングとも呼びます。

座標系

3D空間に何らかの素材を配置して、それをフレームバッファで描画する場合、座標系に気をつけなければいけません。この座標系をケアした計算を頂点シェーダで行うことになるのですが、本稿では2D描画を中心的に扱いますので、説明を省きたいと思います。今回は図4の座標系をイメージしてください。中心が( 0, 0 )、右上が( 1.0, 1.0 )、左下が( -1.0, -1.0 )となります。

まとめ

これまでの知識をおさらいしましょう。図5が、今回ご説明した内容をすべてつなげた場合の説明となります。まずは、描画先を決定します。それはフレームバッファと呼ばれるものですが、オフスクリーン描画を行う場合は、別途OpenGL ES内でFBOを作成する必要があり、FBOに一度描画したものをフレームバッファに描画することになります。次に、描画するモノ( 頂点 )を用意します。そして、その頂点を描画するためのプログラムであるシェーダを用意します。このシェーダを使って最終的なフラグメントの色を決定します。以上が描画の流れとなります。

今回は、OpenGL ESとそれを用いた描画に関する基礎知識をご紹介しました。次回は、実際にOpenGL ESを用いて簡単な図形を描画する方法をご紹介したいと思います。