現在地: メニュー >> 実践編10 >> 実践編10::3dsファイルローダ >> lib3ds編04 >> lib3ds編04_2

材質別に描画する


lib3ds編04::まとめコード1のように、面ごとに材質を切り替えていては効率がよくない。
材質毎にポリゴンをまとめて描画すれば、より効率的である。

データ構造


例えば次のようなデータ構造を用意する。
【例】
//メッシュごとの対応インデックス
struct MeshIndex
{
	std::vector<int> faceId;
};

//材質データ格納用
struct Materials
{
	float	ambient[4];
	float	diffuse[4];
	float	specular[4];
	float	shininess;
	std::vector<MeshIndex> meshIdx;
};
つまり、「材質A」には、各種光源パラメータの他に、
『メッシュ1の中で材質Aを使用する面番号』、『メッシュ2の中で材質Aを使用する面番号』…
という感じになっている。

すると、『2つ目材質を使用するメッシュ4における面番号』は
std::vector<Materials> materials;
materials[1].meshIds[3].faceid[loop] (※loop = 0,1,2,3,...)
とアクセスできる。

面番号を振り分ける


【例】
Lib3dsFile *m_model;
Lib3dsMesh *mesh;
… …
std::vector<Materials> materials;//材質データ構造
Materials MatDefault;//デフォルト用
… …
//材質データ構造に対応するメッシュデータIDを格納する
static int MatId = 0;
for(int k = 0; k < m_model->nmeshes;++k)
{
	mesh = m_model->meshes[k];//k番目のメッシュ
	for(int i = 0; i < mesh->nfaces; ++i)
	{
		MatId = mesh->faces[ i ].material;
		if(MatId == -1) //材質設定の有無で分岐
		{
			MatDefault.meshIdx[k].faceId.push_back( i );
		}else
		{	 
			materials[MatId].meshIdx[k].faceId.push_back( i );
		}
	}
	… …
}

描画する


描画の際は、
[材質ループ]→[メッシュループ]→[面番号ループ]
という3重ループ。

【例】
Lib3dsFile *m_model;
Lib3dsMesh *mesh;
… …
std::vector<MeshNormal> meshNormalAry;//法線データ格納用
std::vector<Materials> materials;//マテリアルデータ格納用
Materials MatDefault;//デフォルトマテリアル用
… …

static std::vector<int>::iterator Iter;
static std::vector<int>::iterator EndIter;
		
for(int k = 0; k < m_model->nmaterials;++k)//材質ループ
{
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, materials[ k ].ambient); 
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, materials[ k ].diffuse);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materials[ k ].specular);
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, materials[ k ].shininess);
		
	glBegin(GL_TRIANGLES);
	for(int n = 0 ; n < m_model->nmeshes;++n)//メッシュループ
	{
		mesh = m_model->meshes[ n ];
		EndIter = materials[k].meshIdx[n].faceId.end();
			
		for(Iter = materials[k].meshIdx[n].faceId.begin(); Iter != EndIter;++Iter)//インデックスループ
		{
			glNormal3fv( &meshNormalAry[n].vertnormals[ (*Iter)*3 ][0]  );
			glVertex3fv(&mesh->vertices[ mesh->faces[ (*Iter) ].index[0] ][0]);

			glNormal3fv( &meshNormalAry[n].vertnormals[ (*Iter)*3+1 ][0]  );
			glVertex3fv(&mesh->vertices[ mesh->faces[ (*Iter) ].index[1] ][0]);

			glNormal3fv( &meshNormalAry[n].vertnormals[ (*Iter)*3+2 ][0]  );
			glVertex3fv(&mesh->vertices[ mesh->faces[ (*Iter) ].index[2] ][0]);
		}
	}
	glEnd();
}
	
//材質見設定部分を描画
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, MatDefault.ambient); //面がもつ材質IDを指定する
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MatDefault.diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, MatDefault.specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, MatDefault.shininess);
glBegin(GL_TRIANGLES);
for(int n = 0 ; n < m_model->nmeshes;++n)
{
	mesh = m_model->meshes[ n ];//n番目のメッシュ + 材質がk番目のものが対象
	EndIter =MatDefault.meshIdx[n].faceId.end();
	for(Iter = MatDefault.meshIdx[n].faceId.begin();Iter != EndIter;++Iter)
	{
		glNormal3fv( &meshNormalAry[n].vertnormals[ (*Iter)*3 ][0]  );
		glVertex3fv(&mesh->vertices[ mesh->faces[ (*Iter) ].index[0] ][0]);

		glNormal3fv( &meshNormalAry[n].vertnormals[ (*Iter)*3+1 ][0]  );
		glVertex3fv(&mesh->vertices[ mesh->faces[ (*Iter) ].index[1] ][0]);

		glNormal3fv( &meshNormalAry[n].vertnormals[ (*Iter)*3+2 ][0]  );
		glVertex3fv(&mesh->vertices[ mesh->faces[ (*Iter) ].index[2] ][0]);
	}
}
glEnd();

サンプルコード


次>>lib3ds編04_3(頂点配列を使う)

目次

― その他 ―

Wiki内検索

計測中...(07.10.8〜)

Save The World






▲よろしければ広告のクリックもお願いします


▲ランキングに参加しました

管理人/副管理人のみ編集できます