Eclipse アプリ作成 Lv7〜Cubeを日付順に並べる〜

イントロダクション

ここ数日の戦いを経て、ようやく先に進めます。※下は戦闘履歴です。

  1. Eclipse アプリ作成 Lv5〜惨敗:CubeにTextureを貼る〜「惨敗」
  2. Java 3DGame LWJGL Retry Lv3 Texture〜動かして理解する3〜「負け越し」
  3. Java 3DGame LWJGL Retry Lv4 デバック〜動かして理解する4〜「黒星」
  4. Java 3DGame LWJGL Retry Lv5 遊んでみる〜動かして理解する5〜「引分け」
  5. Java 3DGame LWJGL Retry Lv6 遊んでみる2〜動かして理解する6〜「白星」

家計簿作成を再開しようと思いますが、その前に戦果の方を見ていただきたく思います。

<現在>

家計簿のためのカレンダー部分が完成しました。

現状では、まだまだわかりづらいのは否めません。。。

しかし、初めに比べれば。。。

<作成当初>

家計簿作成再始動

今回はよりカレンダーらしくするために、カレンダークラスを使用してカレンダーの様にCubeを配置する様にプログラムを変更します。

まずはカレンダー作成

Javaの基本的なクラス(java.util.Calendar)を使用します。作成するクラスは「CalendarPosit」クラスです。

<要件の整理:どんな機能を持たせるか考える>

Cubeを使ってカレンダーを作成しますので。以下の要件を満たす必要があります。→プログラム設計になります。

  1. 対象月の月初の曜日を取得する
  2. 今月の最大日数を取得する
  3. Calendarクラスから取得した曜日が何曜日か判定する
  4. 日曜始まりをデフォルトとして、月曜始まりの場合でも曜日の値(Calendar.DAY_OF_WEEK)を返却する(配列の位置)

実行結果:木のCubeも移動しています

<月曜始まり>の実行結果(isStartMon=true)

<日曜始まり>の実行結果(isStartMon=false)


実装内容:ソースはこちら(Gitでみる)

isStartMonのハンドルを行なっているクラス(DummyGame#init())のソース(2018/11/10現在)

    //// 参照しているフィールド変数(抜粋) ////
    /**
     *  曜日の表示順
     *  true: 月曜始まり false: 日曜始まり
     */
    private boolean isStartMon;
    private static final String[] WEEK_TEXTURE_SUN = new String[]{"Sun", "Mon", "Tue", "Wed", "Thi", "Fri", "Sat"};

    @Override
    public void init(Window window) throws Exception {
        renderer.init(window);
        isStartMon = true;// 月曜始まり、日曜始まりは「false」
        CalendarPosit pos = new CalendarPosit();
        // 月初の曜日
        int firstDayOfWeek = pos.getStartPoint(isStartMon);
        // 今月の最大日数
        int maxDayOfMonth = pos.getMaxDayOfMonth();
        // Cubeの高さ
        ArrayList<float[]> floats = new ArrayList<>();
        floats.add(new float[] {0.0001f, 0.12f, 0.3f, 0.001f, 0.1f, 0.25f, 0.1f});
        floats.add(new float[] {0.15f, 0.19f, 0.23f, 0.2f, 0.08f, 0.13f, 0.12f});
        floats.add(new float[] {0.1f, 0.2f, 0.4f, 0.001f, 0.2f, 0.05f, 0.15f});
        floats.add(new float[] {0.11f, 0.12f, 0.3f, 0.001f, 0.1f, 0.25f, 0.1f});
        floats.add(new float[] {0.12f, 0.13f, 0.14f, 0.015f, 0.16f, 0.17f, 0.18f});
        floats.add(new float[] {0.12f, 0.13f, 0.14f, 0.015f, 0.16f, 0.17f, 0.18f});

        // Cubeの底面のサイズ(正方形)
        final float cubeSize = 0.1f;
        // x軸の初期値
        final float xInit = -0.5f;
        // y軸の初期値
        final float yInit = -0.8f;
        // z軸の初期値
        final float zInit = -2;
        // x軸の増減幅
        final float xWidth = 0.185f;
        // y軸の増減幅
        final float yWidth = 0.033f;
        // z軸の増減幅
        final float zWidth = 0.1f;
        ArrayList arr = new ArrayList();
        
        // マスのカウント
        int box = 0;
        // 日数
        int day = 0;
        // 初めの1回目だけ曜日のテキストプレートを作成する
        boolean isCreateTexture = false;
        // 1ヶ月分(5週間分のマスを作る)
        for(int j = 1; j <= 6; j++) {
        	// 開始点より一列ずらす
        	// X軸の開始点
        	float xStart = xInit - (0.1f * j);
        	// Y軸の開始点
        	float yStart = yInit + (0.06f * j) ;
        	// Z軸の開始点
        	float zStart = zInit - (0.16f * j);
            // 1週間分
        	float[] weekArr = floats.get(j-1);
        	
        	// 1回目だけテクスチャを作成する
        	isCreateTexture = j == 1 ? true: false;
            for(int i = 1; i <= 7; i++) {
            	float xAdd = xWidth * i;
            	float yAdd = yWidth * i;
            	float zAdd = zWidth * i;
        		// 日付をインクリメント
        		box++;
            	if (isCreateTexture) {
            		arr.add(putOnTexturePlate(xStart + xAdd + 0.01f , yStart + yAdd - 0.03f, zStart - zAdd + 0.03f, i-1));
            	}
           	    if (box < firstDayOfWeek) { System.out.println("開始: " + firstDayOfWeek); continue; } day++; if (day >= maxDayOfMonth) {
            		break;
            	}
            	float val = weekArr[i - 1];
        		arr.add(createCube(val,
        				cubeSize, xStart + xAdd, yStart + yAdd, zStart - zAdd));
            }
        }
        // 配列の要素数を指定する
        GameItem[] items = new GameItem[arr.size()];
        // 配列の取り出し
        gameItems = arr.toArray(items);
        
        // DEBUG
        //debug();
    }

ここでのポイントは月曜始まりと、日曜始まりを変更できる様にしたところです。

	/**
	 * 対象月の月初の曜日を取得する
	 * @return Calendar.MONDAY〜SUNDAY
	 */
	public int getStartPoint(boolean isStartMon) {
		int day_week = 0;
		cal.set(Calendar.DATE, 1);
		day_week = cal.get(Calendar.DAY_OF_WEEK);
		if (isStartMon) {
			day_week = day_week == 1 ? 7 : day_week - 1;
		}
		return day_week;
	}

赤字の部分が工夫の部分です、条件文を使って「if文」を使わずに1行で済むし可読性も良い。これを使わないと以下の様なコードになります。(if文を抜粋)

if (isStartMon) {
    if (day_week == 1) {
        day_week = 7;
    } else {
        day_week = day_week -1;
    }
 }

微妙なコードです、なぜかというとif文はネストすると確認しなくてはいけないことが増えるからです。→単純にコード量が多いのもあります。

一応「条件演算子」について、サンプルとして四捨五入の場合です。

/*
 * 返却する値 = 条件式 ? TRUE時の値(式) : FALSE時の値(式)
 * System.in() // 標準入力
 */
int i = System.in;
// 4以下は「0」、5以上は「10」を「response」に代入
int response = i < 5 ? 0 : 10;

そして作成したのが以下のクラス(Gitでみる)です。(ちょっとコード量が多いですが。。。)

package zenryokuservice.gui.lwjgl.kakeibo.util;
import java.util.Calendar;

/**
 * 家計簿の各数値を表示するための領域(日)を作成する
 * @author takunoji
 *
 * 2018/11/10
 */
public class CalendarPosit {
	/** 日本語の曜日 */
	private static final String[] ja_week = new String[] {"日", "月", "火", "水", "木", "金", "土"};
	/** 英語の曜日 */
	private static final String[] en_week = new String[] {"Sun", "Mon", "Tue", "Wed", "thu", "Fri", "Sat"};

	private Calendar cal = null;
	
	public CalendarPosit() {
		cal = Calendar.getInstance();
	}
	
	/**
	 * 今月の最大日数を返す
	 * @return 最大日数
	 */
	public int getMaxDayOfMonth() {
		return cal.getMaximum(Calendar.DATE);
	}

	/**
	 * 今月の最大日数を返す
	 * @move 今月の月からずらす月数
	 * move=1  -> 1ヶ月たす
	 * mobe=-1 -> 1ヶ月引く
	 * 
	 * 
	 * 現在:10月
	 * move=  1  -> 11月の最大日数
	 * move= -1 -> 9月の最大日数
	 * @return 最大日数
	 */
	public int getMaxDayOfMonth(int move) {
		Calendar tmpCal = cal;
		tmpCal.add(Calendar.MONTH, move);
		return tmpCal.getMaximum(Calendar.DATE);
	}

	/**
	 * 対象月の月初の曜日を取得する
	 * @return Calendar.MONDAY〜SUNDAY
	 */
	public int getStartPoint(boolean isStartMon) {
		int day_week = 0;
		cal.set(Calendar.DATE, 1);
		day_week = cal.get(Calendar.DAY_OF_WEEK);
		if (isStartMon) {
			day_week = day_week == 1 ? 7 : day_week - 1;
		}
		return day_week;
	}	

	/**
	 * 現在の年の指定した月初の曜日を返却する
	 * @param month 1-12を指定する
	 * @return 対象月の、月初曜日
	 */
	public int getStartPoint(int month, boolean isStartMon) {
		int day_week = 0;
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.MONTH, month - 1);
		cal.set(Calendar.DATE, 1);
		
		day_week = cal.get(Calendar.DAY_OF_WEEK);
		return day_week;
	}

	/**
	 * カレンダークラスを返却する。
	 * @return
	 */
	public Calendar getCalendar() {
		return this.cal;
	}
	/**
	 * 開始日付に対応する曜日の値を返す。
	 * @return 曜日の文字列
	 */
	public String getDayOfWeek(boolean isStartMon) {
		return ja_week[getStartPoint(isStartMon)];
	}
	/**
	 * 引数の値が何曜日か判定して返却する
	 * @param value Calendarクラスより取得した、DAY_OF_WEEK
	 * @return 対象の曜日の値
	 */
	public int chkWeek(int value, boolean isStartMon) {
		int day_of_week = 0;
		
		switch(value) {
		case Calendar.MONDAY:
			day_of_week = Calendar.MONDAY;
			break;
		case Calendar.TUESDAY:
			day_of_week = Calendar.TUESDAY;
			break;
		case Calendar.WEDNESDAY:
			day_of_week = Calendar.TUESDAY;
			break;
		case Calendar.THURSDAY:
			day_of_week = Calendar.TUESDAY;
			break;
		case Calendar.FRIDAY:
			day_of_week = Calendar.TUESDAY;
			break;
		case Calendar.SATURDAY:
			day_of_week = Calendar.TUESDAY;
			break;
		case Calendar.SUNDAY:
			day_of_week = Calendar.TUESDAY;
			break;
		default:
			// TODO-[例外処理の実装]
			System.out.println("想定外の曜日です[day_of_week]: " + day_of_week);
			System.exit(-1);
		}

		// 日曜始まり=true, 月曜始まり=false
		if (isStartMon == false) {
			day_of_week = day_of_week < 7 ? day_of_week + 1 : 1;
		}
		return day_of_week;
	}
}

