2009年7月7日火曜日

テクスチャマッピン(*^ー゚)b グー...古いか..

昨日の続きです。

頂点や面についてはモデル(O)の行にそれぞれの数を出力して読み込む側で配列のサイズがわかるようにしてたんですが、画像ファイルについては、面の処理をしながら数えているので、モデル行に数が出力できません。一旦画像ファイルの数を数えてからモデル行を出力してもいいんですが、コードが冗長になってしまうので、C++の読み込む側で、配列じゃなくstd::vectorに読みながらつっこむようにしました。vectorを使えば予めサイズを知る必要がありません。配列を使ったり、vectorを使ったり一貫性が無い感じもしますが、まぁ、頂点や面は数が多いので速度重視で配列ということで...

I(画像)行の読み込みは次のような感じです。

/**
* 画像行の読み込み
*/
void Model::readImageLine(std::istream& in) {
std::string file;
in >> file;
if (in.fail()) {
std::cerr << "failed in reading image line" << std::endl;
return;
}
Image *img = new Image(file);
images.push_back(img);
}

imagesというのが画像の情報を保持するvectorです。Imageというのは画像の読み込み等を行うためのクラスです。次のようなメンバ関数をもっています。

bool Image::loadImage(const std::string& path) {
ilBindImage(image);
if (ilLoadImage(path.c_str())) {
width = ilGetInteger(IL_IMAGE_WIDTH);
height = ilGetInteger(IL_IMAGE_HEIGHT);
if(ilGetInteger(IL_IMAGE_ORIGIN) != IL_ORIGIN_LOWER_LEFT) {
iluFlipImage();
}
return true;
} else {
ILenum err = ilGetError();
std::cerr << iluErrorString(err) << std::endl;
return false;
}
}

imageはDevILのilGenImages()で確保した識別名です。これをバインドしてから、ilLoadImage()でファイルから読み込んでいます。自分の環境で読み込んだ画像が上下逆だったので、状態をみて、iluFlipImage()で反転させるようにしています。

実際に画像を出力する部分は次のような感じです。

void Model::draw() const {
// 面の数だけ繰り返し
for (unsigned int faceIdx = 0; faceIdx < numFaces; faceIdx++) {
Face *f = &faces[faceIdx];
bool useTexture;
// テクスチャの準備
if (f->imgIdx >= 0) {
glEnable(GL_TEXTURE_2D);
const Image *img = images.at(f->imgIdx);
img->setup();
useTexture = true;
} else {
glDisable(GL_TEXTURE_2D);
useTexture = false;
}
// 描画
if (f->mtlIdx >= 0) {
const Material *mtl = &materials[f->mtlIdx];
glColor3f(mtl->r, mtl->g, mtl->b);
}
glBegin(GL_QUADS);
std::vector<unsigned int>::iterator itv;
for (unsigned int i=0; i<f->numVerts; i++) {
FaceVertex* fv = &f->verts[i];
if (useTexture) glTexCoord2f(fv->u, fv->v);
Vertex *v = &vertices [fv->idx];
glVertex3f(v->x, v->y, v->z);
}
glEnd();
}
}

ちょっと長いですね。面に画像が割り当てられているかどうかに応じて、テクスチャをオンオフしてます。通常、あまり細かく面毎に画像を割り当てたりしない思うので、もう少し効率的にできると思います。要改善です。テクスチャ座標は面のFaceVertexという構造体に保持するようにして、この座標をglTexCood()に渡しています。

Image::setup()ではテクスチャの設定をしています。

void Image::setup() const {
ilBindImage(image);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, texName);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ilGetData());
}

ilGetData()で読み込んだ画像のポインタを得られるのでこれをglTexImage2D()に渡しています。

..ざっとですが、こんな感じです。画像とか扱いだすとやはりコード量も増えてきますね。乱雑な感じなのでちょっと整理せねば。
で、その後はいよいよボーンアニメーションに突入(の予定)です。

0 件のコメント: