ARGENTO CUORE

 May the code be with you.

--.--.--[--] スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

2010.01.21[木] Android OpenGLでobjファイルを読み込む編 part 5

とりあえず現在のソースコードをまるごと載せてみる。

・複数テクスチャ
・グループ
・材質設定

にはまだ対応してません。

あとすごく遅い。
読み込む時点では頂点数やテクスチャ座標の数が不明なので、ArrayListを使ってaddしてるんですが、
配列と比べて遅いだろうから、あらかじめ数を取得して中間ファイルを作るようにしたほうが良いのかも…。
再配置も、Android上でやるのではなくて、PC上であらかじめ計算してそれを読み込ませたほうが良いかな。

現状mtlにはテクスチャ名を取得しに行っている以外何もしていないので、この読み込みもかなりの無駄…。

どなたかこのコードをレビューしていただけたら感謝しまくりです。

package com.gmail.argent_cuore.graphics;

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.lang.reflect.Field;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.content.Context;
import android.util.Log;

/**
* Object3D
* objファイル形式のデータを処理し、OpenGL上で扱えるデータへと変換する。
*/
public class Object3D {
final String class_name = getClass().getName();

private static Class raw_class;
private static Class drawable_class;
private final static int RAW = 0;
private final static int DRAWABLE = 1;

private static Context context = null;

private String current_material = null; //現在読み込み中のマテリアル名

private float[] vertex_data = null;
private byte[] index_data = null;
private float[] texture_data = null;

private String texture_name = null;


/**
* コンストラクタ
*/
public Object3D(Context c, Class raw, Class drawable){
context = c;
raw_class = raw;
drawable_class = drawable;
}


public Bitmap getBitmap(){
Bitmap bmp = null;
Field f = selectField(DRAWABLE,texture_name);
int id = 0;
try{
id = f.getInt(drawable_class);
}catch(IllegalAccessException e){}
if (id!=0) {
bmp = BitmapFactory.decodeResource(context.getResources(), id);
}
return bmp;
}

/**
* MTLファイルを読む。
*/
private void interpretMTL(BufferedReader buffer){
String line = null;
try {
while((line = buffer.readLine()) != null) {
if (line.length() > 0) {
char c = line.charAt(0);
if (c == 0x23) { //コメント行

} else if (c == 0x09) { //タブ
String s[] = line.split(" ");
if (s[0].equals(new String(new byte[] { 0x09 }) + "map_Kd")) { //[TAB]mak_Kdとイコール
if (current_material != null) {
texture_name = s[1];
} else {
Log.e(class_name, "マテリアル宣言がない状態で材質が定義されている可能性があります");
}
}
} else {
String s[] = line.split(" ");
if (s[0].equals("newmtl")) {
current_material = s[1];
}
}
}
}
}catch(IOException e){
Log.e(class_name, e.toString());
}
}

/**
* objファイル名を引数に受け取る。
* 解釈して頂点座標、テクスチャ座標、面データのインデックス値を生成。
* 他のは無視。
*/
public void interpretOBJ(String filename){
ArrayList<Byte> indices = new ArrayList<Byte>();
ArrayList<Float> vertices = new ArrayList<Float>();
ArrayList<Float> textures = new ArrayList<Float>();
ArrayList<Integer> texnum = new ArrayList<Integer>();

BufferedReader buff_obj = createBufferFromRawFile(filename);
String line;
try {
while ((line = buff_obj.readLine()) != null){
if (line.length() > 0) { //空行は無視
char c1 = line.charAt(0); //一文字目
char c2 = line.charAt(1); //二文字目
char c3 = line.charAt(2); //三文字目
if (c1 == 0x20) { //スペースはスキップ
continue;

} else if (c1 == 0x23) { //#はコメント行であるため解釈しない
continue;

} else if (c1 == 0x6D && c2 == 0x74 && c3 == 0x6C) { //mtl(lib)
String s[] = line.split(" ");
BufferedReader buff_mtl = createBufferFromRawFile(s[1]); //mtlファイルをロード
interpretMTL(buff_mtl); //mtlファイルを解釈
continue;

} else {
switch (c1) {
case 0x76: //v
switch (c2) {
case 0x20: //v(space)
String vs[] = line.split(" ");
vertices.add(Float.parseFloat(vs[1])); //x
vertices.add(Float.parseFloat(vs[2])); //y
vertices.add(Float.parseFloat(vs[3])); //z
break;

case 0x6E: //vn
break;
case 0x74: //vt
String vts[] = line.split(" ");
textures.add(Float.parseFloat(vts[1])); //u
textures.add(Float.parseFloat(vts[2])); //t
break;
default:
Log.w(class_name, "v" + c2 + "というラベルに対する処理が定義されていません");
break;
}
break;
case 0x66: //f
switch (c2) {
case 0x20: //space
String s[] = line.split(" ");

//indicesは三角ポリゴンの面を構成する頂点座標へのインデックス値
//texnumは、頂点座標に対応するテクスチャ座標へのインデックス値
//1番目と2番目しか読まない
String ss1[] = s[1].split("/");
indices.add((byte)(Integer.parseInt(ss1[0])-1)); //0からはじまるようマイナス1
texnum.add((int)Integer.parseInt(ss1[1])-1);

String ss2[] = s[2].split("/");
indices.add((byte)(Integer.parseInt(ss2[0])-1));
texnum.add((int)Integer.parseInt(ss2[1])-1);

String ss3[] = s[3].split("/");
indices.add((byte)(Integer.parseInt(ss3[0])-1));
texnum.add((int)Integer.parseInt(ss3[1])-1);
break;
default:
break;
}
break;
default:
Log.w(class_name, c1 + "というラベルに対する処理が定義されていません");
break;
}
}
}
}
}catch(IOException e){
}

//-------------------------------------------------------
//f行の頂点座標の指定にしたがって新しいリストを作成する
//-------------------------------------------------------
ArrayList<Float> vertices2 = new ArrayList<Float>();
ArrayList<Float> textures2 = new ArrayList<Float>();
int count_max = indices.size();

index_data = new byte[count_max];
for (int i=0; i<count_max; i++){
//頂点座標をindicesの配列に従って再配置
int num = indices.get(i)*3;
vertices2.add(vertices.get(num));
vertices2.add(vertices.get(num+1));
vertices2.add(vertices.get(num+2));

//テクスチャ座標をtexnumの配列に従って再配置
num = texnum.get(i)*2;
textures2.add(textures.get(num));
textures2.add(textures.get(num+1));

//インデックスデータは1から順に並ぶだけ
index_data[i] = (byte)i;
}

//再配置済みの頂点座標を配列にセット
count_max = vertices2.size();
vertex_data = new float[count_max];
for (int i=0; i<count_max; i++){
vertex_data[i] = vertices2.get(i);
}

//テクスチャ座標を配列にセット
count_max = textures2.size();
texture_data = new float[count_max];
for (int i=0; i<count_max; i+=2){
texture_data[i] = textures2.get(i);
texture_data[i+1] = 1.0f - textures2.get(i+1); //t座標は上下が反転するため1.0から引く
}
}

private BufferedReader createBufferFromRawFile(String filename){
BufferedReader buffer = null;
Field f = selectField(RAW,filename);
int id = 0;
try{
id = f.getInt(raw_class);
}catch(IllegalAccessException e){}
return loadFileFromFieldId(id);
}

private BufferedReader loadFileFromFieldId(int id){
InputStream is = context.getResources().openRawResource(id);
return new BufferedReader(new InputStreamReader(is));
}

private Field selectField(int resource_type, String name){
Field f = null;
try {
if (resource_type == RAW){
f = raw_class.getField(name);
} else if (resource_type == DRAWABLE) {
f = drawable_class.getField(name);
}
}catch(NoSuchFieldException e){}

if (f==null){
Log.e(class_name, name + "というフィールドが存在しません。");
}
return f;
}

/**
* 頂点座標のデータをint型の配列で返す。
* interpretOBJ()を呼ぶ前に実行しちゃダメ。
*/
public int[] getVertexDataAsInt(){
int[] vd = null;
if ( vertex_data != null) {
vd = new int[vertex_data.length];
for(int i=0; i<vertex_data.length; i++){
vd[i] = (int)(vertex_data[i] * 65535); //浮動小数点数を固定小数点数に変換
}
}
return vd;
}

public float[] getVertexData(){
return vertex_data;
}

public byte[] getIndexData(){
return index_data;
}

public float[] getTexCoords(){
return texture_data;
}
}

