法線ベクトルの生成とスムージング

次は光源計算にいきたいところですが、メタセコイアのデータには法線ベクトルが含まれないためポリゴン形状から法線ベクトルを計算で求め、スムージングを行います。
メタセコイア以外の法線ベクトルが出力されるモデリングツールを使えばいいのですが、今後必要になるかもしれなので計算処理を作っておきます。

法線ベクトルの生成とスムージング
法線ベクトルの生成とスムージング


法線ベクトルの生成とスムージング

三角形ポリゴン

モデリングツールが出力するデータは多角形ポリゴンで構成されることが多いですが、処理を簡単にするため、すべて三角形に変換してから処理します。

法線ベクトルの計算

法線ベクトルは、外積を使って求めます。ベクトル計算はDirectXMathを使用。

//三角形ポリゴンの法線を求める
XMVECTOR TriangleNormal(XMVECTOR p0, XMVECTOR p1, XMVECTOR p2)
{
	XMVECTOR v10 = XMVectorSubtract(p1, p0);
	XMVECTOR v20 = XMVectorSubtract(p2, p0);
	XMVECTOR nor = XMVector3Cross(v10, v20);
	return XMVector3Normalize(nor);
}

法線のスムージング

法線スムージング(単純平均)
各頂点の法線をポリゴンの法線にすると角ばったシェーディングになってしまうため、スムージング処理を行います。まずは単純に平均化した法線を頂点の法線ベクトルにしてみます。
平均化する対象は、頂点を共有するすべてのポリゴンの法線、かつ法線ベクトル間の角度が一定以下もの。(角度はメタセコイアにスムージング角度を使用、facetチャンク)

法線のスムージング(単純平均)の結果

法線スムージング(単純平均)結果
やはり単純な平均化ではダメなようです。直線的な陰影になるはずだけどジグザグに。
原因究明と対策方法を考えます。

法線のスムージング(単純平均)の問題

法線スムージング(単純平均)の問題
陰影がジグザグになってしまう原因は、曲面を三角形ポリゴンで作成する際の分割方向の違いでした。図のように本来同じ方向になるべき法線が、ポリゴンの分割方向によって異なる向きになってしまいます。

法線のスムージング(重み付き平均)

単純な平均ではダメだったので、重み付きの平均に変更します。重みとして考えられる値は、ポリゴンの角度、面積など。とりあえず2つとも重みとして計算してみる。そのまま掛けると単位が異なるため、基準となるポリゴンの角度と面積で割った比率を重みとします。(図省略)
ss_dx11Model2-2
いい感じです。
もっと複雑なスムージングとして、周囲のポリゴンから曲線(スプライン曲線など)を求めて法線を求めるという方法を思いつきましたが、面倒なので却下。重み付き平均で十分。うまくいかない形状があったらその時考えます。

ポリゴンの角度と面積の計算

// 三角形ポリゴンの角度を求める
// ベクトルp1-p0とp2-p0の角度
float TriangleAngle(XMVECTOR p0, XMVECTOR p1, XMVECTOR p2)
{
	XMVECTOR v10 = XMVector3Normalize( XMVectorSubtract(p1,p0) );
	XMVECTOR v20 = XMVector3Normalize( XMVectorSubtract(p2,p0) );
	// 内積 v10・v20 = |v10||v20|cosθ
	// 正規化しているので|v10| = |v20| = 1
	XMVECTOR cs = XMVector3Dot(v10,v20);//cosθ
	return XMScalarACos( XMVectorGetX(cs) );//θ:2つのベクトルの角度
}

// 三角形の面積を求める
float TriangleArea(XMVECTOR p0, XMVECTOR p1, XMVECTOR p2)
{
	XMVECTOR v10 = XMVectorSubtract(p1, p0);
	XMVECTOR v20 = XMVectorSubtract(p2, p0);
	XMVECTOR cross = XMVector3Cross(v10, v20);
	// 外積の長さ=v10とv20で作られる平行四辺形の面積 
	// 半分にすると三角形の面積
	return XMVectorGetX( XMVector3Length(cross) )*0.5f;
}

サンプルプログラム

ダウンロード
法線ベクトル生成と簡単な光源計算

法線の生成とスムージング

zg_mqo.h/cpp

// 法線を計算で求める
bool ComputeNormal(MQOModel& mqo);

この関数でメタセコイアのデータから法線ベクトルの生成とスムージングを行います。中間データで生成を行うか迷いましたが、メタセコイア固有の問題なので中間データに変換する前に処理するようにしています。ポリゴンの三角形化は、データ解析時に実行済み。


リンクなど

3Dポリゴンモデラー

3Dポリゴンモデラー「メタセコイア」

スクリーンショットのモデルデータ

エナメルP/ハッチ作『ねんどろ風・初音ミク』
-enamel toy box-(一時閉鎖中 2013/3/28現在)
※サンプルプログラムには含まれません

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

認証:数字を入力してください(必須) * Time limit is exhausted. Please reload CAPTCHA.