Cocoa で OpenGL の描画 View を「複数」作る

今回は完全に自分のための備忘録です。

Cocoa 初心者なので、すごく初歩的な話題です。OpenGL も初心者みたいなものなので、致命的な勘違いがあるかもしれません。間違いがあったら是非教えて下さい。

目標

今回の目標は以下の通りです。

  1. Cocoa を使って、XcodeOpenGL を扱うプログラムを書きたい。
  2. 同じシーンを描画する複数の View を作りたい

ちょうど以下の画像のような状態を目指します。

f:id:yuki-koyama:20130613170434p:plain

ポイント1: NSOpenGLView を使わない

Cocoa で OpenGL を描画するためには NSOpenGLView を使うのがお手軽です。

しかし、NSOpenGLView ではレンダリングコンテクスト (NSOpenGLContext) を明示的に持たないため、複数の View を作るのに不適です。

sonson@Picture&Software - [OpenGL] レンダリングコンテキスト

そこで、NSOpenGLView を使わずに、NSView を継承したクラスを作り、レンダリングコンテクストを明示的に管理します。

OpenGL Programming Guide for Mac: Drawing to a Window or View
黒画面への道(CocoaでOpenGL) - nursの日記
View Programming Guide: Creating a Custom View

ポイント2: 1つのレンダリングコンテクストを複数の View で共有する

同じシーンを複数の View で (例えば違うシェーダや違う視点で) 描画する場合などには、1つのレンダリングコンテクストをそれぞれの View で共有するようです。

こうすることで、頂点バッファなどのシーンの情報や光源や素材などの描画に関する設定を自然と共有できます。

今回は違いますが、もしそれぞれの View が全く別のシーンを描くのであれば、レンダリングコンテクストは別々に持つべきでしょう。

実際に作る

実際に作ってみました。この記事の最初の画像がプログラムが動作している様子です。

という形になっています。球体の描画に VBO を使用していますが、View1 と View2 で VBO が共有されているのがポイントです。

ただし、View1 と View2 が対等な関係なら、そもそも View がコンテクストを管理するのではなく、コンテクストを管理するクラスを別途設けるべきだと思います。

ソースコード

公開するのもはばかられるほど汚いコードですが、備忘録として記録に残しておきます。

Xcode プロジェクト (zip)

なぜか Objective-C++ で記述してあります。

NSOpenGLView を使っていないため、各 View の drawRect の内容を実行する前に、以下のような命令を実行しています。

// 対象の View の切り替え
// 現在の View に対してレンダリングするように設定する
[context setView:self];

// コンテクストの切り替え
// 今後の OpenGL の命令はこのレンダリングコンテクストに対する命令だと解釈させる
[context makeCurrentContext];

ここで登場する context (NSOpenGLContext のインスタンス) を、それぞれの View で別々に持たずに、1つのインスタンスを共有しています。