【コラム】

Java API、使ってますか?

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

48/60

立方体を回転させる

前回はNetBeans OpenGL Packにより生成された雛型を元にJOGL(JSR 231)の基本的な使い方を紹介した。今回はそれを少し発展させて、OpenGLで立方体を描画しボタンのクリックに合わせてそれを回転させるようなプログラムを作ってみたい。

まずはGLEventListenerインタフェースを実装した描画用のクラスを作成する。ここでは"My3DGraphic"という名前でリスト1のようにした。My3DGraphicにはフィールドとしてX方向およびY方向の角度を保持し、それぞれに対するGetter/Setterを用意する。このフィールド値によって立方体の回転量が決まる。

displayメソッドでは座標系を移動/回転した上で、そこに立方体を描画する。座標系の回転はGLクラスのglRotatefメソッドにより行うが、その前にglPushMatrixメソッドで現在の座標系を保存しておく。glRotatefメソッドでは、第1引数に回転させる角度を、第2~第4引数に回転の中心とする軸のx,Y,Z座標を指定する。その後立方体を描画し、最後にglPopMatrixメソッドを用いて座標系を保存しておいたものに戻す。

initメソッド、reshapeメソッド、displayChangedメソッドは前回用いたものと同じなので今回は省略する。

リスト1 My3DGraphic.java - 回転の処理を追加

package apisample;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

public class My3DGraphic implements GLEventListener {
    private int angleX = 0;  // X方向の(Y軸に沿った)角度
    private int angleY= 0;   // Y方向の(X軸に沿った)角度

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

        // 描画領域をクリア
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // カーソルを最初の描画位置に移動
        gl.glLoadIdentity();

        // 現在の座標系を保存
        gl.glPushMatrix();

        // 座標系を移動してX方向およびY方向に回転
        gl.glTranslatef(0.0f, 0.0f, -10.0f);
        gl.glRotatef(this.angleX, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(this.angleY, 1.0f, 0.0f, 0.0f);


        // 立方体の描画
        gl.glBegin(GL.GL_QUADS);
            // 左面
            gl.glColor3f(1.0f, 0.0f, 0.0f);
            gl.glVertex3f(-1.0f, 1.0f, 1.0f);
            gl.glVertex3f(-1.0f, 1.0f, -1.0f);
            gl.glVertex3f(-1.0f, -1.0f, -1.0f);
            gl.glVertex3f(-1.0f, -1.0f, 1.0f);
            // 右面
            gl.glColor3f(0.0f, 1.0f, 0.0f);
            gl.glVertex3f(1.0f,  1.0f, 1.0f);
            gl.glVertex3f(1.0f,  1.0f, -1.0f);
            gl.glVertex3f(1.0f, -1.0f, -1.0f);
            gl.glVertex3f(1.0f, -1.0f, 1.0f);
            // 上面
            gl.glColor3f(0.0f, 0.0f, 1.0f);
            gl.glVertex3f(1.0f, 1.0f, 1.0f);
            gl.glVertex3f(1.0f, 1.0f, -1.0f);
            gl.glVertex3f(-1.0f, 1.0f, -1.0f);
            gl.glVertex3f(-1.0f, 1.0f, 1.0f);
            // 下面
            gl.glColor3f(1.0f, 1.0f, 1.0f);
            gl.glVertex3f(1.0f, -1.0f, 1.0f);
            gl.glVertex3f(1.0f, -1.0f, -1.0f);
            gl.glVertex3f(-1.0f, -1.0f, -1.0f);
            gl.glVertex3f(-1.0f, -1.0f, 1.0f);
        gl.glEnd();

        // 座標系を戻す
        gl.glPopMatrix();

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

        // Getter/Setter
    public int getAngleX() {
        return this.angleX;
    }
    public void setAngleX(int angle) {
        this.angleX = angle;
    }
    public int getAngleY() {
        return this.angleY;
    }
    public void setAngleY(int angle) {
        this.angleY = angle;
    }

    public void init(GLAutoDrawable drawable) {
                // 省略
    }

    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
                // 省略
    }

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

続いて、Swingを利用したGUIプログラムの方を作成する。NetBeans OpenGL Packを使っている場合、MatisseのパレットにGLAutoDrawableインタフェースを実装したGLCanvasとGLJPanelという2つのコンポーネントが追加される。したがって通常のSwingプログラムと同様に、Matisseを用いたレイアウトデザインが可能である。たとえば今回の場合、上下左右に回転させるための各ボタンと、立方体を描画するためのGLCancasを図1のような感じに配置すればよい。

図1 MatisseでGLCanvasを利用できる

プログラムのソースはリスト2のようになる(Matisseにより自動生成されるコードは一部を除き省略)。まずMy3DGraphicのインスタンスを生成し、それをGLCanvasに追加する。ボタンが押された際にはMy3DGraphicのangleXまたはangleYの値を増減させる。

リスト2 JoglSampe2.java - ソース側を修正

apisample package;

import com.sun.opengl.util.Animator;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class JoglSampe2 extends javax.swing.JFrame {
    My3DGraphic myGraphic = new My3DGraphic();  // OpenGLキャンバス

    public JoglSampe2() {
        initComponents();

        // キャンバスにリスナーをセット
        this.canvas.addGLEventListener(this.myGraphic);

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

        // ウィンドウのクローズ処理
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                new Thread(new Runnable() {
                    public void run() {
                        animator.stop();
                        System.exit(0);
                    }
                }).start();
            }
        });

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


    private void upRotateButtonActionPerformed(java.awt.event.ActionEvent evt) {
            this.myGraphic.setAngleY(this.myGraphic.getAngleY() - 5);
    }

    private void rightRotateButtonActionPerformed(java.awt.event.ActionEvent evt) {
            this.myGraphic.setAngleX(this.myGraphic.getAngleX() + 5);
    }

    private void downRotateButtonActionPerformed(java.awt.event.ActionEvent evt) {
            this.myGraphic.setAngleY(this.myGraphic.getAngleY() + 5);
    }

    private void leftRotateButtonActionPerformed(java.awt.event.ActionEvent evt) {
            this.myGraphic.setAngleX(this.myGraphic.getAngleX() - 5);
    }


    // 以下、NetBeansによる自動生成部分

    private void initComponents() { ... }

    public static void main(String args[]) { ... }

    private javax.media.opengl.GLCanvas canvas;
    private javax.swing.JButton downRotateButton;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JButton leftRotateButton;
    private javax.swing.JButton rightRotateButton;
    private javax.swing.JButton upRotateButton;
}

