忍者ブログ

カレンダー

03 2025/04 05
S M T W T F S
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30

最新コメント

[11/20 かいせい]
[11/18 NONAME]
[10/01 かいせい]
[10/01 masafumi]
[09/28 なんとなく]

最新トラックバック

プロフィール

HN:
Kaisei+
性別:
男性

バーコード

ブログ内検索

カウンター

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

OBJファイルの読み込み その2

前回の話でなんとなく.objファイルを読み込むモチベーションを感じてもらえたことでしょう.
さて,じゃ読み込みましょうかね.
先に言っておきますが,ここではcもしくはc++で開発します.ボクみたいな面倒くさがりさんは,開発言語はcもしくはc++くらいしか使う気がありません.型を定義しないような言語はデバッグが面倒なことが多いので使いません.

読み込む前に,まず.objファイルがどのような構造なのかを知らなければなりません.
ということで調べましょう.
「cg objファイル フォーマット」とかで検索すれば,なんか出てきます.
で,だいたいそれで正解です.検索ワードにcgを入れないと,cのコンパイルした時にできるようなobjファイルのことについて出てきちゃいます.今はそんなのを知ってもしょうがないですからね.

まぁとにかく調べたらどのサイトも以下のようなことが書いてあると思います.
「v」は頂点x y z
「vt」はテクスチャ座標
「vn」は法線x y z
「f」は面
「g」はグループ
ほかにもマテリアルとか何とかってあるかもしれませんがその辺は無視で.

これらの記号を見ても,初見だと意味わからないですよね.
ボクもそうでした.
これはどういう意味かというと,行のはじめにvがついていた場合,その列は頂点のxyzを記してあるということです.
.objファイルの性質として,一行に1頂点,もしくは1面を定義します.

v 1 0 0

これは{x,y,z}={1,0,0}という頂点を指しているということです,スペース区切りでxyzを並べています.
つぎに,vtですがこれはテクスチャを貼り付けるための座標が記されます.

vt 1 1

これはテクスチャ座標の(1,1)を指します.
そして,vnは法線です.

vn 0 0 1

この場合,法線ベクトルが(0,0,1)だということです.
ここまでが座標に関することです.
なんとなくわかってきたでしょうか.
これらv,vt,vnは座標に関する情報の定義でしたが,これだけではポリゴンメッシュとして定義できません.
面の定義が必要です.
面はfで始まる行で定義されています.しかし,座標に関する定義とは大きく違う書き方をしています.

f a1/b1/c1 a2/b2/c2 a3/b3/c3 a4/b4/c4 ...

このような書き方になっています.
スペース区切りでa/b/cが並んでいます.
それぞれaは頂点座標のインデックス,bはテクスチャ座標のインデックス,cは法線のインデックスです.
a/b/cが3つ並んでいた場合,それは三角形を示します.
4つ並んでいると四角形,5つだと五角形ということになります.
インデックスは最初に定義されたvには1番がつけられ,それ以降は1ずつ増えた番号与えられていきます.
a/b/cはスラッシュ区切りになっており,場合によってはテクスチャ座標が抜かれたり法線が省略されたりします.
テクスチャ座標が参照されないような場合は,

f a1//c1 a2//c2 a3//c3 a4//c4 ...

となっています.
必ずしもスラッシュの数が2つあるわけではなく,

f a1 a2 a3 a4 ...

のように省略される場合もあります.

gのグループについてはgがついたあとの面はグループ化されるということです.
それだけです.

以上がフォーマットについてでしたが,比較的簡単に読み込めそうですよね.
頂点の座標などのv,vt,vnは簡単ですよね.
一行を読み込んで,一文字目を見て,それ以降を単純にスペース区切りで読み込めばよいだけですからね.
しかし,ちょっと厄介なのは面の読み込みです.
何個の頂点で面を構成しているかのかを示していないので,リスト構造や配列を用意してその中に入れてみて,数を数えなければなりません.
しかも,面の各頂点の情報は頂点,テクスチャ座標,法線ベクトルをそれぞれスラッシュ区切りで指しています.
考えるだけでも面倒ですよね.
面倒なのですが,書いてしまえば簡単なものです.

ボクはデータをまとめて持っておくのが好きなタイプですから,ファイルから抜き出したデータを一括して管理しておきます.
ですから,クラスを作って,その中に頂点座標やテクスチャ座標,法線ベクトル,面の情報を格納していきます.
また,面の情報は面の情報としてクラスとします.
それぞれをMeshDataクラスとFaceIndexクラスと名付けました.
この二つのクラスで400行くらいしかないので,短いのですが,この記事にべた張りするとあほみたいに長くなるので,何か別の方法で掲載します.いや,面倒になったらしないかも.
とにかく,これらのクラスは以下のようなメンバー変数を持ちます.
MeshDataクラスのメンバー変数は,

bool vertexF;
int verticesN;
double** vertices;

bool textureF;
int textureCoordN;
double **textureCoords;

bool normalF;
int normalsN;
double **normals;

bool faceF;
int facesN;
FaceIndex **faces;

としました.実は他にもいろいろ持たせてあるのですが,今は面倒なのでこれだけで.
vertexFやtextureF,normalF,faceFはそれぞれそのデータが有効なのかを示すために用意しました.
verticesNとverticesはそれぞれ頂点の数と頂点の座標,textureCoordNとtextureCoordはそれぞれテクスチャ座標の数とテクスチャ座標,normalsNとnormalsはそれぞれ法線ベクトルの数とベクトルです.
facesNとfacesはそれぞれ面の数と面の情報です.

FaceIndexには上で用意したvertices,textureCoordとnormalsのインデックスが格納されます.
FaceIndexクラスのメンバー変数は,

int faceN;
int *verIndex;
int *texIndex;
int *norIndex;

とし,faceNはこの面が何頂点で構成されているか,verIndexとtexIndex,norIndexはそれぞれvertices,textureCoordとnormalsのインデックスが格納されています.

用意したこれらに.objファイルから読みだしたものを格納していけば読み込み終了となります.
読み込みの関数はまた次回ということで.
PR

Trackbacks

TRACKBACK URL :

Comments

Comment Form