現在地: メニュー >> 実践編10 >> 実践編10::3dsファイルローダ >> lib3ds編04
INDEX: lib3ds編03 << lib3ds編04 >> lib3ds編05?

材質データ


材質データは「Lib3dsFile構造体」のメンバ「int nmaterials」が設定されているマテリアルの数を示す。
具体的なデータは「Lib3dsFile構造体」→「Lib3dsMaterial構造体」の中にある。

そのなかのメンバには
  • char name[64]:材質の名前
  • float ambient[3]:環境光
  • float diffuse[3]:拡散光
  • float specular[3]:スペキュラ光
  • float shininess:輝度係数
  • float transparency:透明度(「1-transparency」でdiffuseのアルファ値)
などがある。

材質データを取り出す


材質データを取り出す時は次のような感じ。
Lib3dsFile *m_model;
Lib3dsMesh *mesh;
… …
//データ構造
struct Materials
{
	float	ambient[4];
	float	diffuse[4];
	float	specular[4];
	float	shininess;
};
std::vector<Materials> materials;
… …
//マテリアルが無い場合は終了
if(m_model->nmaterials == 0)
{
	return -1;
}

//マテリアルデータの取り出し
Lib3dsMaterial *material;
			
//メモリ確保
materials.resize(m_model->nmaterials);
for(int loop = 0; loop < m_model->nmaterials;++loop)
{
	material= m_model->materials[loop];//loop番目のマテリアル
	std::cout << material->name << " - ";//マテリアル名

	//ambient
	memcpy(materials[loop].ambient, material->ambient, sizeof(material->ambient) );
	materials[loop].ambient[3] = 1;
		
	//diffuse
	memcpy(materials[loop].diffuse, material->diffuse, sizeof(material->diffuse) );
	materials[loop].diffuse[3] =1 - material->transparency;
		
	//shinness
	memcpy(&materials[loop].shininess, &material->shininess, sizeof(material->shininess) );
	if ( materials[loop].shininess == 0.01f)
	{
		materials[loop].shininess = 20.f;
	}else
	{
		materials[loop].shininess *= 128;
	}

	//specular
	memcpy(materials[loop].specular,material->specular,sizeof(material->specular) );
	materials[loop].specular[3]=1;

}

【解説】
モデルによっては、材質そのものを設定していないものもある。
そのような場合は「retrun」等して処理をカット。

「GLC-Player」で確認したところ、shinness = 0.01fの時は、「shinnessに20.0を設定する」といい。
その他の時には128をかけてスケール変換しておく。「glMaterial関数」に渡すため。

OpenGLの材質のアルファ値は、diffuseのみが計算に使用されるので、他は「1」でよい。

マテリアルを適用する

マテリアルの情報は面単位で持っている。
すなわち、
「Lib3dsFile構造体」→「Lib3dsMesh構造体」→「Lib3dsFace構造体」のメンバ「int material」
に何番目のマテリアルを適用するのかという情報が格納されている。
Lib3dsFile *m_model;
Lib3dsMesh *mesh;
int materialId;//マテリアルの管理用(材質が無い場合は-999が入っているものとする)
… …
//メッシュ単位でのループ
for(int mLoop = 0; mLoop < m_model->nmeshes;++mLoop)
{
	mesh = m_model->meshes[mLoop];//mLoop番目のメッシュへのポインタ

	//面単位でのループ
	for(int loopX = 0;loopX < mesh->nfaces;++loopX)
	{
		//マテリアル設定が全くない場合はカット
		if(materialId != -999){
			materialId = mesh->faces[loopX].material;//Id取得
			if(materialId >=0){
				glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, materials[ materialId ].ambient); //面がもつ材質IDを指定する
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, materials[ materialId ].diffuse);
				glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materials[ materialId ].specular);
				glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, materials[ materialId ].shininess);
			}else
			{
						/*マテリアル設定がない時は適当に設定*/
			}
		}
		… …
	}
}

【メモ】

「Lib3dsFile構造体」→「Lib3dsMesh構造体」→「Lib3dsFace構造体」のメンバ「int material」が「−1」の時は、
材質設定が行われていない。
たぶんテクスチャマッピングだけをしている。

描画する

glBegin/glEndだとこんな感じ
【例】
Lib3dsFile *m_model;
Lib3dsMesh *mesh;

//法線格納場所
struct MeshNormal
{
	float (*vertnormals)[3];
};
std::vector<MeshNormal> meshNormalAry;


//材質データ格納用
struct Materials
{
	float	ambient[4];
	float	diffuse[4];
	float	specular[4];
	float	shininess;
};
std::vector<Materials> materials;

//デフォルト材質
Materials MatDefault=
{
	{0.2f, 0.2f, 0.2f, 1.f},
	{0.8f, 0.8f, 0.8f, 1.f},
	{0.f, 0.f, 0.f, 1.f},
	0.f
};

int materialId;//マテリアルの管理用
… …

//メッシュ単位でのループ
for(int mLoop = 0; mLoop < m_model->nmeshes;++mLoop)
{
	mesh = m_model->meshes[mLoop];//mLoop番目のメッシュへのポインタ

	//面単位でのループ
	for(int loopX = 0;loopX < mesh->nfaces;++loopX)
	{
		//マテリアル設定が全くない場合はカット
		if(materialId != -999){
			materialId = mesh->faces[loopX].material;
			if(materialId >=0){
				glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, materials[ materialId ].ambient); //面がもつ材質IDを指定する
				glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, materials[ materialId ].diffuse);
				glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materials[ materialId ].specular);
				glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, materials[ materialId ].shininess);
			}else
			{
				glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, MatDefault.ambient);
				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);
		//1頂点目
		glNormal3f(
			meshNormalAry[mLoop].vertnormals[loopX*3][0],
			meshNormalAry[mLoop].vertnormals[loopX*3][1],
			meshNormalAry[mLoop].vertnormals[loopX*3][2]);
		glVertex3f(
			mesh->vertices[ mesh->faces[loopX].index[0] ][0],
			mesh->vertices[ mesh->faces[loopX].index[0] ][1],
			mesh->vertices[ mesh->faces[loopX].index[0] ][2]);

		//2頂点目
		glNormal3f(
			meshNormalAry[mLoop].vertnormals[loopX*3+1][0],
			meshNormalAry[mLoop].vertnormals[loopX*3+1][1],
			meshNormalAry[mLoop].vertnormals[loopX*3+1][2]);
		glVertex3f(
			mesh->vertices[ mesh->faces[loopX].index[1] ][0],
			mesh->vertices[ mesh->faces[loopX].index[1] ][1],
			mesh->vertices[ mesh->faces[loopX].index[1] ][2]);

		//3頂点目
		glNormal3f(
			meshNormalAry[mLoop].vertnormals[loopX*3+2][0],
			meshNormalAry[mLoop].vertnormals[loopX*3+2][1],
			meshNormalAry[mLoop].vertnormals[loopX*3+2][2]);
		glVertex3f(
			mesh->vertices[ mesh->faces[loopX].index[2] ][0],
			mesh->vertices[ mesh->faces[loopX].index[2] ][1],
			mesh->vertices[ mesh->faces[loopX].index[2] ][2]);
		glEnd();
	}

}

【メモ】

glMaterialで頻繁に状態を切り替えるので効率が良くない。
本当は別の方法でやるべき。

サンプルコード

目次

― その他 ―

Wiki内検索

計測中...(07.10.8〜)

Save The World






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


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

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