チュートリアル > 頂点レンダラーの開発 |
このチュートリアルでは、3 次元空間のオブジェクトを 2 次元のイメージに変換するという、レンダリングの基本を説明します。これを簡単で高速 (リアルタイム) に行うため、スクリプトでは頂点だけを描画します。イメージはビューポートが更新されるたびに再描画します。 つまり、ビューの変更、パン、ズーム、軌道周回を行うと、頂点レンダラーはそれをすぐに反映します。
アクティブ ビューポート情報、タイプ、および変換へのアクセス
まず VertexRender という名前の MacroScript を定義することから始めます。 これは[HowTo]カテゴリに表示されます。この macroScript は、 on execute do や on is Checked do というイベント ハンドラを持つ高度なものです。
レンダラーがアクティブになっているかどうかを示すフラグを保持するローカル変数を定義します。この変数は最初は false に設定されます。
イメージの幅と高さ、およびフロント バッファとバック バッファという 2 つのビットマップ (詳細は後述) を保持するローカル変数も定義します。
これは、レンダラーが使用可能状態になってビューポートが更新されるときに実行される関数です。
レンダリング スピードについて情報を出力するために、timestamp 関数を使用して現在のシステム時間を取得します。
バック バッファをフロント バッファにコピーし、こうして前のイメージをクリアします。バック バッファにバックグラウンド イメージを入れ、この関数でその上に描画することもできます。ここでは、バック バッファのイメージは黒に設定されています。
シーンのジオメトリ オブジェクトでライトやカメラなどのターゲット オブジェクトではないものすべてについて、ループを繰り返し実行します。このとき、オブジェクトが非表示であるかどうかについてはチェックしないことに注意してください。この点については、練習を兼ねてコードに追加してもかまいません。 ここでは、非表示のものも含め、すべてのオブジェクトを描画します。
オブジェクトをメッシュとしてメモリ内にスナップショットを取ります。これには、オブジェクトに適用されたすべてのモディファイヤとスペース ワープも含まれます。
頂点をペイントするために使用する配列を定義し、描画にワイヤフレーム カラーを使用します。
処理を高速化するため、メッシュ内の頂点の読み込みは 1 回にします。頂点のループを制限するには、次の値を使用します。
v 番目の頂点の位置はビューポートの変換行列によって乗算される必要があります(カメラ ビューポートの場合、viewport.getTM() ではカメラの変換行列の逆行列が返されます。パース ビューポートまたは正投影ビューポートの場合はすでに逆行列になっています)。この行列で頂点位置を乗算すると、3 次元空間の座標がカメラ空間に変換されます。
ここで、レンダリングするイメージが現在の頂点の奥行きで配置されたときのピクセル サイズに相当する投影面のサイズが必要になります。これを計算するには、この面の 2 つの終点(左上と右下)をカメラ空間の 3 次元ポイントとして得る必要があります。
thePos はすでにカメラ座標にあるため、.Z 座標はポイントの Z 深度になります。 mapScreenToView の戻り値は、投影面の左上隅に対応するカメラ空間の 3D ポイントです。
ご存知のとおり、カメラではカメラ位置を頂点とする円錐 (角錐台) ができます。投影面をカメラの Z 軸に沿って「移動」させると、投影面が「目」から離れるほどワールド単位での大きさは大きくなりますが、最終的なイメージ内のピクセル数は変わりません。
スクリーンショットには、カメラと 2 つの投影面 (赤の X) が示されています。また、カメラから離れるほど、投影面が拡大していくのもわかります。
最も離れた投影面は、カメラ空間でのティーポットの位置の奥行きにちょうど位置します。
この投影面の左上隅の赤の球は、先に計算した screen_origin の座標に対応します。このイメージを作成するために、 screen_origin の値が計算され、次に MAXScript の次のコード行が呼び出され、
そのポイントを表す球がワールド座標内に作成されます( screen_origin は最初はカメラ空間にあり、カメラの変換行列で乗算することにより、ワールド座標に変換されます)。
青色の球も同様で、 end_screen の座標を表しています。
ビューをレンダリングすると、カメラからは次のように見えることになります。 赤と青色の球がちょうど予想どおりの場所に現れることがわかります。
これで投影面の 2 つの終点が判明したため、投影面の幅と高さをワールド単位で計算できます。投影面のピクセル単位のサイズもわかっているので、ピクセルとワールド単位の間の関係も割り出すことができます。
投影面のサイズを使用して、アスペクトの値を計算します。 これは基本的に、X 軸および Y 軸に沿ったワールド単位 1 に対するピクセル数になります。
screen_coords= point2 (x_aspect*(thePos.x-screen_origin.x)) (-(y_aspect*(thePos.y-screen_origin.y)))
アスペクトの値を使用して、頂点位置の X と Y の値を実際のピクセル位置に変換します。Y 座標が反転されていることと、X の位置が screen_origin でオフセットされていることに注意してください。 カメラの軸 (イメージの中心) が座標[0,0]にあるのに対し、MAXScript でのイメージの位置が左上隅にあるためです。
フロント バッファの現在の頂点位置にピクセルを描画します。 ワイヤフレーム カラーを使用して先に定義した、カラー配列を使用します。
すべてのオブジェクトのすべての頂点の処理が完了したら、表示を更新します。
この macroScript をツールバー、メニュー、またはクアッドメニューに置くとき、そのチェック状態は最初に定義したローカル変数に格納されたブール値によって決まります。
変数の状態が逆になります。 true であれば false になり、false であれば true になります。
[シーンをレンダリング](Render Scene)ダイアログ ボックスの現在のサイズ値を読み込みます。これらの値を固定値 (320 と 240 など) で置き換え、レンダラーの設定とは関係なく決まったサイズにすることもできます。
これらのサイズ値を使用して 2 つのビットマップを定義します。1 つ目のビットマップは、描画の前にイメージをクリアするために使用するバック バッファです。また、ここで openBitmap の呼び出しを使用し、ディスクからバックグラウンド イメージをロードして上に描画することもできます。
先にビューポート再描画のコールバック関数として定義した関数を登録します。この関数は 3ds Max のビューポートの再描画のたびに呼び出され、レンダリングされたイメージを更新します。