2008年03月17日

X形式のファイルの書き出し その3 modo 301

前回はマテリアルを吐き出せるようにしたので、今回は懸案だった法線のスムーシングを何とかしてみたい。

modoのポイントから得られる法線ベクトル情報はそのポイントを共有するポリゴンの法線ベクトルの平均値のようだ。そしてそれをそのままXファイルで書き出しちゃうと、どのエッジもスムース処理されてヌルヌルなメッシュになってしまう。

modoではポリゴンメッシュをカクカクな多面体に見せるのか、それともツルンとした曲面に見せるのかはそのポリゴンのマテリアルの「スムーシング」と「スムーシング角度」で設定するようになっている。パラメータ「スムーシング」はON/OFFじゃなくてパーセンテージで設定できて、100%を超えることもマイナスに設定することも出来てややこしいので今回はパスして「スムーシング角度」のみ扱うことにしておく。

その「スムーシング角度」パラメータはポイントを共有するポリゴンの法線ベクトルが成す角度がこの設定値を下回った時に、該当するポリゴングループの法線ベクトルの平均値をシェーディング用の法線とするようにするための閾値だ。

fig01CGの陰影はライトからの光線とそれが当たる場所の法線ベクトルから基本的に計算される。だから平らなポリゴンでも表面の法線ベクトルが変化すればポリゴン上の陰影が変化して凹凸があるように見せかけることが出来る。これがバンプマップの原理だったわけだ。

fig02ポリゴンのスムーシングはこの法線ベクトルを滑らかに変化させることで滑らかな曲面に見せる手法で、ポリゴンとポリゴンの境界部分で2つのポリゴンの法線ベクトルが同じになれば2つのポリゴンは陰影の境目が無く滑らかに繋がって見えるわけだ。そこで境界線上の法線ベクトルを両方のポリゴンの法線ベクトルの平均値にって話しになってくるわけだ。

fig03でもマテリアル単位でそのスムーシング角度は変更できるので、片方のポリゴンはスムーシングされた法線ベクトルになって、もう一方のポリゴンはスムージングされない法線ベクトルになる事もあるので、シェーディングのための法線ベクトルはポイント1つに1つ決まるんじゃなくて、ポイント1つに対してそのポイントを共有するポリゴンの数ぶんだけ必要になるわけだ。だからポイントに設定されている法線ベクトルを単純にクエリしただけじゃ取得出来ないわけだな。

さてそこでまず、マテリアルに設定されているスムーシング角度を取得しなくちゃならないんだけど、これも残念な事にマテリアルからクエリで取得することは出来ない。だからこれもマテリアルアイテムを探し出してそのアイテムIDで以下のコマンドから引っ張ってこないとならない。

item.channel advancedMaterial$smAngle ? item:アイテムID

特定のマテリアルグループにどんなアイテムが設定されているかは以下のクエリで取得出来るんだけど、

query layerservice material.textures ? マテリアルインデックス

覆いかぶさって機能していないマテリアルも取得出来ちゃうので、有効なマテリアルを取得するのは結構大変だ。順番としてはシェーダーツリーの下から順にタプルに入ってくるのでリスト化してreverse()メソッドで反転して先頭から順に見て行って最初に出て来た「advancedMaterial」をこのマテリアルグループのマテリアル設定として採用する事にしてある。

こうして得られたスムーシング角度を法線のブロックを生成する時に使っている。メッシュはポリゴン単位で処理するようにしてあって、最初に選択されたアイテムに入っているポリゴンリストを取得し、そのポリゴン1つ1つに対して以下のクエリで

query layerservice poly.vertList ? ポリゴンインデックス

そのポリゴンに属するポイントのリストを取得し、そのポイント1つ1つに対して位置や所属ポリゴン、今となっては不要となったポイントの法線ベクトルやスムーシング角度をまとめてリスト化してあるので、法線ベクトルのブロックを生成する時はそのリストに登録されているポイントごとにポイントインデックスとポリゴンインデックスとスムーシング角度を取り出して来て、そのポリゴンの法線ベクトルと接続するほかのポリゴンの法線ベクトルが成す角がスムーシング角度より小さいかどうかで取捨選択し、スムーシング角度より小さい角度のものだけ集めて法線ベクトルの平均値を取ってそれをそのポイントの法線ベクトルとして書き出すようにした。

このポイントによって繋がっているポリゴンのリストは、

query layerservice vert.polyList ? ポイントインデックス

によって求められ、そのポリゴンの法線ベクトルは、

query layerservice poly.normal ? ポリゴンインデックス

で求められる。法線ベクトルどうしの成す角は2つのベクトルの内積を計算してcos()の逆関数acos()を使って求めた。

ベクトルの内積


法線ベクトルは長さが1の単位ベクトルとして取得出来るので、2つのベクトルの内積はそのまま2つの角度のコサインになるわけだ。ただ、Pythonの数値計算は誤差を含むので、単位ベクトルどうしの内積なんだけど1を超える場合があって、そのままacos()に渡すとエラーになるので1より大きい値は角度が0ラジアンと決めてしまった。

スムーシングが閾値で変えられるようになった

まあそんなこんなで何とかスムーシングの処理も組み込む事が出来たよ。次はUVマップかな。

それではまた次回。

スクリプトまとめページ( Down Load はこちらから)  

カテゴリー別ページ 



take_z_ultima at 12:35│Comments(0)TrackBack(0)modo | CG

トラックバックURL

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 

Archives