スポンサーサイト

Comment

2010.07.24 Sat 14:00  

ぐぐってたらここを見つけました。
objの読み込みは難しそうですね・・・
  • #/l2i4akk
  •  
  • [URL]
  • [Edit]

2010.07.24 Sat 20:30  どもー

いらっしゃいませ。ライブラリとして公開されている誰かが作ったやつを使うのが一番早道かなと思います。ただ、完全にobjを扱えるライブラリ&オープンソースのものが見当たらないです……。
  • #yl2HcnkM
  • RoNor 
  • [URL]
  • [Edit]

2011.04.03 Sun 08:46  承認待ちコメント

このコメントは管理者の承認待ちです
  • #
  •  
  • []
  • [Edit]

2011.04.19 Tue 18:02  Re: objファイルのロード方法分かりません

はじめまして。
返事が遅れてしまいもうしわけありません。

わざわざ断りを入れてくださってありがとうございます。
ブログのほうに書いているコードについては、特に断りなく自由に使っていただいて大丈夫です。が、objロードのコードはとりあえず動くという形で、単純なモデルデータでもロード処理に時間がかかるかもしれません(最近のAndroid端末だったら平気かな……)。あと、マテリアル関係は単一テクスチャにしか対応しておりません。あと、不具合などももしかしたらあるかもしれないので、それをご承知の上でお使いいただければと思います。

objのファイルフォーマットは、解析という手段をとらなくても、テキストファイルで記述されているため通常のエディタ等で開くことができます。また、ファイルフォーマットの中身については、

http://www.javaview.de/guide/formats/Format_Obj.html

等を参考にされると良いと思います。



> はじめまして、AndroidのOpenGLでモデリングファイルをインポートする方法を探してたどり着きました。
> 一応こういうのもありましたが(まだ試してませんが)、ご自身で作成される予定でしょうか?
> もし、ロード方法がわからなければ、RoNorさんのソースを使用してアプリを作成しても大丈夫でしょうか?
> objファイルを解析するスキルがないですので・・。
>
> http://d.hatena.ne.jp/nakamura001/20101102/1288715737
>
> (一部objファイルのロード)
> http://code.google.com/p/earth-live-wallpaper/source/browse/trunk/%20earth-live-wallpaper/SLWP/src/com/seb/SLWP/Sphere.java
  • #-
  • RoNor 
  • [URL]
  • [Edit]






(編集・削除用)


管理者にだけ表示を許可

Trackback

http://ronor.blog81.fc2.com/tb.php/37-26a1f77e

この記事にトラックバック(FC2Blog User)

Scala Feed

scala feed

FC2カウンター

プロフィール

RoNor

Author:RoNor
得意呪文はScalaですって言えるようになるのが夢です。
デスマーチ中、パーティメンバーの防御力を向上させたりさせなかったり。

検索フォーム

QRコード

QRコード

Copyright © 2009-2010 ARGENTO CUORE and RoNor All rights reserved.

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。