Java 3DGame LWJGL Retry Lv1 〜動かして理解する〜

イントロダクション

LWJGLのGitBookを読み進めChapter8まできましたが、ここからよく解らなくなってしまいました。

原因は、3Dモデル描画(レンダリング)の部分をちゃんと理解していないためです。

なので、Chapter5-2からやり直します。

幸いにも、GitからPULLしてきたファイルがあるのでそいつをカスタムして理解していきます。

余談

EclipseでGitからPULLする場合は、ChapterX("X"には数字)のフォルダをPULLするとプロジェクトが作成されてちょうど良い感じです。

フォルダ(ディレクトリ)の直下に「.project」ファイルがあるとEclipseはそのフォルダを「プロジェクト」として読み込んでくれます。

今回のGitリポジトリは「pom.xml」ファイルがあるのでそれはMevenプロジェクトとして読み込んでくれるようです。

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


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

Chapter5-2で表示

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


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

  ソースで遊ぶ

前回表示したのは、シンプルに四角でした。こいつを以下のようにしてみます。

1.色を色々と変えてみる

色を決めているであろう、ソースコードは下の部分になります。

DummtGame#init()

       // 追記 2018/10/27
        float[] colors = new float[] {
        	    0.5f, 0.0f, 0.0f, // T01
        	    0.0f, 0.5f, 0.0f, // T02
        	    0.0f, 0.0f, 0.5f, // T03
        	    0.0f, 0.5f, 0.5f,}; // T04

これのT01行の値(「0.5f, 0.0f, 0.0f,」)を変更してみます。

「0.0f, 0.0f, 0.0f,」

「0.0f, 0.5f, 0.0f,」

「0.0f, 0.0f, 0.5f,」

どうやら「0.0f」は黒「0.5f」はRGBの3つ並んだうちの色を出すようです。

→「0.0f, 0.0f, 0.0f,」黒、「0.5f, 0.0f, 0.0f,」赤、「0.0f, 0.5f, 0.0f,」緑、「0.0f, 0.0f, 0.5f,」青

逆に1.0fの値は白になるだろうか?

「1.0f(R), 0.0f(G), 0.0f(B),」は左上が白くなるであろうと仮説を立てます。

<実行結果>

明るい赤でした。。。でも上記の配列はRGBの順番でそれぞれの色の強さを示していることがわかりました。

次は二段目、T02行の値(「0.0f, 0.5f, 0.0f,」)を変更してみます。T01の行と同様に値を変えていきます。

「0.5f, 0.0f, 0.0f,」

「0.5f, 0.0f, 0.0f,」

「0.0f, 0.0f, 0.5f,」

ここまでやって、はっきりしました。

 

       // 追記 2018/10/27
        float[] colors = new float[] {
        	    0.5f, 0.0f, 0.0f, // T01:左上(赤)
        	    0.0f, 0.5f, 0.0f, // T02:左下(緑)
        	    0.0f, 0.0f, 0.5f, // T03:右下(青)
        	    0.8f, 0.8f, 0.0f,}; // T04:(黄)

 

こんな感じで、color部分に関しては理解できました。

次回

今度は、positionをいじって遊ぼうと思います。

関連ページ一覧

Java 3DGame LWJGL GitBook chapter5-2〜レンダリング詳細〜

<開発準備>

Java Install Eclipse〜開発ツールのインストール〜

<LWJGLのGitBokに関して>

  1. Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜

<Java Basic>

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 8.5 〜Array〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜


Eclipse アプリ作成 Lv1〜家計簿を作る準備〜

イントロダクション

今までLWJGLを学んできました。これはOpenGLとOpenAL(オーディオ関連ライブラリ)を含んだフレームワークです。本当はまだまだ続きがあります(chapter7/chapter28)

駄菓子菓子!Matrix(行列)が出てきたあたりから解らなくなってきたので、今一度理解するためにアプリを作って理解しようというわけです。

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜
  9. Chapter5-2〜レンダリング詳細〜
  10. Chapter6〜Projection(投影)〜
  11. Chapter7-1〜Cubeを作る〜
  12. Chapter7-2〜Texture〜

家計簿アプリを作る準備

セットアップ

1.まずはMavenプロジェクトを作成します。

2.そして、プロジェクトのセットアップを行います。

今回は、フレームワークとしてLWJGLを使用します。必要なライブラリをMevenで落としてくるのも良いのですが、バージョンが沢山あるので、今使用しているライブラリを使用します。LWJGLのセットアップ