いろんなパターンに対応できる様に先にコードだけ作りました。

関連ページ一覧

<家計簿アプリ作成>

  1. Eclipse アプリ作成 Lv1〜家計簿を作る準備〜
  2. Eclipse アプリ作成 Lv2〜家計簿を作る土台作り〜
  3. Eclipse アプリ作成 Lv3〜3Dグラフ用Cube作り〜
  4. Eclipse アプリ作成 Lv4〜3Dグラフ用Cubeに高さを与える〜
  5. Eclipse アプリ作成 Lv5〜惨敗:CubeにTextureを貼る〜
  6. Eclipse アプリ作成 Lv7〜Cubeを日付順に並べる

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 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Java 3DGame LWJGL Retry Lv7 遊んでみる3〜全部テクスチャにする〜

イントロダクション

ここのところ負け越しの1引分けでしたが、ついにやっつけました。

<戦闘履歴>

  1. Eclipse アプリ作成 Lv5〜惨敗:CubeにTextureを貼る〜「惨敗」
  2. Java 3DGame LWJGL Retry Lv3 Texture〜動かして理解する3〜「負け越し」
  3. Java 3DGame LWJGL Retry Lv4 デバック〜動かして理解する4〜「黒星」
  4. Java 3DGame LWJGL Retry Lv5 遊んでみる〜動かして理解する5〜「引分け」
  5. Java 3DGame LWJGL Retry Lv6 遊んでみる2〜動かして理解する6〜「白星」

最終的に以下の様なコードができました。主にいじったのは「DummyGame」クラスです。ポイントは以下になります。

  1. メッシュを作成するときはテクスチャを使用する様に修正
  2. メッシュを作成するときの各頂点(Vertex)の定義を見直す
  3. 同様に頂点を結びつける順番(indices)を見直す

