Java 3DGame LWJGL GitBook chapter3〜LWJGLを学習する3〜

イントロダクション

LWJGL GitBookChapterを写経しながら理解していきます。Git(ソース)はこちら。。。

前回は、Chapter2(4)をやりました。ようやくChapter3に入ることができます。

と言うわけでChapter3の始まりです。(GitのソースはChapter4になっていました(笑))

Chapter3は説明のみだったので飛ばしています。

Introduction

LWJGL We will understand GitBook ‘s chapter while shooting. Git (source) is here. . . Last time I did Chapter 2(4) so We will do Chapter 3 this time. Let's get sarted!.

https://ahbejarano.gitbook.io/lwjglgamedev/chapter3

トラブルシューティング(Trouble shooting)

Chapter3の目玉

今回から描画処理が入ってきます。まずは3角形の描画です。

<実行結果>

そして、今回のChapter3ですがChapter2の続きなので追加されているクラスを見ていくことにします。

  1. DummyGame
  2. Renderer
  3. GameEngine
  4. IGameLogic
  5. Timer
  6. Window

今回追加になったクラス

  1. Utils
  2. ShaderProgram

まずはUtilクラスから見ていきます。あと起動するときには「resources」フォルダをビルドパスに繋げる必要があります。

Utilクラス

このクラスが呼ばれている場所を探します。目で追いかけると時間がかかるのでEclipseの機能を使用します。

Utilクラスを開いてメソッドにカーソルを合わせます。下のような感じです。

カーソルを合わせたら右クリック->Reference->Projectを選択します。すると下の部分に参照しているクラスが表示されます。

そして、Rendererクラスを開きます。

    public void init() throws Exception {
        shaderProgram = new ShaderProgram();
        shaderProgram.createVertexShader(Utils.loadResource("/vertex.vs"));
        shaderProgram.createFragmentShader(Utils.loadResource("/fragment.fs"));
        shaderProgram.link();

        float[] vertices = new float[]{
            0.0f, 0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f
        };

        FloatBuffer verticesBuffer = null;
        try {
            verticesBuffer = MemoryUtil.memAllocFloat(vertices.length);
            verticesBuffer.put(vertices).flip();

            // Create the VAO and bind to it
            vaoId = glGenVertexArrays();
            glBindVertexArray(vaoId);

            // Create the VBO and bint to it
            vboId = glGenBuffers();
            glBindBuffer(GL_ARRAY_BUFFER, vboId);
            glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
            // Define structure of the data
            glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

            // Unbind the VBO
            glBindBuffer(GL_ARRAY_BUFFER, 0);

            // Unbind the VAO
            glBindVertexArray(0);
        } finally {
            if (verticesBuffer != null) {
                MemoryUtil.memFree(verticesBuffer);
            }
        }
    }

Chapter2に比べてinit()のコード量が増えています。今回追加の「ShaderProgram」クラスを生成(インスタンス化)してフィールドに設定(セット)して(メソッドの名前から予測して)VertexシェーダとFragmentシェーダを作成してます。

そして、点を示す(verticies)配列を初期化しています。それ以降の部分については今はわかりません。とりあえず見ていきます。わからないものは調べレバ良い(笑)

※LWJGLのAPIに関してはOpenGLなどの理解が必要なのでわかるところから攻める。。。つまりJavaSE(StanderdEdition)APIから攻める!JavaDocを見てもわからなかったら、調べる→動かす→一部理解する→調べる。。。。と無限ループする。

最終奥義は「人に聞く(教えてもらう)」

これが一番早い(笑)