プロジェクトを右クリックして、properties

Build Pathを選択

ライブラリを追加しますので、ライブラリ(Libraries)を開き「Add Library」

そして、「User libraries」をクリック

「New」でUserLibraryを作成します。

「Add External Jar」で外部(Eclipseの外)ライブラリ(JAR)を読み込みます。

今回はLWJGLなのでダウンロードした、頭に「lwjgl」とついているJARファイルを全てパスに繋ぎます。そしてOK。

Javaのバージョンを1.8以上にします。

Project右クリック > Properties > Java Compiler

でJavaのバージョンを1.8以上にします。

トドメに、「Hello World」を実行

とりあえずは、ここまでで一区切りです。

でわでわ。。。

 関連ページ一覧

<開発ツールのインストール>

<プロジェクトの作成(はじめ方)>

<GitからのPULL方法>

<Javaの基本から応用など>

 


Java 3DGame LWJGL GitBook chapter8〜Camera〜

イントロダクション

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

前回は、Chapter7-2をやりました。今回は画面を表示するときの「カメラ」に付いてやります。

ゲームで表示されている領域を変えたり、ズームアップしたりするアレです。

コードを読む(Read Code)

今までに見て来た部分は割愛します。

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜
  9. Chapter5-2〜レンダリング詳細〜
  10. Chapter6〜Projection(投影)〜
  11. Chapter7-1〜Cubeを作る〜
  12. Chapter7-2〜Texture〜

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

今回の追加ソース

  1. MouseInput
  2. Camera

大きな修正部分

  1. Transformation#getWorldMatrix()を修正していました。
  2. DummyGame#init()
  3. Renderer#render()

写経後に起動するアプリ

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


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

改めてソースを読む

Main: DummyGame, GameEngineをインスタンス化してGameEngine#start()を実行

DummyGame: Renderer, Camera, Vector3fをインスタンス化して各フィールドに設定

GameEngine:

  1. スレッドを立ち上げ(new Thread(this))、フィールドにWindow, MounseInput, DummyGameのインスタンスを設定する
  2. OSの種類に応じて、GameEngine#run() or GameEngine#start()を切り替えて実行する
  3. フィールドにセットした各クラスの初期処理(init())を起動する
  4. gameLoopを回しながらinput, renderを繰り返し実行する

大雑把にこんな感じの処理をしていました。

今回のキモ

ズバリ、カメラワークでしょう!そして、因縁の三角関数!!

そして、GitBookの説明を読んでもよくわからなかったので、デバッカーを作って実行

スクリーンショット 2018-10-31 20.38.06.png

入力があったときのみコンソールに出力する様に処理を追加→欠陥品でした。。。1回目しか出力しません。。。

スクリーンショット 2018-10-31 21.47.10.png

出力結果

2018-10-31 21.46.55

とりあえずはここまでやったのだけど、入力した値が逆方向に向いている(-0.05)こと以外はわからなかった次第でございます。

続きはまた後日。

でわでわ。。。

 

Java 3DGame LWJGL GitBook chapter7-2〜Texture〜

イントロダクション

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

前回は、Chapter7-1をやりました。

今回は前回作詞したCubeにテクスチャを貼り付けます。

コードを読む(Read Code)

今までに見て来た部分は割愛します。

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜
  9. Chapter5-2〜レンダリング詳細〜
  10. Chapter6〜Projection(投影)〜
  11. Chapter7-1〜Cubeを作る〜

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

写経前の準備

上のリンクにあるGitBookを読んでみるとMavenでのライブラリ追加に関して記載があります。なのでライブラリの追加(依存関係の追加)を行います。

依存関係の追加(Maven、POMファイル)

上のキャプチャの様にPOMファイルを開きます。

そして、GitBookのページからPOMファイルの記載部分をコピって「ぺっ」ってやります。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  
  <modelVersion>4.0.0modelVersion>
  <groupId>zenryokuservicegroupId>
  <artifactId>gui.mtmartifactId>
  <version>0.0.1-SNAPSHOTversion>
  <packaging>jarpackaging>
  <name>gui.mtmname>
  <url>http://maven.apache.orgurl>
  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
  properties>
  
  <dependencies>
    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>3.8.1version>
      <scope>testscope>
    dependency>
    
    <dependency>
         <groupId>org.jomlgroupId>
         <artifactId>jomlartifactId >
         <version>1.9.6version >
    dependency>
    
    <dependency>
      <groupId>org.l33tlabs.twlgroupId>
      <artifactId>pngdecoderartifactId>
      <version>バージョンを記載version>
    dependency>
  dependencies>