<DummyGame#init()>

    @Override
    public void init(Window window) throws Exception {
        renderer.init(window);
        // Cubeの高さ
        ArrayList<float[]> floats = new ArrayList<>();
        floats.add(new float[] {0.0001f, 0.12f, 0.3f, 0.001f, 0.1f, 0.25f, 0.1f});
        floats.add(new float[] {0.15f, 0.19f, 0.23f, 0.2f, 0.08f, 0.13f, 0.12f});
        floats.add(new float[] {0.1f, 0.2f, 0.4f, 0.001f, 0.2f, 0.05f, 0.15f});
        floats.add(new float[] {0.11f, 0.12f, 0.3f, 0.001f, 0.1f, 0.25f, 0.1f});
        floats.add(new float[] {0.12f, 0.13f, 0.14f, 0.015f, 0.16f, 0.17f, 0.18f});
        // Cubeの底面のサイズ(正方形)
        final float cubeSize = 0.1f;
        // x軸の初期値
        final float xInit = -0.5f;
        // y軸の初期値
        final float yInit = -0.8f;
        // z軸の初期値
        final float zInit = -2;
        // x軸の増減幅
        final float xWidth = 0.185f;
        // y軸の増減幅
        final float yWidth = 0.033f;
        // z軸の増減幅
        final float zWidth = 0.1f;
        ArrayList arr = new ArrayList();
        
        // 初めの1回目だけ曜日のテキストプレートを作成する
        boolean isCreateTexture = false;
        // 1ヶ月分(5週間分のマスを作る)
        for(int j = 1; j <= 5; j++) {
        	// 開始点より一列文ずらす
        	// X軸の開始点
        	float xStart = xInit - (0.1f * j);
        	// Y軸の開始点
        	float yStart = yInit + (0.06f * j) ;
        	// Z軸の開始点
        	float zStart = zInit - (0.16f * j);
            // 1週間分
        	float[] weekArr = floats.get(j-1);
        	
        	// 1回目だけテクスチャを作成する
        	isCreateTexture = j == 1 ? true: false;
            for(int i = 1; i <= 7; i++) {
            	float xAdd = xWidth * i;
            	float yAdd = yWidth * i;
            	float zAdd = zWidth * i;
            	if (isCreateTexture) {
            		arr.add(putOnTexturePlate(xStart + xAdd + 0.01f , yStart + yAdd - 0.03f, zStart - zAdd + 0.03f, i-1));
            	}
            	float val = weekArr[i - 1];
        		arr.add(createCube(val,
        				cubeSize, xStart + xAdd, yStart + yAdd, zStart - zAdd));
            }
        }
        // 配列の要素数を指定する
        System.out.println("GmaeItems: " + arr.size());
        GameItem[] items = new GameItem[arr.size()];
        // 配列の取り出し
        gameItems = arr.toArray(items);
        
        // DEBUG
        //debug();
    }

<DummyGame#putOnTexturePlate()>

    /**
     * Texture作成メソッド
     * @param xPos
     * @param yPos
     * @param zPos
     * @param num 曜日の番号0:月〜7:日
     * @return GameItem
     */
    private GameItem putOnTexturePlate(float xPos, float yPos, float zPos, int num) {
    	float size = 0.08f;
    	float[] positions = new float[] {
    			-1 * size, size, size, // V0
    			-1 * size, -1 * size, size, //V1 
    			size, -1 * size, size, // V2
    			size, size, size, // V3
    			
    			-1 * size, size, -1 * size, // V4
    			size, -1 * size, size, //V5 
    			-1 * size, -1 * size, -1 * size, // V6
    			size, -1 * size, -1 * size, // V7
    			};
    	float[] textCoords = new float[]{
                0.0f, 0.0f, 
                0.0f, 1.0f,
                1.0f, 1.0f,
                1.0f, 0.0f,
            };
    	int[] indices = new int[] {
    			0, 1, 3, 3, 1, 2
			};
    	Texture texture = null;

    	try {
        	texture = new Texture("/textures/" + weekTexture[num] +  ".png");
    	} catch(Exception e) {
    		e.printStackTrace();
    	}
        TexturedMesh mesh = new TexturedMesh(positions, textCoords, indices, texture);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(xPos, yPos, zPos);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

<DummyGame#createCube()>

    private GameItem createCube(float height, float cubeSize, float posX, float posY, float posZ) {
        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -1 * cubeSize,  height,  cubeSize,
            // V1
            -1 * cubeSize, -1 * cubeSize,  cubeSize,
            // V2
            cubeSize, -1 * cubeSize,  cubeSize,
            // V3
            cubeSize,  height,  cubeSize,
            // V4
            -1 * cubeSize,  height, -1 * cubeSize,
            // V5
            cubeSize,  height, -1 * cubeSize,
            // V6
            -1 * cubeSize, -1 * cubeSize, -1 * cubeSize,
            // V7
            cubeSize, -1 * cubeSize, -1 * cubeSize,
        };
        float[] colours = new float[]{
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            4, 0, 3, 5, 4, 3,
            // Right face
            3, 2, 7, 5, 3, 7,
            // Left face
            6, 1, 0, 6, 0, 4,
            // Bottom face
            2, 1, 6, 2, 6, 7,
            // Back face
            7, 6, 4, 7, 4, 5,
        };
    	Texture texture = null;
    	try {
        	texture = new Texture("/textures/wood1.png");
    	} catch(Exception e) {
    		e.printStackTrace();
    	}
        TexturedMesh mesh = new TexturedMesh(positions, colours, indices, texture);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(posX, posY, posZ);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

上記のポイントを抑えサイドコードを直したところうまくいきました。


関連ページ一覧

<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 Retry Lv6 遊んでみる2〜動かして理解する6〜

イントロダクション

ここ数日連敗が続いていましたが、昨日引き分けにもつれ込みました。

  1. Eclipse アプリ作成 Lv5〜惨敗:CubeにTextureを貼る〜「惨敗」
  2. Java 3DGame LWJGL Retry Lv3 Texture〜動かして理解する3〜「負け越し」
  3. Java 3DGame LWJGL Retry Lv4 デバック〜動かして理解する4〜「黒星」
  4. Java 3DGame LWJGL Retry Lv5 遊んでみる〜動かして理解する5〜「引分け」
  5. Java 3DGame LWJGL Retry Lv6 遊んでみる2〜動かして理解する6〜「白星」

今日は勝つ予定です。。。

前回(「引分け」)はLWJGL GitBook Chapter7テクスチャを張り替えたり表示を変えたりして遊びました。

そして「遊んでみる方が学習効率も高い」ということを確信しました。というわけで、このまま次のチャプタをやってみようと思います。

Chapter8〜Camera〜

チャプタとしては「カメラ」と書いてありますが、ポイントとしてはテクスチャを貼り付けたオブジェクトを複数生成する場合の処理方法の理解です。

<Chapter8の実行結果>

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

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

 テクスチャありとなしのキューブを作成する

色々やったけど、こんな感じで中途半端にテクスチャが貼れています。

結論

シェーダを2種類用意していないな・・・つまり、テクスチャありの状態でCubeを作成しているので、全てのCubeにテクスチャが貼り付けられている状態です。

『本当は、「テクスチャあり」が手前の7個でそのほかは「テクスチャなし」にしようと思っております。』

<2018/11/09追記>
→この考え方が負因でした、片方はシェーダを使用する、もう片方はシェーダを使用しない。こうなるとシェーダプログラムを2つ用意してそれぞれのメッシュにもそれぞれのシェーダプログラムを適用する必要があるので、まぁ面倒だし実用的でないと判断しました。つまり全部テクスチャを使用する様に修正しました。

 

<テクスチャなし>色を指定しています。

今回は辛勝といったところでしょうか。。。

でわでわ。。。

関連ページ一覧

<今回のやっていること>

  1. Eclipse アプリ作成 Lv1〜家計簿を作る準備〜
  2. Eclipse アプリ作成 Lv2〜家計簿を作る土台作り〜
  3. Eclipse アプリ作成 Lv3〜3Dグラフ用Cube作り〜
  4. Eclipse アプリ作成 Lv4〜3Dグラフ用Cubeに高さを与える〜
  5. Eclipse アプリ作成 Lv5〜惨敗:CubeにTextureを貼る〜
  6. Eclipse アプリ作成 Lv7〜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 Retry Lv5 遊んでみる〜動かして理解する5〜

イントロダクション

この数日、連敗が続いている状態です。

  1. Eclipse アプリ作成 Lv5〜惨敗:CubeにTextureを貼る〜
  2. Java 3DGame LWJGL Retry Lv3 Texture〜動かして理解する3〜「負け越し」
  3. Java 3DGame LWJGL Retry Lv4 デバック〜動かして理解する4〜「黒星」

こんな感じで3連敗です。。。

元々は、OpenGLで作成したCubeにテクスチャを貼り付けようとしていました。

ここで、初心に戻り動くものを弄って遊んでみようとなりました。突破口になるかもしれません。

サンプルコード:「Chapter7-2のマイクラの様なブロックを回転させる

<起動結果>


遊んでみる

First Attack: テクスチャを弄ってみる

<DummyGame#init()>元々のコード

        float[] textCoords = new float[]{
            0.0f, 0.0f,// TRY2
            0.0f, 0.5f,// TRY3
            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,// TRY1
            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,
        };

テクスチャの座標を指定している部分です。こいつを弄って遊んでみようとなりました。

TRY1-①: 「0.0f, 0.5f」→「0.0f, 0.2f」に変更。

回転しているので座標がわかりづらい。。。

ちょっとハゲができました。

TRY1-②: 「0.0f, 0.5f」→「0.5f, 0.5f」に変更。

頂点の一部がかき消された様になっています。下のコードをみてみると頂点が被っていて、実際は3点のみになっています。

            // For text coords in top face
            0.5f, 0.5f,// 同じ
            0.5f, 0.5f,// 同じ
            0.0f, 1.0f,
            0.5f, 1.0f,

なるほど、テクスチャの頂点を指定している様です。

ここからが本題

元々のコード、緑色の部分に関しては未だになんなのかわかっていませんのでこいつを弄ってみます。

「TRY2」の部分を「0.0f, 0.0f」→「0.5f, 0.5f」に変更

おそらく、V0の座標を変更したので下のイメージの半分より下の部分がテクスチャとして認識されていると思われます。

Texture coordinates front face

テクスチャのイメージファイルを変更してみます。

<実行結果>

うーんパズルの様な感じになりました。ちょいと調節すると。。。

一面のみうまく表示されています。この状態のコードは以下です。

        float[] textCoords = new float[]{
            0.0f, 0.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.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.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 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,
        };

次のコードです。

        float[] textCoords = new float[]{
        	// Imageの取得する座標
            0.0f, 0.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            // この部分がわからない
            0.0f, 0.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            
            // For text coords in top face
            0.0f, 0.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,

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

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

            // For text coords in bottom face
            0.0f, 0.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
        };

一面以外はうまくいっている様です。(多分底面がうまくいっていない)

ですが、なんとなく処理の流れ(座標の取り方)がわかってきました(そんな気がする。。。)、まだ仮説状態です。

まずは頂点定義の配列を眺めます

 
        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,
            /* ③横のたて(1本分)を定義する */
            // For text coords in right face
            // V12: V3 repeated
            0.5f, 0.5f, 0.5f,
            // V13: V2 repeated
            0.5f, -0.5f, 0.5f,
            /* ④横のたて(1本分)を定義する */
            // 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,
        };

 

