3Dコンソールレンダラー

何もしませんか? 3D Console Software Renderingを書くだけですか?

猫へようこそ!

画像





今日は、最も単純な3Dレンダラーソフトウェアの作成方法を説明します。

最適化なし(この種のプログラムでは一般的です) 私の主な目標は、3Dレンダリングを高速化するのではなく、どのように行われるかを伝えることです。



この記事の形式では、使用するアルゴリズムの本質を説明することはできず、たとえば、変換マトリックスがこのように見え、他の方法ではない理由を説明することはできません。 そのような場合、検索キーワードまたはリンクを指定して、実行すべき内容を記述します。 理解して扱ってください:)

それでは、始めましょう:



はじめに



この場合、最も単純な3Dレンダラーには次のものが含まれます。



一般的な用語で、1つの三角形をレンダリングするためのアルゴリズムを説明します(この方法で、画面に表示される各三角形に対して繰り返されます)。

  1. 各頂点の座標を元の座標から画面に変換します。 このために、いわゆる 「同次座標」。 それが何であるかを知る必要はありません、ただそれを使用する方法を理解してください。 本質はこれです:各頂点に4番目の座標w = 1を割り当てます。 次に、3つの行列(World、View、Projection)を乗算し、座標x / w、y / w、z / wの頂点を取り、xおよびy座標を画面上の点の座標に線形に変換します(具体的な説明は以下に示します)
  2. 次に、画面上の3点のラスタライザーを使用して、三角形のすべての点の画面座標を取得し、各点に対してz検定を実行します。 Zテストは、画面上のポイントの深さと、表示するポイントの深さとの比較です。 出力ポイントがすでに存在するポイントより「遠く」にある場合、何も出力する必要はありません。 したがって、3Dオブジェクトを任意の順序で描画できます。どのオブジェクトが近いか、どれが遠いかを心配する必要はありません。 Zテストがある場合、すべてが自動的に判明します-最も近いオブジェクトが遠くのオブジェクトをカバーします。
  3. その後、画面にポイントを表示するだけです。 これを行うために、「ポイントの色」がカラーバッファーに記録され、その深さがzバッファーに記録されます。




ステップ1.カラーバッファーとzバッファー



今回のColorBufferとZBufferは、2つの80x25配列にすぎません(これはもちろん例であり、すべてコンソールのサイズに依存します)。 1つ目はコンソールキャラクターと、必要に応じてその色を保存します。 2番目は、各ピクセルの深度値です。 これは、floatまたはdouble —浮動小数点数である任意のデータ型です。 これをテンプレートクラスとして実装しました。テンプレートパラメータは、配列に格納されているデータ型です。



ステップ2.ラスタライザー



ラスタライズアルゴリズムは、座標x、y、zを使用して画面上の指定された3点からピクセル三角形を構築するために必要です。 これを理解して理解するには、 ru.wikipedia.org / wiki / Bresenham_algorithmを読んで線をラスタライズし、それを使用して三角形をラスタライズすることをお勧めします: compgraphics.info/2D/triangle_rasterization.php

これらの目的にはさまざまなアルゴリズムがあり、好きなものを使用してください。 主なことは、与えられたスクリーン座標に従って三角形/線のすべてのポイントを生成する機能が実装されることです(つまり、私にとっては、例えば、0..79、0..24の範囲になります)。

または、私が実装したものを使用することができます-ラインラスタライズ関数を使用する三角形ラスタライズ関数があります。これはポイントラスタライズ関数を呼び出し、zテストを実行して画面にポイントを表示します。 (卵の中の針、アヒルの中の卵など)

作業のロジックをトレースする方が簡単なので、作業の速度には注意を払いません。 もちろん自宅では、何かを最適化できます。



ステップ3.座標の変換



したがって、座標x、y、zを持つ点を3次元空間で与えます。

正しいModel-View-Projection変換を実行して3次元効果を作成する方法を紹介します。 先ほど言ったように、まず4次元のベクトル(x、y、z、1)を作成します

最初の変換はモデルです。 本質的に、これは単に座標系の平行移動/回転/圧縮/拡張または他の変換です。 オブジェクトを経時的に簡単に移動するために必要です。たとえば、オブジェクトはX軸を中心に10ミリ秒ごとに数度回転します。 したがって、モデルの座標をそのまま保存しますが、この回転を定義するマトリックスを変更するだけです。

最も単純な3次元変換マトリックスの例-転送、回転、圧縮。

したがって、より複雑な変換の場合は、構成を取得します。 ベクトルを列ベクトルとして表し、右側の行列で乗算します。 したがって、逆を行う必要がある場合-行列を転置し、異なる順序で乗算します。 行列自体の乗算の順序は重要であることに注意してください。オブジェクトを回転してから転送を行う場合は、転送行列に回転を乗算し、次にポイントの半径ベクトルの座標を乗算します。 結果のベクトルは、変換されたポイントの半径ベクトルになります。