project>

上記の様な感じでPOMファイルができると思いますが、「バージョン」に関しては調べる必要あります。今回追加するのは

PNGDecoder

なのでそのサイトへいきバージョンを調べます。

ちょっとわかりづらいけど「1.0」と記載してありました。

上の様にpom.xmlを右クリック→Maven→Maven installでインストール完了です。

そして実行結果は以下の様になりました。

中身を見る

今回は、前回作成したCube(立方体)にテクスチャを貼り付ける作業になります。

ソースの差分を見るのでなく面倒なのでソースをそのまま読みます。

Main: 変化なし(やってることは変わらない)

DummyGame:Textureクラスを生成、Meshクラスに渡す

Texture texture = new Texture("/textures/grassblock.png");
Mesh mesh = new Mesh(positions, textCoords, indices, texture);

GitBookの説明には以下の様にありました。


次のステップは、テクスチャをグラフィックスカードメモリにアップロードすることです。まず、新しいテクスチャ識別子を作成する必要があります。テクスチャに関連する各操作はその識別子を使用するため、バインドする必要があります。

//新しいOpenGLテクスチャを作成する 
int textureId = glGenTextures ; 
//テクスチャをバインドする
glBindTexture GL_TEXTURE_2D textureId ;

次に、RGBAバイトを解凍する方法をOpenGLに伝える必要があります。各コンポーネントのサイズは1バイトなので、次の行を追加する必要があります。

glPixelStorei GL_UNPACK_ALIGNMENT 1 ; 

最後にテクスチャデータをアップロードすることができます:

glTexImage2D GL_TEXTURE_2D, 0, GL_RGBA,cgetWidth, 
    decoder.getHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf; 

Mesh: TextureのVBOのIDを取得して〜とCubeと同じ処理をする

textCoordsBuffer = MemoryUtil.memAllocFloat(textCoords.length);
textCoordsBuffer.put(textCoords).flip();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, textCoordsBuffer, GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);

※詳細はChapter5-2を参照してください。

Cubeを作成した時と同様に各頂点(V0〜V7)までの点に対して順序を指定します。

<頂点イメージ>

<テクスチャとモデルの関係>

<テクスチャ>

grassblock

テクスチャをCubeの頂点とOpenGLに結びつけてやる。

        // Load Texture file=>Mavenで追加したライブラリのクラス
        PNGDecoder decoder = new PNGDecoder(Texture.class.getResourceAsStream(fileName));

        // Load texture contents into a byte buffer
        ByteBuffer buf = ByteBuffer.allocateDirect(
                4 * decoder.getWidth() * decoder.getHeight());
        decoder.decode(buf, decoder.getWidth() * 4, Format.RGBA);
        buf.flip();

        // Create a new OpenGL texture 
        int textureId = glGenTextures();
        // Bind the texture
        glBindTexture(GL_TEXTURE_2D, textureId);

        // Tell OpenGL how to unpack the RGBA bytes. Each component is 1 byte size
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        // Upload the texture data
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0,
                GL_RGBA, GL_UNSIGNED_BYTE, buf);
        // Generate Mip Map
        glGenerateMipmap(GL_TEXTURE_2D);

