ABA Games

GL4Java自分FAQ


このページは、OpenGLのハードウェアアクセラレーションをつかって、 Javaでもリアルタイムゲームが作れるんじゃないか、という安易な発想の元、 GL4Javaに手を出した人間の奮闘記(あがき)です。

Q1. GL4Javaってなに?

JavaからOpenGLを使うためのしくみの一つです(OpenGL Java bindingと呼ばれる)。 OpenGLは、標準的な3DグラフィックスAPIです。 GL4Javaを使うことで、Javaから簡単にOpenGLの各種APIをさわることができます。

Webページは、ここ

Q2. OpenGL Java bindingっていろいろあるけど、どれがいいの?

わかりません。

一覧は、 ここ にあります。ちょっと前までは、Magicianなんかが一番よくできてそうに 見えたのですが、タダでないことに2の足を踏んでいたら、サポートを止めてしまったようです。 (4/15現在。あんまり売れなかったことが原因、とWebに書いてある) (5/30現在、Magicianは復活しています)

つうわけで、GL4Javaにしました。これはタダです。おそらく。 メンテナンスもされてそうだし、多くのプラットフォームで動きます。 ドキュメントも豊富です。

5/30現在、最新版は2.0.0R1です。

Q3. 1.2.0のAPIをみると、馬鹿でかいGL4Java.GLFrameとかいうクラスがあるんだけど、これでいいの?

2.0.0から、GLFrameは廃止され、GLCanvas一本に絞られました。 また、メソッドを一つのクラスに張り付けるのもやめられ、いくつかの インタフェースなどに分割されました。

これでだいぶ見通しはよくなったのですが、1.2.0から2.0.0に移行する際には 結構な書き直しが必要です。

Q4. インストールはどうするの?

以下はWindowsの場合の話です。

ダウンロードした、 をどこか適当なディレクトリに展開してください。GL4Javaというディレクトリの下に 必要なファイル群があります。

binpkg\libGL4Java-Win32-x86ディレクトリ内のdllを実行時に見えるところ、 もしくはWindowsのシステムディレクトリにコピーしてください。 2.0.0から、SGIのOpenGLドライバを利用することはなくなりました。 Microsoft謹製のドライバを使って下さい。

また、binpkg\gl4java.jarにクラスパスを通す必要があります。

以上。

Q5. GLCanvasってどう使うの?

GL4Javaは、基本的にGLCanvasのメンバ変数glやgluのメソッドを たたいてアクセスします。 そこで、まずGLCanvasをextendsしたクラスを作って、 そのinitメソッドをオーバライドし、適当な初期化処理を行います。

  public void init() {
    gl.glClearColor(0, 0, 0, 0);    // 背景は黒
    gl.glFrontFace( GL_CW );

    gl.glDisable(GL_LIGHTING);      // 光源関係の処理?
    gl.glDisable(GL_LIGHT0);

    int width  = cvsGetWidth();     // ビューポートの設定
    int height = cvsGetHeight();
    gl.glViewport( 0, 0, width, height );

    gl.glEnable(GL_DEPTH_TEST);     // デプスバッファを有効にする
    gl.glEnable(GL_CULL_FACE);      // 裏面は表示しない
    gl.glMatrixMode(GL_PROJECTION); // ビューの設定、らしい
    gl.glLoadIdentity();
    glu.gluPerspective(
     90.0, 1.0, 1.0, 100.0);     // 見える範囲, アスペクト, 近傍面, 遠方面
    gl.glMatrixMode(GL_MODEVIEW);   // 以後、表示するモデルを移動、回転、変形させる
    gl.glLoadIdentity();
    glj.gljCheckGL();
  }
glLoadIdentityは不要かもしれません。はずしてもちゃんと動いているように見えます。

Q6. 立方体でも表示させましょうか?

そうしましょう。

Java 3DのShape3Dのような便利なクラスはないので、自前で似たようなものを作ってみましょう。 今回は、draw(GLFrame)メソッドを備えたインタフェースIShapeを実装して、立方体を表示するクラスを 作ってみました。

public class Cube implements IShape {
  private float[][] vtxs = {  // 頂点の座標の定義
    {1,1,1}, {1,-1,1}, {-1,-1,1}, {-1,1,1},
    {1,1,-1}, {-1,1,-1}, {-1,-1,-1}, {1,-1,-1},
    {1,1,1}, {-1,1,1}, {-1,1,-1}, {1,1,-1}, 
    {1,-1,1}, {1,-1,-1}, {-1,-1,-1}, {-1,-1,1},
    {1,1,1}, {1,1,-1}, {1,-1,-1}, {1,-1,1},
    {-1,1,1}, {-1,-1,1}, {-1,-1,-1}, {-1,1,-1},
  };

