【コラム】

Java API、使ってますか?

47 JOGLで3Dプログラミング その3

47/60

JOGLを使ったプログラミングの基礎

前回はNetBeans OpenGL Packを使ってJOGLを使うプログラムの雛型(リスト1 JoglSample.java)を作るところまでを行った。今回はその中身を見ながら、JOGLプログラミングの基本となる部分を紹介していきたい。

リスト1 JoglSample.javaの概観

package apisample;

import com.sun.opengl.util.Animator;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

public class JoglSample implements GLEventListener {
    public static void main(String[] args) { ... }

    public void init(GLAutoDrawable drawable) { ... }

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { ... }

    public void display(GLAutoDrawable drawable) { ... }

    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { ... }
}

JSR-231ではOpenGLのレンダリング対象としてGLDrawableというインタフェースを、コンテキストとしてGLContextというインタフェースを定義している。また、GLDrawableを継承した上でイベントドリブンのメカニズムを持ったインタフェースにGLAutoDrawableがある。GLEventListenerの各メソッドにはこのGLAutoDrawableオブジェクトがイベントとして渡される。

initメソッドで初期化処理

JoglSampleのinitメソッドでは、このGLAutoDrawableからgetGLメソッドを用いてGLオブジェクトを取得している(リスト2)。GLインタフェースはOpenGLの各機能にアクセスするための基本となるインタフェースで、OpenGL APIの関数に対応したメソッドが大量に定義されている。ここではOpenGLのglClearColor関数にあたるglClearColorメソッドで描画領域のクリアを、glShadeModel関数にあたるglShadeModelメソッドでシェーディングモードをスムースシェーディング (GL_SMOOTH) に設定している。

リスト2 JoglSample.init() - 初期化処理

    public void init(GLAutoDrawable drawable) {
        // Use debug pipeline
        // drawable.setGL(new DebugGL(drawable.getGL()));

        GL gl = drawable.getGL();
        System.err.println("INIT GL IS: " + gl.getClass().getName());

        // Enable VSync
        gl.setSwapInterval(1);

        // 描画領域とシェーディングの設定
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glShadeModel(GL.GL_SMOOTH);
    }

reshapeメソッドで描画領域を設定

続いてreshapeメソッドを見てみよう。reshapeメソッドでは描画領域の範囲や投影手法、ビューポートなどを設定する。ここでは最初のglMatrixModeメソッドにGL.GL_PROJECTIONを渡すことで投影に関する行列を指定し、glLoadIdentityメソッドで恒等行列をロードしている。

次のGLUクラスはOpenGL Utility Library(GLU)の機能にアクセスするためのクラスである。gluPerspectiveメソッドは透視投影法の視体積を設定するメソッドで、画面の幅と高さ(第1、第2引数)、前面までの距離(第3引数)、一番奥面までの距離(第4引数)を指定する。

2つ目のglMatrixModeメソッドではGL.GL_MODELVIEWを渡すことでモデルビューの行列を指定し、glLoadIdentityメソッドで恒等行列をロードしている。

リスト3 JoglSample.reshape() - 表示領域が変更された際の処理

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        GL gl = drawable.getGL();
        GLU glu = new GLU();

        if (height <= 0) { // avoid a divide by zero error!
            height = 1;
        }
        final float h = (float) width / (float) height;

    // ビューポートを設定
        gl.glViewport(0, 0, width, height);

    // 投影の行列を指定し、描画範囲を設定
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, h, 1.0, 20.0);

    // モデルビューの行列を指定
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

図形の描画はdisplayメソッドで

実際の図形の描画処理はdisplayメソッドに記述する。基本的にはGLインスタンスに対してOpenGL APIの関数と同名のメソッドを呼び出せばよい。NetBeans OpenGL Packのテンプレートでは、リスト1.3.1のように、あらかじめ三角と四角の2次元図形を描くプログラムが記述されている。まずglTranslatefメソッドでカーソルを初期位置に移動し、glBeginで図形の種類を指定して描画を開始、glColor3fとglVertex3fで色と頂点座標を指定して、glEndで描画を完了するといった具合だ。最後にglFlushメソッドを呼び出してすべての図形の描画を終了する。