Cubeの頂点とテクスチャの頂点をセットした配列を用意して、OpenGLに結びつける(Bind)

        // Create the Mesh
        float[] positions = new float[] {
            // V0
            -0.5f, 0.5f, 0.5f,
            // V1
            -0.5f, -0.5f, 0.5f,
            // V2
            0.5f, -0.5f, 0.5f,
            // V3
            0.5f, 0.5f, 0.5f,
            // V4
            -0.5f, 0.5f, -0.5f,
            // V5
            0.5f, 0.5f, -0.5f,
            // V6
            -0.5f, -0.5f, -0.5f,
            // V7
            0.5f, -0.5f, -0.5f,
            
            // For text coords in top face
            // V8: V4 repeated
            -0.5f, 0.5f, -0.5f,
            // V9: V5 repeated
            0.5f, 0.5f, -0.5f,
            // V10: V0 repeated
            -0.5f, 0.5f, 0.5f,
            // V11: V3 repeated
            0.5f, 0.5f, 0.5f,

            // For text coords in right face
            // V12: V3 repeated
            0.5f, 0.5f, 0.5f,
            // V13: V2 repeated
            0.5f, -0.5f, 0.5f,

            // For text coords in left face
            // V14: V0 repeated
            -0.5f, 0.5f, 0.5f,
            // V15: V1 repeated
            -0.5f, -0.5f, 0.5f,

            // For text coords in bottom face
            // V16: V6 repeated
            -0.5f, -0.5f, -0.5f,
            // V17: V7 repeated
            0.5f, -0.5f, -0.5f,
            // V18: V1 repeated
            -0.5f, -0.5f, 0.5f,
            // V19: V2 repeated
            0.5f, -0.5f, 0.5f,
        };
        float[] textCoords = new float[]{
            0.0f, 0.0f,
            0.0f, 0.5f,
            0.5f, 0.5f,
            0.5f, 0.0f,
            
            0.0f, 0.0f,
            0.5f, 0.0f,
            0.0f, 0.5f,
            0.5f, 0.5f,
            
            // For text coords in top face
            0.0f, 0.5f,
            0.5f, 0.5f,
            0.0f, 1.0f,
            0.5f, 1.0f,

            // For text coords in right face
            0.0f, 0.0f,
            0.0f, 0.5f,

            // For text coords in left face
            0.5f, 0.0f,
            0.5f, 0.5f,

            // For text coords in bottom face
            0.5f, 0.0f,
            1.0f, 0.0f,
            0.5f, 0.5f,
            1.0f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            8, 10, 11, 9, 8, 11,
            // Right face
            12, 13, 7, 5, 12, 7,
            // Left face
            14, 15, 6, 4, 14, 6,
            // Bottom face
            16, 18, 19, 17, 16, 19,
            // Back face
            4, 6, 7, 5, 4, 7,};

テクスチャをアクティブにする(と思う)

        // Activate firs texture bank
        glActiveTexture(GL_TEXTURE0);

他のクラスは変わりなし。。。多分(実行結果からその様に予測。。。)

まとめ

大まかな流れが読めて来ました。テクスチャもCubeなど3DモデルもOpenGLに頂点座標を渡して描画する様です。

  1. 必要な頂点座標(配列)を用意する
  2. 各頂点をOpenGLにバインド(結びつける)
  3. 描画用に使用する値を「シェーダプログラム」に渡す
    1.         // Create uniforms for world and projection matrices and texture
              shaderProgram.createUniform("projectionMatrix");
              shaderProgram.createUniform("worldMatrix");
              shaderProgram.createUniform("texture_sampler");
  4. 描画

の様な順序で処理していました。実際に触って見るのが良いと思います。

Gitにソースアップしています。(上のリンクからもダウンロードできます。)わかりやすい方でどうぞ。

追伸:自分の写経したソースは、resourcesフォルダにfs, vsファイルがあるのでそちらもダウンロードされたし。。。。

次のChapterが楽しみです。

でわでわ。。。



Java 3DGame LWJGL GitBook chapter6〜Projection(投影)〜

イントロダクション

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

前回は、Chapter5-2をやりました。

Introduction

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

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

コードを読む(Read Code)

今までに見て来た部分は割愛します。

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜
  9. Chapter5-2〜レンダリング詳細〜

今回は、いきなりコードではなくドキュメントから読んでいきます。ちょっと難しくなって来ました。

今までと同様に、プロジェクトのコードを起動します。

スクリーンショット 2018-10-28 13.46.42.png

こんな色の四角を描画します(プログラムが)。この描画はChapter5-2でやりました。

次です。

このチャプターの目玉機能「Transformation」です。どうやら以下の様なイメージで動かすことの様です。

そして、上の様な操作を行うためのクラスを作成します。その名も

Transformationクラス

package zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter6.engine.graph;

import org.joml.Matrix4f;
import org.joml.Vector3f;

public class Transformation {
	private final Matrix4f projectionMatrix;
	private final Matrix4f worldMatrix;

	public Transformation() {
		projectionMatrix = new Matrix4f();
		worldMatrix = new Matrix4f();
	}

	public final Matrix4f getProjectionMatrix(float fov, float wid, float hei, float zNear, float zFar) {
		float aspectRatio = wid / hei;
		projectionMatrix.identity();
		projectionMatrix.perspective(fov, aspectRatio, zNear, zFar);
		return projectionMatrix;
	}