Cube coords

頂点を定義した後に、面を定義する様に座標点を設定していきます。

Texture coordinates front face

中途半端だけど。。。

コードはこちらにアップロードしてあります。2018/11/08


 

関連ページ一覧

<今回のやっていること>

  1. Eclipse アプリ作成 Lv1〜家計簿を作る準備〜
  2. Eclipse アプリ作成 Lv2〜家計簿を作る土台作り〜
  3. Eclipse アプリ作成 Lv3〜3Dグラフ用Cube作り〜
  4. Eclipse アプリ作成 Lv4〜3Dグラフ用Cubeに高さを与える〜
  5. Eclipse アプリ作成 Lv5〜惨敗:CubeにTextureを貼る〜
  6. Eclipse アプリ作成 Lv7〜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 Retry Lv4 デバック〜動かして理解する4〜

イントロダクション

前々回、惨敗を喫してしまったのでリベンジきめます。前回は3次元描画ではなく2次元描画にレベルを落として動かしてみました。PNGファイルを読んでいるところまでは、確認できているのですが。。。そのあと描画するときに指定する座標に関してはまるで判らない状態なのでそこを解決しようと思います。

デバック方法

  1. まずはコードを見直す
  2. 想定通りの結果を得るための処理として正しいか、否か?
  3. 原因を探る
  4. 解決策を打つ

参照するドキュメント:LWJGL GitBookChapterのChapter5

カスタムするコード:LWJGL GitBook Chapter5

座標に関して(ソースを見直す)

ソースコード上では以下のようになっています。

<DummyGame#createFloor()>

    /**
     * 床のような土台のメッシュ(3Dモデル)を作成します
     * @return GameItem 床型のメッシュ
     */
    private GameItem createFloor() {
        float[] positions = new float[]{
            	// V0
                0.0f, 0.25f, 0.0f,
                // V1
                -0.0f, -0.0f, 0.0f,
                // V2
                0.5f, -0.0f, 0.0f,
                // V3
                0.5f, 0.25f, 0.0f,};
            int[] indices = new int[]{
                0, 1, 3, 3, 1, 2,};
            // 追記 2018/10/27
            float[] textCoord = new float[] {
            	    0.5f, 0.0f, 0.0f,   //V0の色(赤(R))
            	    0.0f, 0.5f, 0.0f,   // V1の色(緑(G))
            	    0.0f, 0.0f, 0.5f,   // V2の色(青(B))
            	    0.8f, 0.8f, 0.0f,}; // V3の色(黄)
            return new GameItem(new Mesh(positions, indices, textCoord));
    }

上記の赤字部分が理解できていない部分です。ここの部分は、元々色を指定していた部分です。変数名が「colour」から「textCoords」に変わっただけです。

現状の理解は、上のコードにあるように各頂点の色を指定している認識です。実行結果もそのようになりました。

これがTextureに変わることで下のようになってしまいました。

ちょっとホラーな感じがします(自分だけ?)

調査開始(正しい処理か?否か?)

まずは、未着手部分→シェーダについて調べます。現状のシェーダは以下のようになっています。

<Renderer#init()>

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

上のコードから「/vertex5.vs」「/fragment5.fs」を参照していることを確認。

そして、フォルダー構成より以下の階層を確認(ビルドパスには「resources」を追加してあります。

<vertex5.vs>

#version 330

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

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

<fragment5.fs>

#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;
}

以前追加したコードがあるようです。

これで考える材料が揃いました。