「聞くは一時の恥、聞かぬは末代までの恥」と言いますからね。信頼できる仲間を作る様にしましょう。→作らなかったので今苦労しています。。。。

        shaderProgram = new ShaderProgram();
        shaderProgram.createVertexShader(Utils.loadResource("/vertex.vs"));
        shaderProgram.createFragmentShader(Utils.loadResource("/fragment.fs"));
        shaderProgram.link();

        float[] vertices = new float[]{            0.0f, 0.5f, 0.0f,            -0.5f, -0.5f, 0.0f,            0.5f, -0.5f, 0.0f        };
        /* ここからがわからない部分 */
        FloatBuffer verticesBuffer = null;
        try {
            verticesBuffer = MemoryUtil.memAllocFloat(vertices.length);
            verticesBuffer.put(vertices).flip();

            // Create the VAO and bind to it
            vaoId = glGenVertexArrays();
            glBindVertexArray(vaoId);

            // Create the VBO and bint to it
            vboId = glGenBuffers();
            glBindBuffer(GL_ARRAY_BUFFER, vboId);
            glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
            // Define structure of the data
            glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

            // Unbind the VBO
            glBindBuffer(GL_ARRAY_BUFFER, 0);

            // Unbind the VAO
            glBindVertexArray(0);
        } finally {
            if (verticesBuffer != null) {
                MemoryUtil.memFree(verticesBuffer);
            }
        }

ちなみに、参照したJavaDocAPIのFloatBufferの「flip()」は親クラス「Buffer」クラスにいます。そして調べた結果「flip()」は書き込みの準備処理を行う様です。

つまり、わからなかった以下の処理は、float配列から取得したFloatBufferに初期化したfloat配列を設定(セット)して書き込みの準備を行う処理と言うことになります。

// float配列の長さからFloatBufferを取得する
verticesBuffer = MemoryUtil.memAllocFloat(vertices.length);
// 取得したFloatBufferにfloat配列をセットして書き込みの準備
verticesBuffer.put(vertices).flip();

そのあとは、コメントを信じて読み飛ばします(笑)。

実行結果が以下の様に表示するものなので少しいじって見ます。


*************************************


*************************************

サンプルソースで遊ぶ

上のソースで赤字になっているところを修正して起動して見ます。

        float[] vertices = new float[]{
            0.5f, 0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f
        };

同じく赤字の部分を「0.0f」から「0.5f」へ修正して起動した結果です。

三角形の頂点が移動した様に見えます。

今度は以下の様に変更しました。

 float[] vertices = new float[]{
            0.0f, 0.0f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f
        };

次は隣を0.5fに変更

 float[] vertices = new float[]{
            0.0f, 0.5f, 0.5f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f
        };

初めのものと変化がない。。。今回の表示は2Dだから左から3番目の値は無視される?(仮説を立てて見ます)

        float[] vertices = new float[]{
            0.0f, 0.5f, 0.5f,
            -0.5f, -0.5f, 0.3f,
            0.5f, -0.5f, 0.7f
        };

想定通り、細かい違いはあるかもしれないが上の赤字の部分は無視される様だ。。。

あと知りたいことは、真ん中の座標(値)が知りたい。。。

        float[] vertices = new float[]{
            0.0f, 0.0f, 0.5f,
            -0.0f, -0.0f, 0.3f,
            0.0f, -0.0f, 0.7f
        };

こうすると全てが中点を指定するので何も描画されない。。。なるほど。。。

こうするとどうなる?

        float[] vertices = new float[]{
            0.5f, 0.8f, 0.5f,
            -0.5f, 0.8f, 0.3f,
            0.0f, -0.0f, 0.7f
        };

ふむふむ。。。どうやら真ん中の座標が0.0f, 0.0f, X.Xfになる様だ。

では四角形はいけるのかな?

        float[] vertices = new float[]{
            0.5f, 0.8f, 0.5f,
            -0.5f, 0.8f, 0.3f,
            -0.5f, 0.0f, 0.7f,
            0.5f, 0.0f, 0.7f
        };

赤字の部分を追加しました。

なかなか想定通りには行かない様です。その原因についてはGitBookに記載があり、シェーダが関係している様です。

続きは次回