	public Matrix4f getWorldMatrix(Vector3f offset, Vector3f rotation, float scale) {
		worldMatrix.identity().translate(offset)
			.rotateX((float) Math.toRadians(rotation.x))
			.rotateY((float) Math.toRadians(rotation.y))
			.rotateZ((float) Math.toRadians(rotation.z))
			.scale(scale);
		return worldMatrix;
	}
}

写経して見て「ああ、なるほど」と思うことは各クラスの繋がりとか役割に関して頭の中でイメージが描けることです。メソッドとか気がついたら覚えているしね(笑)。

結果

スクリーンショット 2018-10-28 21.42.59.png

初めの表示とかわりませんでした。。。

けど、追加で作成したTrasformationクラスを使用してprojectionMatrix, worldMatrixの使い方が少しわかった様な気がします。ShaderProgramに関しても少しずつわかって来た様な気がします。

今回の実装では。GameItemを追加してから表示するためのデータセットのコードが参照したページにはありませんでしたので、自分で考えて実装しました。

DummyGame#init()に処理を追加してやりました。
結局のところ、画面の描画部分には何も変化がなかったのですが、3Dモデルを作成してからモデルを回転したりするときに使用するロジックの様です。でわまた次回。。。








 

Java 3DGame LWJGL GitBook chapter5-2〜レンダリング詳細〜

イントロダクション

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

前回は、Chapter5-1をやりました。

Introduction

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

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

コードを読む(Read Code)

今までに見て来た部分は割愛します。

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜

今回のポイント

Renderer#render()

    public void render(Window window, Mesh mesh) {
        clear();

        if (window.isResized()) {
            glViewport(0, 0, window.getWidth(), window.getHeight());
            window.setResized(false);
        }

        shaderProgram.bind();

        // Draw the mesh
        glBindVertexArray(mesh.getVaoId());
        glEnableVertexAttribArray(0);
        glDrawElements(GL_TRIANGLES, mesh.getVertexCount(), GL_UNSIGNED_INT, 0);

        // Restore state
        glDisableVertexAttribArray(0);
        glBindVertexArray(0);

        shaderProgram.unbind();
    }

LWJGL(OpenGL)での廟は3角形をベースに描いている様だ。

上のコードで赤字にしている部分は参考にしたドキュメントで「重要です」と記載している部分です。説明内容からして以下の部分で指定しているのは3角形を描くための点を指定している様です。→だから4つ(3個で1セット)指定しているんですね〜

     float[] positions = new float[]{
            -0.5f, 0.5f, 0.0f, /* V1 */
            -0.5f, -0.5f, 0.0f,/* V2 */
            0.5f, -0.5f, 0.0f, /* V3 */
            0.5f, 0.5f, 0.0f,};// V4
        int[] indices = new int[]{
            0, 1, 3, 3, 1, 2,};
        mesh = new Mesh(positions, indices);

上の画像を使って考えて見ます。下の表はindicesに設定した値とV1〜V4の関係を示します。

V1

V2

V3

V4

0

1

2

3

そして、下の表はindicesの意味を示します。左半分が上の図はオレンンジ色の三角形にあたり緑色が右半分の三角形です。

0

1

3

3

1

2

V1

V2

V4

V4

V2

V3

自分で描いていて、複雑ですがなるほどなぁ〜と思いますね。

そしてGitBookにはここで色を変更する手段について来さしています。

Meshクラスのコンストラクタの内容に以下の処理を追記します。3つのファイルを修正します。

  1. Meshクラス
  2. vertex,vs
  3. fragment.fs

Meshクラスのコンストラクタ

    public Mesh(float[] positions, int[] indices, float[] colors) {
        FloatBuffer posBuffer = null;
        IntBuffer indicesBuffer = null;
        try {
            vertexCount = indices.length;

            vaoId = glGenVertexArrays();
            glBindVertexArray(vaoId);

            // Position VBO
            posVboId = glGenBuffers();
            posBuffer = MemoryUtil.memAllocFloat(positions.length);
            posBuffer.put(positions).flip();
            glBindBuffer(GL_ARRAY_BUFFER, posVboId);
            glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
            glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

            // Index VBO
            idxVboId = glGenBuffers();
            indicesBuffer = MemoryUtil.memAllocInt(indices.length);
            indicesBuffer.put(indices).flip();
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxVboId);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
            
            // Color VBO この部分を追記する 2018/10/27
            final int colourVboId = glGenBuffers();
            FloatBuffer colourBuffer = MemoryUtil.memAllocFloat(positions.length);
            colourBuffer.put(colors).flip();
            glBindBuffer(GL_ARRAY_BUFFER, colourVboId);
            glBufferData(GL_ARRAY_BUFFER, colourBuffer, GL_STATIC_DRAW);
            MemoryUtil.memFree(colourBuffer);
            glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);
            // 追記部分ここまで
            glBindBuffer(GL_ARRAY_BUFFER, 0);
            glBindVertexArray(0);
        } finally {
            if (posBuffer != null) {
                MemoryUtil.memFree(posBuffer);
            }
            if (indicesBuffer != null) {
                MemoryUtil.memFree(indicesBuffer);
            }
        }