このプログラムを実行すると図2のように表示される。方向ボタンをクリックするとその分だけ立方体が回転する。

図2 ボタンを押した分け立方体が回転する

GLJPanelを使う

次に、図3のように3Dグラフィックの描画領域の中に、Swingによる2Dのボタンを配置してみる。ここではボタンをクリックしたら立方体が左回転/左回転でアニメーションするようなプログラムを考える。

図3 3Dパネル内に2Dのボタンを表示する

まず3Dコンポーネントを描画するMy3DGraphic.javaには、左右の回転のon/off状態を保持するフィールドと、それを制御するメソッドをそれぞれリスト3のように追加しておく。

リスト3 My3DGraphic.java - 回転の状態を保持するフィールドと、on/offを制御するメソッドを追加

    private boolean isRightRotating = false;  // 右回転on/off
    private boolean isLeftRotating = false;   // 左回転on/off

        ......

        // 右回転on
    public void startRightRotate() {
        this.isLeftRotating = false;
        this.isRightRotating = true;
    }
        // 左回転on
    public void startLeftRotate() {
        this.isRightRotating = false;
        this.isLeftRotating = true;
    }
        // 停止
    public void stopRotate() {
        this.isLeftRotating = false;
        this.isRightRotating = false;
    }

また、displayメソッドの先頭に、回転がonの場合に角度を変化させるようリスト4の処理を追加する。

リスト4 My3DGraphic.java - displayメソッドの先頭に回転の処理を追加

        // 回転がonのとき
        if (this.isRightRotating) {
            angleX += 1;
        } else if (this.isLeftRotating) {
            angleX -= 1;
        }

続いてJoglSampe2.javaだが、今回はGLCanvasに代わってGLJPanelクラスを利用する。GLJPaneはjavax.swing.JPanelを継承したクラスだが、GLCanvasと同様にGLAutoDrawableインタフェースをimplementsしているため3Dグラフィックの描画に対応している。NetBeans OpenGL Packを使っている場合はGLCanvasのときと同じようにMatisseを利用してデザインできる。今回は図4のように配置すればよい。

図4 GLJPanelの上にJButtonを配置する

ソースコード側は、まずGLJPanelを利用するようにコンストラクタを修正する (リスト5)。

リスト5 JoglSampe2.java - コンストラクタを修正

        // キャンバスにリスナーをセット
        //this.canvas.addGLEventListener(this.myGraphic);
        // GLパネルにリスナーをセット
        this.glPanel.addGLEventListener(this.myGraphic);

ボタンを押した際のイベント処理部分はリスト2.6のようになる。

リスト6 JoglSampe2.java - ボタンを押したときの処理

    private void startRightRotateActionPerformed(java.awt.event.ActionEvent evt) {
        this.myGraphic.startRightRotate();
   }

    private void startLeftRotateActionPerformed(java.awt.event.ActionEvent evt) {
        this.myGraphic.startLeftRotate();
    }

    private void stopRotateActionPerformed(java.awt.event.ActionEvent evt) {
        this.myGraphic.stopRotate();
    }

これで実行すれば図3のように表示されるはずだ。

まとめ

最初に書いたように、JOGLはその名の通りJavaとOpenAPIのバインディングを定義したAPIであり、メソッド名などはOpenGL APIのものをほぼそのまま引き継いでいるため、基本的な部分さえ理解しておけば残りはOpenGLの知識だけでプログラミングできてしまう。本連載は3Dプログラミングの方法を解説することが本質ではないため、非常に基礎的な部分しか紹介できなかったが、3Dグラフィックが扱えることでアプリケーションの表現の幅が大きく広がるので、ぜひ積極的に使ってみてほしいと思う。

48/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」に登録してください。

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

関連キーワード


人気記事

一覧

イチオシ記事

新着記事