|
フラットシェーディングは面を一色で塗りつぶしましたが、 グローシェーディングでは、頂点ごとに色を設定して、 その間の色を補間するやりかたで面を塗ります。 頂点の色はどうやって設定するかというと、 頂点の法線を設定してその法線と光線ベクトルの内積から色を求めます。 んじゃぁ、頂点の法線はどうやって設定するかというと、 その頂点を共有する面の法線ベクトルの平均です。
-----------------------------------------------------------------------
//------------------------------------------------------
// 面の法線ベクトルを共有する頂点に足しこむ
//-----------------------------------------------------
void v_normal_add(shape_type shape,men_type men[],vertex_type vertex[])
{
for(int i=0; i<shape.number_of_tryangel; i++){
vertex_type v0,v1,v2;
v0=vertex[men[i].index[0]];
v1=vertex[men[i].index[1]];
v2=vertex[men[i].index[2]];
//面の法線を計算
men[i].vector.x= (v1.wy - v0.wy)*(v2.wz - v0.wz)-
(v1.wz - v0.wz)*(v2.wy - v0.wy);
men[i].vector.y= (v1.wz - v0.wz)*(v2.wx - v0.wx)-
(v1.wx - v0.wx)*(v2.wz - v0.wz);
men[i].vector.z= (v1.wx - v0.wx)*(v2.wy - v0.wy)-
(v1.wy - v0.wy)*(v2.wx - v0.wx);
//面を共有する頂点にその法線を足す
vertex[men[i].index[0]].normal.x += men[i].vector.x;
vertex[men[i].index[0]].normal.y += men[i].vector.y;
vertex[men[i].index[0]].normal.z += men[i].vector.z;
vertex[men[i].index[1]].normal.x += men[i].vector.x;
vertex[men[i].index[1]].normal.y += men[i].vector.y;
vertex[men[i].index[1]].normal.z += men[i].vector.z;
vertex[men[i].index[2]].normal.x += men[i].vector.x;
vertex[men[i].index[2]].normal.y += men[i].vector.y;
vertex[men[i].index[2]].normal.z += men[i].vector.z;
//後で、法線の平均を出すので足しこんだ回数を記憶する
vertex[men[i].index[0]].count++;
vertex[men[i].index[1]].count++;
vertex[men[i].index[2]].count++;
}
}
//------------------------------------------------------
// 足しこんだ平均の法線ベクトルを頂点にセット
//-----------------------------------------------------
void v_normal_set(shape_type shape,vertex_type vertex[])
{
for (int i=0;i < shape.number_of_vertices;i++){
//平均化する
if (vertex[i].count > 0){
vertex[i].normal.x /= vertex[i].count;
vertex[i].normal.y /= vertex[i].count;
vertex[i].normal.z /= vertex[i].count;
}
}
}
//------------------------------------------------------
// 法線をもとに、頂点にライティング処理を行って色をセット
//-----------------------------------------------------
void v_color_set(shape_type shape,vertex_type vertex[],struct vector eye)
{
for (int i=0;i < shape.number_of_vertices;i++){
//法線ベクトルを正規化
Normalize(vertex[i].normal);
//光源ベクトルを正規化
Normalize(eye);
//内積を求める
float naiseki = vertex[i].normal.x * eye.x+
vertex[i].normal.y * eye.y+
vertex[i].normal.z * eye.z;
//頂点の色を設定
vertex[i].R = (vertex[i].tempR+1)*(naiseki);
if(vertex[i].R >31)vertex[i].R=31;
if(vertex[i].R < 0)vertex[i].R=0;
vertex[i].G = (vertex[i].tempG+1)*(naiseki);
if(vertex[i].G >31)vertex[i].G=31;
if(vertex[i].G < 0)vertex[i].G=0;
vertex[i].B = (vertex[i].tempB+1)*(naiseki);
if(vertex[i].B >31)vertex[i].B=31;
if(vertex[i].B < 0)vertex[i].B=0;
}
}
-------------------------------------------------------------------
後はスキャンラインするときに、色も補間しながらその情報を書きこんでおきましょう。 そしてポリゴンを描く時に水平に色を補間してあげれば出来あがりです。 ![]() ↑フラットシェーディングの場合:カクカク ![]() ↑グローの場合:まったりなめらか 実行してみるとわかりますが、処理がクソ重いです。 原因は浮動小数点で色の算出をしているからです。(わかってるなら直せ) 賢い人は固定小数点で計算しましょう。 追伸 ソースがどんどん汚くなっています。気をつけてください。 grou_cube.zip[36kb] |