vertex.vs

#version 330

layout (location =0) in vec3 position;

// 追記 2018/10/27
layout(location=1) in vec3 inColour;
out vec3 exColour;

void main()
{
	gl_Position = vec4(position, 1.0);
	// 追記 2018/10/27
	exColour = inColour;
}

fragment.fs

#version 330

// 追記 2018/10/27
in  vec3 exColour;
out vec4 fragColor;

void main()
{
	fragColor = vec4(exColour, 1.0);
}

 

つまづいたところ

下のコードを追記する部分よりも上に記述していたため、バインドを解放した後にcolourBufferを作成したりしても四角(クアッド)には関連図かない(反映されない)事に気がつかず。。。まぁ数時間(笑)

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

 

まとめ

描画するときに与える頂点座標は3角形をベースにする(3個1セット)、そして三角形をくっつけている様なとき(四角形など)の時は重複する点ができるのでそれをindices配列で順序付けをする。

VAOとVBOのバインド、アンバインドに注意する必要がある。。。

ガッテン! x 3

関連ページ一覧

<再度学習するのにやったこと>

  1. Eclipse アプリ作成 Lv1〜家計簿を作る準備〜
  2. Eclipse アプリ作成 Lv2〜家計簿を作る土台作り〜
  3. Eclipse アプリ作成 Lv3〜3Dグラフ用Cube作り〜

<Java Basic>

  1. Java Basic for文 〜Step1_3_1〜
  2. Java Basic Level8 〜How to use for statement〜
  3. Java Basic Level 9〜Training of for statement〜
  4. Java 3DGame LWJGL GitBook chapter7-1〜Cube作成〜「動画あり」

<サイトマップ>

Java 3DGame LWJGL GitBook chapter5-1〜レンダリングについて〜

イントロダクション

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

前回は、Chapter4をやりました。

Introduction

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

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

レンダリング

ついに来ました、今回初めからLWJGLを学ぶことにした理由の部分です。→3D描画方法がわからなかったんですね。。。

プログラム起動準備

使用しているクラス(ファイル)は名前が同じですが、差分があるはずなのでそれを確認します。Eclipseにはファイルマージ機能があるのでそれを使用します。

  1. 比較するファイル(フォルダ)を選択する
  2. 右クリックして「Compare」を選択する

スクリーンショット 2018-10-27 13.17.37.png

こんな感じで表示されますのでそれを比較して差分を無くします(マージします)。

スクリーンショット 2018-10-27 13.20.28.png

マージしてクラスを自分のプロジェクト内に配置しました。パッケージ名を修正するだけでした。

スクリーンショット 2018-10-27 13.30.06.png

そして実行

スクリーンショット 2018-10-27 13.32.43.png

今回は四角を描画する様です。一応、Chapter2でやった十字キーで色が変わる機能もついています。Chapter3,4もついてます。コードいじってないので(笑)

スクリーンショット 2018-10-27 13.33.33.png

コードを読む(Read Code)

今までに見て来た部分は割愛します。

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜

Meshクラスを作成して描画する

Chapter4に比べて追加になったMeshクラスから見ていきます。結論から言うとMeshクラスで細かい描画部分をまとめてしまう様にソースを修正した様です。

import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import org.lwjgl.system.MemoryUtil;

public class Mesh {

    private final int vaoId;

    private final int posVboId;

    private final int idxVboId;

    private final int vertexCount;