  public void draw(GLFunc gl) {
    for ( int idx=0 ; idx < vtxs.length ; idx+=4 ) {
      switch ( idx ) {
        case 0:
          gl.glColor3f(1.0f, 1.0f, 1.0f);  // 描画色の指定
          break;
        case 4:
          gl.glColor3f(1.0f, 0.1f, 0.1f);
          break;
        case 8:
          gl.glColor3f(0.1f, 1.0f, 0.1f);
          break;
        case 12:
          gl.glColor3f(0.1f, 0.1f, 1.0f);
          break;
        case 16:
          gl.glColor3f(1f, 1.0f, 0.1f);
          break;
        case 20:
          gl.glColor3f(1f, 0.1f, 1.0f);
          break;
      }
      gl.glBegin(GLFrame.GL_QUADS);  // 四角形を書き始める
      gl.glVertex3fv(vtxs[idx]);     // 各頂点の指定
      gl.glVertex3fv(vtxs[idx+3]);
      gl.glVertex3fv(vtxs[idx+2]);
      gl.glVertex3fv(vtxs[idx+1]);
      gl.glEnd();                    // 描画指定終了
    }
  }
}
まず、glColor3fメソッドで、表示するものの色を決めます。 そうしたら、glBeginメソッドで、表示するものの形状を指定します。 ここでは、GL_QUADSで、四角形を書くことを宣言しています。 (ほかにも、TRIANGLE_ARRAYやTRIANGLE_FAN, TRIANGLE_STRIPなどがあるようです。 APIドキュメントを参照しましょう。) glVertex3fvメソッド(glVertex3fでも可。違いは、配列で与えるかどうかだけです)で、 各頂点の座標を与えましょう。最後にglEndとすることで、描画が行われます。

ここで指定する順番で面のCULLINGが行われると思われるので、 頂点を指定する順番には注意しましょう。

Q7. 物体の移動、回転はどうやるの?

Q6で定義したIShapeインタフェースを持つインスタンスを、 指定の場所、角度で表示するクラスTrnsObjを作ってみます。

public class TrnsObj {
  public float x, y, z, d1, d2, d3;  // 描画する位置、角度
  private GLFunc gl;  // 描画する
  private IShape shape;     // 描画する形を定義したインスタンス

  public TrnsObj(IShape shape, GLFunc gl) {
    this.gl = gl;
    this.shape = shape;
  }

  public void draw() {
    gl.glPushMatrix();          // 変換マトリクスを待避
    gl.glTranslatef(x, y, z);   // 位置を設定
    gl.glRotatef(d1, 0, 1, 0);  // y軸回り回転
    gl.glRotatef(d2, 1, 0, 0);  // x軸回り回転
    gl.glRotatef(d3, 0, 0, 1);  // z軸回り回転
    shape.draw(gl);             // 描画
    gl.glPopMatrix();           // 待避していたマトリクスを復帰
  }
}
publicメンバに指定された場所、角度で書くことにします。

drawメソッドを見てください。まず、glPushMatrixメソッドで変換行列を待避します。 これをやらないと正しい位置に描画できません。理由はよく分かってません。 その後、glTranslatefによって変換マトリクスに位置を設定します。

そして角度を設定するのですが、それにはglRotatefメソッドを使います。 このメソッドは、(おそらく)最初のパラメタに、回転する角度を度(360度=1回転)で指定します。 (なぜ度なのかはわかりません。2π=1回転にする設定もあるのかもしれません) その後の3つのパラメタが(たぶん)回転軸をあらわすベクトルです。 ここでは、d1, d2, d3をy, x, z軸回りの回転に適用しています。

そうしたら、さきほど用意したIShape.drawメソッドを呼び出します。 その後、待避していた変換行列をglPopMatrixメソッドでとり出して、めでたしです。

Q8. シーン描画用のメソッドはどんな感じ?

こんな感じでどうでしょうか。GLCanvasをextendsしたクラス内のwakeUpメソッドを 呼び出して、描画することにします。

  public void wakeUp() {
    sDisplay(); // Canvasの再描画
  }

  public void display() {
    clear();
    trnsObj.draw(); // TrnsObjの描画
    swap();
  }

  public void clear() {
    glj.gljMakeCurrent(true);
    gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // 画面のクリア
  }

  public void swap() {
    glj.gljSwap();  // ダブルバッファのスワップ
    glj.gljCheckGL();
    glj.gljFree();
  }
画面の消去を行う、clearメソッド中で、glj.gjlMakeCurrentメソッドで、 バックバッファへの描画の開始を宣言しています。 gl.glClearメソッドでバックバッファをクリアします。 その後、さきほど用意したTrnsObjクラスのdrawメソッドを 使って、物体の描画を行います。 最後にswapメソッドで画面のスワップを行っています。 swapメソッドの最後でglj.gljFreeメソッドを呼び出します。 これを忘れるとちゃんと表示されないので、忘れないようにしましょう。

Q9. 視点の移動はどうするの?

まだよくわかってません。

glu.gluLookAtによって、ある場所から指定された場所を見るように視点を設定することはできます。

Q10. なんか遅いんですけど?

Windowsの場合、Microsoftが提供しているOpenGLドライバを使っている限りあまり性能がでません。 とくに画面のスワップに非常に時間がかかります。

できる限り各ビデオカードのベンタが提供しているOpenGL対応ドライバを使うべきです。 Voodooカードの場合、Mesaのドライバを利用するとうまく動作します。
Rerurn もどる