処理を追いかけます。参照するコードはイントロダクション部分にリンクがあるのでそちらをご覧ください。

  1. Main#main(): DummyGame, GameEngineをインスタンス化してGameEngine#satrt()を起動
  2. DummyGameのコンストラクタ: Rendererクラスのインスタンス化→フィールドで保持
  3. GameEngineのコンストラクタ: 自分自身をスレッド化してWindowクラスのインスタンス化、DummyGame(インターフェース)をフィールドに保持、Timerクラスをインスタンス化してフィールドに保持
  4. 「1」でGameEngine#start()が起動される、OSの判定をして結局GameEngine#run()が起動する
  5. GameEngine#init()とgameLoop()を起動する
  6. 最後にclearnup()が起動する
  7. GameEngine#init()でフィールドに保持した「Window」「Timer」「gameLogic(DummyGame)」のinit()を起動する
  8. 今回は描画部分を調査するのでDummyGame#init()(gameLogic.init())を眺める
  9. DummyGame#init()ではRenderer#init()とGameItem(Mesh)を作成している
  10. Renderer#init(): ShaderProgram をインスタンス化、shader, fragmentプログラムを読み込み最後にShapderProgram#link()を起動する
  11. 「glLinkProgram()」でShaderをインスタンス化したときにフィールドで保持したprogramIdをリンクする(OpenGLのメソッドなので深堀はしないでおく→ハマることが多い)そのほか設定する処理を走らせる。
  12. 今回の目玉四角形を作成する

そして、ドキュメントを読むと「Meshクラスを変更して、色の代わりにテクスチャ座標を含む浮動小数点数の配列を受け入れるようにします」とあるので単純に「colour」を「textCoords」に変更した状態が今のコードです。

上記の部分を修正して実行してみると。。。

まっくろくろすけでわ、あーりませんか?

試しに背景を白くしてみます。。。とその前に今までのソースは「import static  XXXX.GL?」というクラスをstaticでインポートしているのでどのメソッドがどのクラスのメソッドかわからなかったので「static」を消します。

<Rendererクラス>

package zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter5.game;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

import org.joml.Matrix4f;

import zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter5.engine.Utils;
import zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter5.engine.Window;
import zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter5.engine.graph.GameItem;
import zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter5.engine.graph.Mesh;
import zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter5.engine.graph.ShaderProgram;
import zenryokuservice.gui.lwjgl.tutoriral.gitbook.chapter5.engine.graph.Transformation;

public class Renderer {

    private ShaderProgram shaderProgram;
    
    // 2018/11/08
    private Transformation transformation;

    public Renderer() {
    	transformation = new Transformation();
    }

    public void init() throws Exception {
        shaderProgram = new ShaderProgram();
        shaderProgram.createVertexShader(Utils.loadResource("/vertex5.vs"));
        shaderProgram.createFragmentShader(Utils.loadResource("/fragment5.fs"));
        shaderProgram.link();
        
        // 2018/11/08追記
        shaderProgram.createUnitform("projectionMatrix");
        shaderProgram.createUnitform("worldMatrix");
        shaderProgram.createUnitform("texture_sampler");
    }

    public void clear() {
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
    }

    public void render(Window window, GameItem[] gameItems) {
        clear();

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

        shaderProgram.bind();
        int i = -1;
        for (GameItem item : gameItems) {
// Meshクラスに処理を移動
//            // Draw the mesh
//            glBindVertexArray(item.getMesh().getVaoId());
//            glEnableVertexAttribArray(++i);
//            // 追記 2018/10/27
//            glEnableVertexAttribArray(++i);
//            glDrawElements(GL_TRIANGLES, item.getMesh().getVertexCount(), GL_UNSIGNED_INT, 0);
        	// ワールド座標を設定する
        	Matrix4f worldMatrix = transformation.getWorldMatrix(item.getPosition(), item.getRotation(), item.getScale());
        	shaderProgram.setUniform("worldMatrix", worldMatrix);
        	item.getMesh().render();
        }

        // Restore state
        GL20.glDisableVertexAttribArray(0);
        GL30.glBindVertexArray(0);

        shaderProgram.unbind();
    }

    public void cleanup() {
        if (shaderProgram != null) {
            shaderProgram.cleanup();
        }
    }
}

今度は真っ白です、つまり何も描画していないことになります。

※背景の色を変えるのはWindow#colorの値を1.0fにしてやるとできます。

もう何がわからないので、ネットで探します。

LWJGLのWiki

色々探してみたが、Textureの座標とMeshの頂点座標の関係がわからない。。。

次は、貼れたテクスチャを解剖してみるかな?

参照するのはChapter7-1です。(Cubeの動画あり)

関連ページ一覧

<今回のやっていること>

  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 Retry Lv3 Texture〜動かして理解する3〜

イントロダクション

前回、惨敗を喫してしまいました。Textureが結局判らずじまい。。。

悔しいので、2次元描画のプログラムをカスタムしてもう一度やってみます。

参照するドキュメント:LWJGL GitBookChapterのChapter5

カスタムするコード:LWJGL GitBook Chapter5

ここで描画した四角形にテクスチャを貼ろうと思います。

<元の画像>

元々のコードにTextureクラスを追加して、MeshクラスにTextureを作成するコードを加えたものを起動してみました。

ちなみにGitに登録しているソースです。下のような感じです。



そして、実行してみた結果は以下です。

想定と全く違うものです。。。原因は一体なんだろう?

ちなみに一部ですが、ソースはこんな感じです。

<Meshクラス>

    // 最後の「boolean」はコンストラクタのオーバーロードのためだけにつけたものです。エラー回避ようです。
    public Mesh(float[] positions, int[] indices, float[] textCoords, boolean flg) {
        FloatBuffer posBuffer = null;
        IntBuffer indicesBuffer = null;
        FloatBuffer textCoordBuffer = null;
        try {
        	texture = new Texture("/textures/Mon.png");
        } catch(Exception e) {
        	e.printStackTrace();
        }
        vboIdList = new ArrayList<>();
        try {
            vertexCount = indices.length;
            vaoId = glGenVertexArrays();
            vboIdList.add(vaoId);
            glBindVertexArray(vaoId);

            // Position VBO
            int posVboId = glGenBuffers();
            vboIdList.add(posVboId);
            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);

            // Texutre coordinates VBO:2018/11/07追記部分です。
            int vboId = glGenBuffers();
            vboIdList.add(vboId);
            textCoordBuffer = MemoryUtil.memAllocFloat(textCoords.length);
            textCoordBuffer.put(textCoords).flip();
            glBindBuffer(GL_ARRAY_BUFFER, vaoId);
            glBufferData(GL_ARRAY_BUFFER, textCoordBuffer, GL_STATIC_DRAW);
            glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
            
            // Index VBO
            idxVboId = glGenBuffers();
            vboIdList.add(idxVboId);
            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);
            }
            if (textCoordBuffer != null) {
                MemoryUtil.memFree(textCoordBuffer);
            }
        }
    }

これで、とりあえず動かしてみたのだけど、上記のキャプチャ通りの結果でした。ブログを書いていて気がついたけど「シェーダ・プログラム」を修正していなかった。。。

関連ページ一覧

<今回のやっていること>

  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作成〜「動画あり」

<サイトマップ>

 