    public Mesh(float[] positions, int[] indices) {
        /* Chapter3、4では描画する準備でやったことです */
        FloatBuffer posBuffer = null;
        IntBuffer indicesBuffer = null;
        try {
            vertexCount = indices.length;

            vaoId = glGenVertexArrays();
            glBindVertexArray(vaoId);

            // Position VBO
            posVboId = glGenBuffers();
            posBuffer = MemoryUtil.memAllocFloat(positions.length);
            posBuffer.put(positions).flip();
            glBindBuffer(GL_ARRAY_BUFFER, posVboId);
            glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
            glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

            // Index VBO
            idxVboId = glGenBuffers();
            indicesBuffer = MemoryUtil.memAllocInt(indices.length);
            indicesBuffer.put(indices).flip();
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxVboId);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);

            glBindBuffer(GL_ARRAY_BUFFER, 0);
            glBindVertexArray(0);
        } finally {
            if (posBuffer != null) {
                MemoryUtil.memFree(posBuffer);
            }
            if (indicesBuffer != null) {
                MemoryUtil.memFree(indicesBuffer);
            }
        }
    }

    public int getVaoId() {
        return vaoId;
    }

    public int getVertexCount() {
        return vertexCount;
    }

    public void cleanUp() {
        glDisableVertexAttribArray(0);

        // Delete the VBOs
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDeleteBuffers(posVboId);
        glDeleteBuffers(idxVboId);

        // Delete the VAO
        glBindVertexArray(0);
        glDeleteVertexArrays(vaoId);
    }
}

ポイント

DummyGameクラスのfloat配列が3行ではなく4行になっているところ

        float[] positions = new float[]{
            -0.5f, 0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
            0.5f, 0.5f, 0.0f,};
        int[] indices = new int[]{
            0, 1, 3, 3, 1, 2,};
        mesh = new Mesh(positions, indices);

Meshクラスで描画部分をまとめたのでgl〜のメソッドが消えている

スクリーンショット 2018-10-27 14.13.17.png

glDrawElementでVertexの数を指定しているところが三角形と四角形の違いなのか?

ちょっと遊んでみる

今回の「遊んでみるポイント」は下の行です。

    @Override
    public void init() throws Exception {
        renderer.init();
        float[] positions = new float[]{
            -0.5f, 0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
            0.5f, 0.5f, 0.0f,};
        int[] indices = new int[]{
            0, 1, 3, 3, 1, 2,};
        mesh = new Mesh(positions, indices);
    }

今回はここまでにしておきます。

 

 

Java 3DGame LWJGL GitBook chapter3〜プロジェクトの起動エラー〜

トラブルシューティング

この記事は、chapter3を始めるにあたり画面の起動でエラーが出てしまった時のメモとして記載します。

エラーになった原因(自分のケース) Cause getting Error in Chapter3

出力したエラーログ

java.lang.NullPointerException: source
	at java.util.Objects.requireNonNull(Objects.java:228)
	at java.util.Scanner.(Scanner.java:578)
	at zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter4.engine.Utils.loadResource(Utils.java:11)
	at zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter4.game.Renderer.init(Renderer.java:26)
	at zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter4.game.DummyGame.init(DummyGame.java:22)
	at zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter4.engine.GameEngine.init(GameEngine.java:50)
	at zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter4.engine.GameEngine.run(GameEngine.java:38)
	at java.lang.Thread.run(Thread.java:748)
	at zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter4.engine.GameEngine.start(GameEngine.java:29)
	at zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter4.game.Main.main(Main.java:13)

上の様なエラーログが出力された場合です。これは上の赤字の部分から追いかけると原因がわかります。

対象のコード(赤い字)

    public static String loadResource(String fileName) throws Exception {
        String result;
        try (InputStream in = Class.forName(Utils.class.getName()).getResourceAsStream(fileName);
                Scanner scanner = new Scanner(in, "UTF-8")) {
            result = scanner.useDelimiter("\\A").next();
        }
        return result;
    }

上記の赤い部分がエラーの出ている行になります。コードを追いかけてみると「in」をScannerで読み取るための準備(Scannerをインスタンス化)をしているところでエラーが起きていますので、「in」「"UTF-8"」が怪しいと睨みます。「"UTF-8」は固定値(定数)なので犯人ではなさそうです。

次に、「in」を追跡します。「in」はInputStream=>ClassクラスのメソッドgetResourceAsStreamを呼び出しているのでそいつを調べます。

引数にある「リソース(ファイル)」を取得するメソッドですので返却する値はInputStreamです。

※ここら辺について記載した記事はこちらです。

 

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に記載があり、シェーダが関係している様です。

続きは次回