なお、JSR 231仕様には載っていないが、JOGLにはGLUT (The OpenGL Utility Toolkit) の実装も用意されているため、これを利用すればより簡単に2Dおよび3Dの図形を作ることが可能だ。

リスト4 JoglSample.display() - 描画処理

    public void display(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();

        // 描画領域をクリア
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // 単位行列をロードして行列をリセット
        gl.glLoadIdentity();

        // カーソルを最初の描画位置に移動
        gl.glTranslatef(-1.5f, 0.0f, -6.0f);

        // 三角形を描画を開始
        gl.glBegin(GL.GL_TRIANGLES);
            gl.glColor3f(1.0f, 0.0f, 0.0f);    // 色を赤に設定
            gl.glVertex3f(0.0f, 1.0f, 0.0f);   // 上の頂点
            gl.glColor3f(0.0f, 1.0f, 0.0f);    // 色を緑に設定
            gl.glVertex3f(-1.0f, -1.0f, 0.0f); // 左下の頂点
            gl.glColor3f(0.0f, 0.0f, 1.0f);    // 色を青に設定
            gl.glVertex3f(1.0f, -1.0f, 0.0f);  // 右下の頂点
        // 三角形の描画を終了
        gl.glEnd();

        // カーソルを別の描画位置に移動
        gl.glTranslatef(3.0f, 0.0f, 0.0f);

        // 正方形を描画を開始
        gl.glBegin(GL.GL_QUADS);
            gl.glColor3f(0.5f, 0.5f, 1.0f);    // 色を青に設定
            gl.glVertex3f(-1.0f, 1.0f, 0.0f);  // 左上の頂点
            gl.glVertex3f(1.0f, 1.0f, 0.0f);   // 右上の頂点
            gl.glVertex3f(1.0f, -1.0f, 0.0f);  // 右下の頂点
            gl.glVertex3f(-1.0f, -1.0f, 0.0f); // 左下の頂点
        // 正方形の描画を終了
        gl.glEnd();

        // 全ての描画を終了
        gl.glFlush();
    }

diyplayChangedメソッドはGLAutoDrawableの表示モードや表示デバイスが変更された場合に呼び出されるメソッドだが、今回は必要がないので空白のままになっている。

GLCanvasクラスを使ってSwingプログラムに統合

最後にmainメソッドを見てみよう。GLCanvasというのはGLAutoDrawableインタフェースをimplementsしており、かつjava.awt.Canvasクラスを継承したクラスである。すなわち、OpenGLによる3D図形を描画する機能を持ったAWTコンポーネントということになる。GLCanvasに図形を描画するには、GLEventListenerオブジェクトをaddGLEventListenerメソッドを用いてセットすればよい。つまり今回の例の場合はJoglSampleクラスのインスタンスそのものである。

Animatorクラスはアニメーション機能をサポートするためもの。通常displayメソッドは一度しか呼び出されないが、GLAutoDrawableインスタンスを渡してAnimatorを生成し、startメソッドを呼び出すことで、displayメソッドが周期的に呼ばれるようになる。ウィンドウのクローズ処理では、プログラムを終了する前にアニメーションを正常に停止させるため、Animatorのstopメソッドを呼び出している。

リスト5 JoglSample.main() - 起動時の処理

    public static void main(String[] args) {
        Frame frame = new Frame("Simple JOGL Application");
        // OpenGL用のキャンバスを生成し、リスナーをセット
        GLCanvas canvas = new GLCanvas();
        canvas.addGLEventListener(new JoglSample());

        frame.add(canvas);
        frame.setSize(640, 480);

        // Animatorを生成
        final Animator animator = new Animator(canvas);

        // ウィンドウのクローズ処理
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                // Run this on another thread than the AWT event queue to
                // make sure the call to Animator.stop() completes before
                // exiting
                new Thread(new Runnable() {
                    public void run() {
                        animator.stop();
                        System.exit(0);
                    }
                }).start();
            }
        });

        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        // アニメーションをスタート
        animator.start();
    }

このプログラムを実行すると図1のように表示される。

図1 JoglSample.javaの実行結果

47/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。

関連キーワード


人気記事

一覧

イチオシ記事

新着記事