Eclipse アプリ作成 Lv4〜3Dグラフ用Cubeに高さを与える〜

参照コード:Chapter7-1(Gitです)

参照サイト:https://lwjglgamedev.gitbooks.io/3d-game-development-with-lwjgl/content/chapter07/chapter7.html

イントロダクション

前回は、Cubeを使って7 x 5マスを作りました。これだけではグラフになりませんのでこれに高さを与えてやる必要があります。

現状のソースは以下にようになってます。

@Override
    public void init(Window window) throws Exception {
        renderer.init(window);
        // Cubeのサイズ(たて、横、高さが同じなので値は1つ)
        final float cubeSize = 0.1f;
        // x軸の初期値
        final float xInit = 0;
        // y軸の初期値
        final float yInit = 0;
        // z軸の初期値
        final float zInit = -2;
        // x軸の増減幅
        final float xWidth = 0.185f;
        // y軸の増減幅
        final float yWidth = 0.033f;
        // z軸の増減幅
        final float zWidth = 0.1f;

        ArrayList arr = new ArrayList();
        for(int i = 1; i <= 7; i++) {
    		arr.add(createCube(
    				cubeSize, xInit + (xWidth * i), yInit + (yWidth * i), zInit - (zWidth * i)));
        }
        // 配列の要素数を指定する
        GameItem[] items = new GameItem[arr.size()];
        // 配列の取り出し
        gameItems = arr.toArray(items);
    }

    /* 追加したメソッドです */
    private GameItem createCube(float cubeSize, float posX, float posY, float posZ) {
        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -1 * cubeSize,  cubeSize,  cubeSize,
            // V1
            -1 * cubeSize, -1 * cubeSize,  cubeSize,
            // V2
            cubeSize, -1 * cubeSize,  cubeSize,
            // V3
            cubeSize,  cubeSize,  cubeSize,
            // V4
            -1 * cubeSize,  cubeSize, -1 * cubeSize,
            // V5
            cubeSize,  cubeSize, -1 * cubeSize,
            // V6
            -1 * cubeSize, -1 * cubeSize, -1 * cubeSize,
            // V7
            cubeSize, -1 * cubeSize, -1 * cubeSize,
        };
        float[] colours = new float[]{
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            4, 0, 3, 5, 4, 3,
            // Right face
            3, 2, 7, 5, 3, 7,
            // Left face
            6, 1, 0, 6, 0, 4,
            // Bottom face
            2, 1, 6, 2, 6, 7,
            // Back face
            7, 6, 4, 7, 4, 5,
        };
        Mesh mesh = new Mesh(positions, colours, indices);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(posX, posY, posZ);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

現状のソースを修正する

現在の処理は次のような処理を行なっています。

  1. Cubeを作成するのに必要な値を初期化、作成の開始点を設定
  2. Cubeを複製するのに必要な値(Cube1つ分の移動する幅)を定義
  3. ループで7回、createCubeを呼ぶ処理を回す
  4. createCubeでCubeを作成する時にcubeSizeを渡す
  5. 上の赤字の部分を修正して次のように変更します。
  6. Cubeの高さを持っているArrayListを作成
  7. Cubeを作成するのに必要な値を初期化、作成の開始点を設定
  8. 1ヶ月分のマス(Cube)を作成するために5回ループを作成
  9. 「2」で指定した開始点にループした回数分ずらす処理を追加(1回目は変更なし)
  10. Cubeを複製するのに必要な値(Cube1つ分の移動する幅)を定義
  11. createCubeでCubeを作成する時にcubeSizeと高さを渡す
  12. ループで7回、createCubeを呼ぶ処理を回す

<今回のソース>

    @Override
    public void init(Window window) throws Exception {
        renderer.init(window);
        // Cubeの高さ
        ArrayList<float[]> floats = new ArrayList<>();
        floats.add(new float[] {0.2f, 0.12f, 0.3f, 0.001f, 0.1f, 0.25f, 0.1f});
        floats.add(new float[] {0.15f, 0.19f, 0.23f, 0.2f, 0.08f, 0.13f, 0.12f});
        floats.add(new float[] {0.1f, 0.2f, 0.4f, 0.001f, 0.2f, 0.05f, 0.15f});
        floats.add(new float[] {0.11f, 0.12f, 0.3f, 0.001f, 0.1f, 0.25f, 0.1f});
        floats.add(new float[] {0.12f, 0.13f, 0.14f, 0.015f, 0.16f, 0.17f, 0.18f});
        // Cubeの底面のサイズ(正方形)
        final float cubeSize = 0.1f;
        // x軸の初期値
        final float xInit = -0.5f;
        // y軸の初期値
        final float yInit = -0.8f;
        // z軸の初期値
        final float zInit = -2;
        // x軸の増減幅
        final float xWidth = 0.185f;
        // y軸の増減幅
        final float yWidth = 0.033f;
        // z軸の増減幅
        final float zWidth = 0.1f;
        ArrayList arr = new ArrayList();
        // 1ヶ月分(5週間分のマスを作る)
        for(int j = 1; j <= 5; j++) {
        	// 開始点より一列文ずらす
        	// X軸の開始点
        	float xStart = xInit - (0.1f * j);
        	// Y軸の開始点
        	float yStart = yInit + (0.06f * j) ;
        	// Z軸の開始点
        	float zStart = zInit - (0.16f * j);
            // 1週間分
        	float[] week = floats.get(j-1);
            for(int i = 1; i <= 7; i++) {
            	float val = week[i - 1];
        		arr.add(createCube(val,
        				cubeSize, xStart + (xWidth * i), yStart + (yWidth * i), zStart - (zWidth * i)));
            }
        }
        // 配列の要素数を指定する
        GameItem[] items = new GameItem[arr.size()];
        // 配列の取り出し
        gameItems = arr.toArray(items);
    }

    /* 追加したメソッドです */
    private GameItem createCube(float height, float cubeSize, float posX, float posY, float posZ) {
        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -1 * cubeSize,  height,  cubeSize,
            // V1
            -1 * cubeSize, -1 * cubeSize,  cubeSize,
            // V2
            cubeSize, -1 * cubeSize,  cubeSize,
            // V3
            cubeSize,  height,  cubeSize,
            // V4
            -1 * cubeSize,  height, -1 * cubeSize,
            // V5
            cubeSize,  height, -1 * cubeSize,
            // V6
            -1 * cubeSize, -1 * cubeSize, -1 * cubeSize,
            // V7
            cubeSize, -1 * cubeSize, -1 * cubeSize,
        };
        float[] colours = new float[]{
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            4, 0, 3, 5, 4, 3,
            // Right face
            3, 2, 7, 5, 3, 7,
            // Left face
            6, 1, 0, 6, 0, 4,
            // Bottom face
            2, 1, 6, 2, 6, 7,
            // Back face
            7, 6, 4, 7, 4, 5,
        };
        Mesh mesh = new Mesh(positions, colours, indices);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(posX, posY, posZ);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

実行結果です


色がみんな同じなのでわかりづらいですね(笑)

続きは次回

でわでわ。。。

関連ページ一覧