マトリックスの例:

(Translation)

(x,y,z) -



1 0 0 x

0 1 0 y

0 0 1 z

0 0 0 1



/ (Scale)

(x,y,z) -

x 0 0 0

0 y 0 0

0 0 z 0

0 0 0 1

α (Rotate)

1 0 0 0

0 cos α -sin α 0

0 sin α cos α 0

0 0 0 1







他の軸を中心とした回転も同じ方法で行われます。左上の3x3サブマトリックスの対応する回転マトリックスを置き換えるだけです



任意の軸の周りの回転:OpenGLには、回転角度と軸(任意)の方向を入力できる機能があり、それ自体が回転行列を生成して乗算します。

この関数は回転行列を計算するだけなので、ここでは説明しません。 あなたはそれを自分で書くか、グーグルでグーグル(glRotateと呼ばれます)するか、私のソースからそれを取ることができます(私はすでにあなたのためにグーグルでグーグルをしています:)



次に、ビュー変換が実行されます。 これを説明する最も簡単な方法は、おそらく「カメラ」の概念を使用することです。 3次元のゲームをプレイした場合、これがゲームの世界とこの世界の空間でのカメラの向きを見るポイントであると想像するでしょう。 これを行うには、上記の逆の変換を実行する必要があります。 たとえば、ポイント(1,2,3)から世界を見る必要がある場合、転送(-1、-2、-3)を行う必要があります。 これは論理的です-3Dワールドのオブジェクトに座標(a、b、c)があることを想像してください。 その後、そのモデル行列は対応します-a、b、cを転送します。 同時にカメラが同じポイントから世界を見ると、ビューマトリックスは次のようになります:-a、-b、-cを転送し、その結果、View * Model *(x、y、z、1)を乗算すると、元の座標が取得されますオブジェクト-したがって、カメラはオブジェクトと同じ場所にあります。

カメラの向きを設定するには、まだ順番が必要です。 誰かの人生を複雑にしないために、単にgluLookAt関数をグーグル(この記事はすでに大きいので、ここにソースを投稿すべきではないと思います)またはソースを取得します-この関数もあります。 カメラ位置、視線方向、アップベクトルの特定の座標に対してビューマトリックスを生成します(このベクトルがないと、カメラの向きは明らかにあいまいになります)。

結果はどのような行列ですか? 何らかの初期座標系があり、移動/回転を行い、異なる座標系を取得すると想像してください。 この変換は、特定のマトリックスによって定義されます。 新しい座標系の開始点がカメラの位置と一致する場合、「z」軸は視線の方向に向けられ、「y」は上になり、ビュー変換行列はこの変換の逆行列になります。 もちろん、誰も逆行列を探していません-ViewMatrixを取得するためだけに、逆変換はすぐに行われます。



そして最後に、プロジェクション。 射影行列は、座標を可視性のピラミッド(錐台)から(遠近法を考慮して)単位立方体に変換します。その後、ポイントは既に画面に簡単に表示されます。

Frustumは、スクリーンに投影される世界の一部です。 これは、底辺に2つの三角形のある角錐台です。 画像

また、射影行列の構造については詳しく説明しません。パラメータznear、zfar(前面および背面のクリッピング平面)、fovy(垂直視野角)、およびaspectratio(カラーバッファの幅と高さの比-に依存することは明らかです)正方形は、長方形ではなく長方形の画面上の正方形のように見えました)。 Google関数gluPerspectiveまたはソースから取得します。



最終的に、変換は次のようになります:Projection * View * Model *(x、y、z、1)。 ベクトルの最終半径で、最初の3つの座標を4番目の座標で除算し、レンダリングとZテストの準備ができたポイントを取得します。



4.最終的な変換





すべてを画面座標に変換することは残っています。 マトリックス変換はポイントの座標を立方体[-1,1]に変換し、コンソールポイントの座標を0..79および0..24に変換したため、簡単な操作で正しい座標を設定する必要があります:(x + 1.0)* 0.5 * 80 and( y + 1.0)* 0.5 * 25。



ここで、z-testを実行する必要があります。 結果のz値が既存のz値よりも大きい場合、ピクセルを表示する必要はありません。 それ以外の場合は、カラーバッファーにピクセルの色の値を、zバッファーにそのz座標を書き込む必要があります。



それだけです! デモをダウンロードしてご覧ください!

LinuxおよびWindowsのアーカイブソースと実行可能ファイル



おわりに





この記事では、ソフトウェアレンダリングの最も簡単な方法について説明します。 もちろん、実際のプロジェクトでは多数の最適化が使用され、レンダリングプロセスははるかに複雑で、より多くの機能を備えています。



最後に、ubuntuコンソールの別のスクリーンショット:



画像







All Articles