フラットシェーディング

シェーディングとは、3次元で光を表現する技術のことで、物体の「陰」の処理を行います。
要するに、面に光があたると面の色が明るくなって、逆に光があたらないと暗くなる処理のことです。
つまり物体からの反射光の演出を行います。
空を見上げて、「今日も太陽がまぶしいぜ」ってことではありません。

どうすれば良いか?
まず、面の法線ベクトルを求めます。
法線ベクトルは面に垂直なベクトルのことです。
んで、この法線ベクトルを正規化します。(長さを1にする)
次に光線ベクトルを設定します。
今回は視点の位置と同じにしました。
ちなみに光の減衰処理は行っていません。
んで、この光線ベクトルもまた正規化します。(長さを1にする)

正規化の式はこんな感じ。
a=sqrt(nx*nx+ny*ny+nz*nz);
 nx/=a;
 ny/=a;
 nz/=a;

求めた法線ベクトルと光線ベクトルの内積を求めます。
ちなみにどちらも正規化しているので、その内積の値がそのままcosθの値になります。
あとは内積の値を元に、面の色を設定すれば出来あがりです。

「面に当たる光の強さは、正規化された光線ベクトルと法線ベクトルの内積」
ということを覚えましょう。
θが0のとき、内積(=cosθ)が1で光の強さは最大。
θが90のとき、内積(=cosθ)が0で光はまったく当たらないということになります。
----------------------------------------------------------------
//-----------------------------------------------------------------------------
//               フラットシェーディング
//-----------------------------------------------------------------------------
void flatshadeing(struct shape_type p,struct men_type *men,struct vector eye)
{
	vertex_type *v0,*v1,*v2;
	v0=&p.vertex[men->index[0]];
	v1=&p.vertex[men->index[1]];
	v2=&p.vertex[men->index[2]];
	
	//面の法線を計算
	men->vector.x=	(v1->wy - v0->wy)*(v2->wz - v0->wz)-
			(v1->wz - v0->wz)*(v2->wy - v0->wy);

	men->vector.y=	(v1->wz - v0->wz)*(v2->wx - v0->wx)-
			(v1->wx - v0->wx)*(v2->wz - v0->wz);
	
	men->vector.z=	(v1->wx - v0->wx)*(v2->wy - v0->wy)-
			(v1->wy - v0->wy)*(v2->wx - v0->wx);
	//視線ベクトルを単位行列化
	Normalize(eye);

	//面の法線を単位行列化
	Normalize(men->vector);

	//内積を求める
	float naiseki = men->vector.x * eye.x+
			men->vector.y * eye.y+
			men->vector.z * eye.z;

	//内積イコォルcosθ
	float cosSITA = naiseki;

	//面の色を設定
	men->R = (unsigned int)( (men->tempR+1)*(cosSITA));
	if(men->R >31)men->R=31;
	if(men->R < 0)men->R=0;
	men->G = (unsigned int)( (men->tempG+1)*(cosSITA));
	if(men->G >31)men->G=31;
	if(men->G < 0)men->G=0;
	men->B = (unsigned int)( (men->tempB+1)*(cosSITA));
	if(men->B >31)men->B=31;
	if(men->B < 0)men->B=0;

}
----------------------------------------------------------------------

↑マウスでドラッグしてみてください。
面が正面を向くと明るくなります。
flat_cube.zip[33kb]