<今回のやっていること>

  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作成〜「動画あり」

<サイトマップ>

Mapping of Java Bassic etc …~Java Basicなど記事一覧~

Eclipse アプリ作成 Lv3〜3Dグラフ用Cube作り〜

参照コード: Chapter7-1

イントロダクション

前回は、Cubeを作成して3つ並べるところまでやりました。

今回は、3つではなく7つ並べてみようと思います。

<前回のコード>

    @Override
    public void init(Window window) throws Exception {
        renderer.init(window);
        gameItems = new GameItem[] { createCube(0.1f, 0, 0, -2) };
        
    }

    /* 追加したメソッドです */
    private GameItem createCube(float cubeSize, float posX, float posY, float posZ) {
        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -1 * cubeSize,  cubeSize,  cubeSize,
            // V1
            -1 * cubeSize, -1 * cubeSize,  cubeSize,
            // V2
            cubeSize, -1 * cubeSize,  cubeSize,
            // V3
            cubeSize,  cubeSize,  cubeSize,
            // V4
            -1 * cubeSize,  cubeSize, -1 * cubeSize,
            // V5
            cubeSize,  cubeSize, -1 * cubeSize,
            // V6
            -1 * cubeSize, -1 * cubeSize, -1 * cubeSize,
            // V7
            cubeSize, -1 * cubeSize, -1 * cubeSize,
        };
        float[] colours = new float[]{
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            4, 0, 3, 5, 4, 3,
            // Right face
            3, 2, 7, 5, 3, 7,
            // Left face
            6, 1, 0, 6, 0, 4,
            // Bottom face
            2, 1, 6, 2, 6, 7,
            // Back face
            7, 6, 4, 7, 4, 5,
        };
        Mesh mesh = new Mesh(positions, colours, indices);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(posX, posY, posZ);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

前回のコードではCubeを作成するのに、いちいちX〜Zまでの値を設定していました。これは、コードを書き間違えやすく修正点も多いのでイマイチなコードです。なので、これを一般化して作成するCubeの数を与えるようなコードに修正します。

<修正したコード>

    @Override
    public void init(Window window) throws Exception {
        renderer.init(window);

        final float cubeSize = 0.1f;
        // x軸の初期値
        final float xInit = 0;
        // y軸の初期値
        final float yInit = 0;
        // z軸の初期値
        final float zInit = -2;
        // x軸の増減幅
        final float xWidth = 0.185f;
        // y軸の増減幅
        final float yWidth = 0.033f;
        // z軸の増減幅
        final float zWidth = 0.1f;

        ArrayList arr = new ArrayList();
        for(int i = 1; i <= 7; i++) {
    		arr.add(createCube(
    				cubeSize, xInit + (xWidth * i), yInit + (yWidth * i), zInit - (zWidth * i)));
        }
        // 配列の要素数を指定する
        GameItem[] items = new GameItem[arr.size()];
        // 配列の取り出し
        gameItems = arr.toArray(items);
    }

    /* 追加したメソッドです */
    private GameItem createCube(float cubeSize, float posX, float posY, float posZ) {
        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -1 * cubeSize,  cubeSize,  cubeSize,
            // V1
            -1 * cubeSize, -1 * cubeSize,  cubeSize,
            // V2
            cubeSize, -1 * cubeSize,  cubeSize,
            // V3
            cubeSize,  cubeSize,  cubeSize,
            // V4
            -1 * cubeSize,  cubeSize, -1 * cubeSize,
            // V5
            cubeSize,  cubeSize, -1 * cubeSize,
            // V6
            -1 * cubeSize, -1 * cubeSize, -1 * cubeSize,
            // V7
            cubeSize, -1 * cubeSize, -1 * cubeSize,
        };
        float[] colours = new float[]{
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            4, 0, 3, 5, 4, 3,
            // Right face
            3, 2, 7, 5, 3, 7,
            // Left face
            6, 1, 0, 6, 0, 4,
            // Bottom face
            2, 1, 6, 2, 6, 7,
            // Back face
            7, 6, 4, 7, 4, 5,
        };
        Mesh mesh = new Mesh(positions, colours, indices);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(posX, posY, posZ);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

こちらのコードでは、Cubeの初期値(を指定しています、この初期値から何個並べるのかを指定できるようにしてあります。赤字の部分が初期値を設定している部分になります。

処理概要DummyGame#init()

  1. 初期値を設定(初期化)
  2. 7回Cube作成メソッドを呼び出す
  3. ループするたびに「増減幅」文を初期値に追加(+, -)する

<実行結果>

初期値を画面の中心に指定しているのでこのようになります。

次は?

3Dグラフを表示するのに、グラフが右に寄りすぎ、、、位置が悪いので修正します。

        // x軸の初期値
        final float xInit = -0.8f;
        // y軸の初期値
        final float yInit = -0.8f;
        // z軸の初期値
        final float zInit = -2;

修正したのは赤字の部分の値だけです。表示結果は以下のようになります。

なんかイマイチですが、これを1ヶ月分(7 x 5マス)並べてみます。

修正した部分は以下になります。For文が1つだったのを2つにして以下のような手順に変更しました。

  1. 5回ループする
  2. 7つCubeを作成するときの初期値を変更する
  3. 初期値を元にCubeを7つ並べる



コードは以下になります。いわゆる2次元ループってやつですね(笑)

        // 1ヶ月分(5週間分のマスを作る)
        for(int j = 1; j <= 5; j++) {
        	// 開始点より一列文ずらす
        	// X軸の開始点
        	float xStart = xInit - (0.1f * j);
        	// Y軸の開始点
        	float yStart = yInit + (0.06f * j) ;
        	// Z軸の開始点
        	float zStart = zInit - (0.16f * j);
            // 1週間分
            for(int i = 1; i <= 7; i++) {
        		arr.add(createCube(
        				cubeSize, xStart + (xWidth * i), yStart + (yWidth * i), zStart - (zWidth * i)));
            }
        }

でわでわ。。。

関連ページ一覧

  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作成〜「動画あり」

<サイトマップ>

Mapping of Java Bassic etc …~Java Basicなど記事一覧~

 

 

Eclipse アプリ作成 Lv2〜家計簿を作る土台作り〜

前提

LWJGLのセットアップが完了して、Eclipseのプロジェクトも作成済みであること。→前回をみてください。

インントロダクション

前回はプロジェクトをEclipse上に作成し、開発の準備をしました。

重要なことなので今一度、以下を確認してください。

  1. 作成した、プログラム「Hello World」が動くことを確認 → 前回
  2. LWJGLに必要なライブラリがBuildPathに繋がっていることを確認 → LWJGLのセットアップ


3Dグラフを作る

Chapter7-1で作成したCubeをベースに作成します。

初めにCubeを小さくします。変更するのは各頂点の位置を狭くします。

<DummyGame#init()>

        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -0.1f,  0.1f,  0.1f,
            // V1
            -0.1f, -0.1f,  0.1f,
            // V2
             0.1f, -0.1f,  0.1f,
            // V3
             0.1f,  0.1f,  0.1f,
            // V4
            -0.1f,  0.1f, -0.1f,
            // V5
             0.1f,  0.1f, -0.1f,
            // V6
            -0.1f, -0.1f, -0.1f,
            // V7
             0.1f, -0.1f, -0.1f,
        };

