OpenGL ESでの画角の指定

iPhone 上でOpen GL ES1を利用して、画角を指定してのオブジェクトの描画方法を調べてみまたので、
メモです。
(もっと、きちんとした方法が他にあるのだとうとはおもいますが....)

前提準備

  1. XCodeでOpen GL ES Applicationを選択してプロジェクトを作成。これによって、テンプレートソースが生成される。
  2. OpenGL ES 2.0 対応を無効にする

EAGLView.m の initWithCoder メソッドでのES2Rendererオブジェクトの生成部分をコミットするだけ.

// renderer = [[ES2Renderer alloc] init];

これで、ES1Renderer.m の renderメソッドを編集することにより、
Open GL ES1 での描画をすることができる。

ここらはこちらなどを参照.

描画実装の前提

とりあえず、簡略可するために以下の制限、前提での実装としました。

  • 幅->1.0, 高さ->1.0 / (Window の幅 / 高さ), 奥行き1.0のサイズのオブジェクト空間に描画することとする。座標としては、x -> -0.5〜 0.5, y -> -0.5 * (Window の幅 / 高さ)〜0.5 * (Window の幅 / 高さ), z -> -0.5 〜0.5の

範囲のオブジェクトが描画されるものとする。

  • 水平画角での計算とする。

実装

画角/2に対するtanの逆(余接)にObject座標の大きさ(1.0)を掛けたものが、表示範囲(視体積)の一番手前となり、
かつ、オブジェクトの手前になるように実装しました。
手順としては。

  1. 画角/2に対するtangentの逆(余接)にObject座標の大きさ(1.0)を掛けたものが、表示範囲(視体積)の一番手前となるよう、glFrustumfでの設定を行う。
  2. 描画オブジェクトを原点から表示範囲の手前までの距離とObject座標上のZ座標のマイナス方向の大きさを加えた距離だけマイナス方向に移動.これで、Objectのマイナス側の一番手前が、表示範囲(視体積)の一番手前となる.


ES1Renderer.m の renderメソッドの実装は以下のとおりです。画角は60度とベタに指定しています。

- (void)render {
  // This application only creates a single context which is already set current at this point.
  // This call is redundant, but needed if dealing with multiple contexts.
  [EAGLContext setCurrentContext:context];
 
  // This application only creates a single default framebuffer which is already bound at this point.
  // This call is redundant, but needed if dealing with multiple framebuffers.
  glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
  glViewport(0, 0, backingWidth, backingHeight);

 
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  GLfloat fovy = 60.0f;  // 画角を60度とする
  /*
       角度にあわせた視体積の設定.
        tanの逆(余接)にObject座標の大きさを掛けたものが、
    nearの位置にくるようにする.
  */
  GLfloat aspect = (GLfloat)backingWidth / (GLfloat)backingHeight;
  GLfloat width = 1.0f;
  GLfloat height = width / aspect;
      GLfloat near = 1.0f;
  GLfloat far = 100.0f;
  near = 1.0f / tan(fovy * 0.5 * M_PI / 180.0) * width;
  GLfloat x = width / 2;
  GLfloat y = height / 2;
  glFrustumf(-x, x, -y, y, near, far);
     NSLog(@"glFrustumf(%f,%f,%f,%f,%f,%f)",-x, x, -y, y, near, far);
  /*
    視体積のnearの位置にあわせて、モデルZ座標を移動
    原点からnearまでの距離+ObjectのZ座標のマイナス方向への大きさ分だけマイナス方向に移動.
    これで、Objectのマイナス側の一番手前が、
    視体積の一番手前となる.
  */
  //
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(0.0f, 0.0f, -(width / 2) - near);
   NSLog(@"glTranslatef z = %f",-(width / 2) - near);
  // .... ここでオブジェクトの描画を....
   // [self draw];
  // 
  // This call is redundant, but needed if dealing with multiple renderbuffers.
  glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
  [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}