上記のように「0.5f」の部分を「0.1f」に変更します。

それで表示できるのが下のようなイメージです。

これができたら、大きさを調節できるように各頂点を定義している部分をメソッドに切り出します。そして、サイズを指定できるように変数に変えます。

<DummyGame#createCube()>

    /* 追加したメソッドです */
    private GameItem createCube(float cubeSize, float posX, float posY, float posZ) {
        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -1 * cubeSize,  cubeSize,  cubeSize,
            // V1
            -1 * cubeSize, -1 * cubeSize,  cubeSize,
            // V2
            cubeSize, -1 * cubeSize,  cubeSize,
            // V3
            cubeSize,  cubeSize,  cubeSize,
            // V4
            -1 * cubeSize,  cubeSize, -1 * cubeSize,
            // V5
            cubeSize,  cubeSize, -1 * cubeSize,
            // V6
            -1 * cubeSize, -1 * cubeSize, -1 * cubeSize,
            // V7
            cubeSize, -1 * cubeSize, -1 * cubeSize,
        };
        float[] colours = new float[]{
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            4, 0, 3, 5, 4, 3,
            // Right face
            3, 2, 7, 5, 3, 7,
            // Left face
            6, 1, 0, 6, 0, 4,
            // Bottom face
            2, 1, 6, 2, 6, 7,
            // Back face
            7, 6, 4, 7, 4, 5,
        };
        Mesh mesh = new Mesh(positions, colours, indices);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(posX, posY, posZ);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

そして呼び出し部分を以下のように修正します。

<DummyGame#init()>

    @Override
    public void init(Window window) throws Exception {
        renderer.init(window);
        gameItems = new GameItem[] { createCube(0.1f, 0, 0, -2), createCube(0.1f, 0.185f, 0.033f, -2.1f) , createCube(0.1f, 0.37f, 0.066f, -2.2f) };
    }

ここまできたら、現在3つ並んでいるCubeをカレンダーのように並べます。が今回はここまでにします。ロジックを考える時間が欲しいのです。。。

でわでわ。。。

関連ページ一覧

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

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

<GitからのPULL方法>

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

 

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

イントロダクション

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

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

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

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

前回は、色の指定方法について解析ました。

今回は、形の変形に関してやります。

変形について

修正したJavaクラス一式に関してはGitにアップロードしてあります。PULLしたらChapter5というパッケージがありますのでそれが今回のソースになります。

元々のソース(GitBookにあるソースより少し修正しています)

<DummyGame#init()>いじって遊ぶ部分です。

 float[] positions = new float[]{
         // V0
         0.0f, 0.25f, 0.0f,
         // V1
         -0.0f, -0.0f, 0.0f,
         // V2
         0.5f, -0.0f, 0.0f,
         // V3
         0.5f, 0.25f, 0.0f,};

この状態での表示結果は下のように表示されます。

コメントにあるV0〜V3までのfloat型の値、3個で1セットになります。

V0「 0.0f, 0.25f, 0.0f,」

V1「-0.0f, -0.0f, 0.0f,」

V2「0.5f, -0.0f, 0.0f,」

V3「0.5f, 0.25f, 0.0f,」

こんな感じです。

<各点のイメージ>

2次元なので2次関数の理解があれば難しくはありません。

問題は3次元での位置

アップロードしたファイル(Git)のChapter7-1に移動します。

<DummyGame#init()>点(Vertexの「V」) が増えて8つになります。

元々のソースです。

        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -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,
        };

ちょいといじってみました。元々はinit()の中でpositions, colours, indicesを設定していたのを変更して、positionsのみ変数で値を変更できるようjにしてみました。

   @Override
    public void init(Window window) throws Exception {
        renderer.init(window);
        // キューブの大きさキューブの位置
        gameItems = new GameItem[] { createCube(0.1f, 0, 0, -2) };
        
    }
    /* 追加したメソッドです */
    private GameItem createCube(float cubeSize, float posX, float posY, float posZ) {
        // Create the Mesh
        float[] positions = new float[]{
            // VO
            -1 * cubeSize,  cubeSize,  cubeSize,
            // V1
            -1 * cubeSize, -1 * cubeSize,  cubeSize,
            // V2
            cubeSize, -1 * cubeSize,  cubeSize,
            // V3
            cubeSize,  cubeSize,  cubeSize,
            // V4
            -1 * cubeSize,  cubeSize, -1 * cubeSize,
            // V5
            cubeSize,  cubeSize, -1 * cubeSize,
            // V6
            -1 * cubeSize, -1 * cubeSize, -1 * cubeSize,
            // V7
            cubeSize, -1 * cubeSize, -1 * cubeSize,
        };
        float[] colours = new float[]{
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
            0.5f, 0.0f, 0.0f,
            0.0f, 0.5f, 0.0f,
            0.0f, 0.0f, 0.5f,
            0.0f, 0.5f, 0.5f,
        };
        int[] indices = new int[]{
            // Front face
            0, 1, 3, 3, 1, 2,
            // Top Face
            4, 0, 3, 5, 4, 3,
            // Right face
            3, 2, 7, 5, 3, 7,
            // Left face
            6, 1, 0, 6, 0, 4,
            // Bottom face
            2, 1, 6, 2, 6, 7,
            // Back face
            7, 6, 4, 7, 4, 5,
        };
        Mesh mesh = new Mesh(positions, colours, indices);
        GameItem gameItem = new GameItem(mesh);
        gameItem.setPosition(posX, posY, posZ);
        gameItem.setRotation(20, 30, 0);
        return gameItem;
    }

Cubeを作成するための座標(8点)を指定して、中点(0.0f, 0.0f, 0.0f0)を起点としたモデルを作成した後にsetPosition()でCubeを移動、setRotation()で傾きをつけてやることで、3Dモデルのようにみることができます。傾きを与えないと正方形にしか見えません。。。

作成したコードで遊んでみる

上のソース「 gameItems = new GameItem[] { createCube(0.1f, 0, 0, -2) }; 」

の行について、gameItemsにGameItemの配列を作成していますが、今回は1つだけ作成しているのであまり意味のないものになっています。がこれの意味をもたせます。

Cubeを3つに増やしてみます。コードを下のように修正します。

gameItems = new GameItem[] { createCube(0.1f, 0, 0, -2), createCube(0.1f, 1, 0, -2) };

名付けて「キューブ三兄弟」!

更に並べてみた。

gameItems = new GameItem[] { createCube(0.1f, 0, 0, -2), createCube(0.1f, 0.185f, 0.033f, -2.1f) , createCube(0.1f, 0.37f, 0.066f, -2.2f) };



お後がよろしいようで。

関連ページ一覧

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

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

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

Eclipse Meven 開発手順〜プロジェクトの作成〜

<GitからのPULL方法>

Eclipse Gitリポジトリの取得 〜GitからソースをPullしよう〜

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

Mapping of Java Bassic etc …~Java Basicなど記事一覧~