財団名:三次元空間を表す

単一のピクセルが描画される前に、3Dエンジンは、オブジェクトを空間に記述するために数学的な言語を持っている必要があります。コアはのベクトル(位置、方向、または色を表す3つのコンポーネントのタプル)と[のマトリネス]の4×4配列(変換をエンコードする)です。Cでは、これらは、通常、単純に指示として定義されます::

  • 点とベクトルの
  • 列の順に格納された変形の行列のために。

オブジェクトは [ triangles で構成されます。三角形は、それぞれ位置で定義され、オプションで通常と色が異なります。これらを連続した配列(例、)として、キューブに対して保存すると、キャッシュの効率性が向上します。後でフレームごとに数千面の顔を処理する場合、重要な考慮事項です。

グラフィックパイプライン: 頂点からピクセルまで

グラフィックパイプラインは、3Dシーンデータを2Dイメージに変換する一連のステージです。 基本的なソフトウェアレンダリングエンジンでは、各ステージを手動で実行します。 主なフェーズは次のとおりです。

  1. Vertex Processing] - モデル、ビュー、および投影変換を適用します。
  2. []Rasterization] - 変形した三角形をフラグメント(ポテンシャルピクセル)に変換します。
  3. シェーディング] - 照明と材料に基づいて各フラグメントの色を計算します。
  4. []出力マージ] - 深さのテストを含むフレームバッファとフラグメントをブレンドします。

ハードウェアアクセラレーテッドエンジン(OpenGL、Vulkan、DirectX)は、GPUのほとんどのステップを実行しますが、ソフトウェアパスを理解することで、GPUがフードの下でどのように動作するかを深く理解できます。

頂点処理と変革

頂点は[モデルスペース(オブジェクトの相対座標)で始まります。 世界でそれを位置するために、翻訳、回転、スケーリングをエンコードするモデル行列]を適用する。 ]]]]ビュー行列]は、世界がカメラの相対座標(ビュー)に変換します[FLT:]]]。 [FLT:[FLT:]]]は、[FLT:[FLT:]フィールドを[F]フィールドを[F]、[F]フィールドを[F]、[F]、[[FLT]、[[F]フィールドを[F]、[[F]、[[FLT]フィールドを[F]、[[F]、[[F]、[[F]]]、[FLT]、[[F]、[[F]、[[F]]]]]]、[[F[F[F[F[F[F[F[F]]]]]]、[[F[F[F[F[F

Cでは、変換関数は以下のような機能があります。

  • [ – アイデンティティ行列を返します。
  • - 翻訳行列を作成します。
  • – X軸の周りの回転。
  • [ - 4 要素ベクトル(homogeneous座標)で 4×4 行列を乗じます。

ソフトウェアで同等の頂点シェーダーは、全ての頂点を反復し、それぞれを組み合わせて []] 行列で複数個数を掛け、変換された頂点バッファに結果を格納します。

予測: 視点対正性

投影は、画面上で深さが表現されるかを制御します。 ] の視点から、遠くのオブジェクトが小さくなるようにします。 その行列は、ビュー、アスペクト比、ほぼおよび遠くのクリッピング平面のフィールドから構築されます。 古典的な式は、z(行列の乗算後)によってxとyのコンポーネントを分割することを含みます。 Cでは、投影行列を一度に計算し、すべてのフレームを再利用します。

  • - 標準の視点行列を返します。

[ Orthographic projection]]は、並列行を保存し、UIやCADツールに使われるシンプルです。 視点の分裂は含まれていません。

rasterization: 満ちる三角形

投影後、2D画面座標(ピクセル位置)と深さ値(z)があります。 ラスタライゼーションは、各三角形を整数ピクセル座標をカバーするフラグメントに分割します。 古典的なアルゴリズムはのスカンリン変換です。

  1. y座標で三角形の3つの頂点を並べ替えます。
  2. 左端と右端を下ろし、各スキャンラインのX境界を計算します。
  3. 水平スパンの各ピクセルでは、三角形を横断してフラグメントの深さを計算します。
  4. の深さ test を実行します。 フラグメントの z を、深さバッファに既に値と比較します。 近い場合は、深さのバッファを更新し、フラグメントの色を計算します。

C で効率的なエッジウォークアルゴリズムを実装するには、タイトなループと固定ポイントの算術の慎重な使用が必要です。多くのホビリストエンジンは、ブルートフォースのアプローチから始まります(境界ボックス内のすべてのピクセルをチェック)、そしてエッジの式で後で最適化します。

シェーディングと照明

シンプルなフラットシェードエンジンは、顔のノーマルとシングル光源から計算された三角形当たりの単色を使用します。 ]]]Lambertianモデルは、拡散強度を与えます:[]]]。 Cでは、2つの三角形のエッジの交差製品として正常を計算します(その後、世界空間に頂点を変換)、その後、三角形のベースカラーで光強度を乗っ掛けます。

深さを追加するには、[]Gouraud shading(vertexの正常値、断片を渡る補間)または[Phong Shading](ピクセルの正常値)を実装します。 後者は、世界の位置と正常値を補う必要があります。その後、フラグメントごとの計算照明が高価で劇的に改善されます。

Cのエンジンの構築:実用的なステップ

ゼロからソフトウェア3Dエンジンを最小限に構築して歩こう。目標は、周囲の回転キューブと640×480ピクセルのウィンドウに拡散照明をレンダリングすることです。

ステップ1 - ピクセルバッファを設定する

フレームと深さのメモリバッファを定義します。と。フレームバッファを黒にクリアし、各フレームごとに1.0(ファープレーン)の深さバッファをクリアします。

ステップ2 - シーンデータを定義する

キューブでは、6面(12三角形)は12×3 = 36頂点を必要とします。 それらを位置(3フロート)と色(RGB用3フロート)でstructsの配列に保存します。 8つのユニークなキューブ角と6面の色を事前に定義します。 重複する頂点を避けるためにインデックスバッファを使用します。

ステップ3 - トランスフォーメーションパイプライン

各フレームは、モデル行列を角度(例、回転Y(時間))、原点を見ている固定カメラからのビュー行列、および投影行列から計算します。それらを単一のMVP行列に結合します。[]]]。[を乗じて、すべての頂点を変換します。その後、視点分岐(wで分割x、y、z)を実行して、正規化デバイス座標(--1〜+1)を取得するために、[FLT]を[FLT]]に変換します。[FLT]:[FLT]]]を[FLT]]]]]に変換します。[F]、[[FLT]]]、[F]]]]、[[F]]]]]、[[F]]]]]、[F]]]、[[F]]]]、[[F]]]]]]、[[F]、[[F]]]]、[[[[[[[[[[[[[[[FLT]]]]]]]]]]]]]]]]]]]]]]]]]]]

ステップ4 - レイスタライズとシェード

各三角形では、スキャンラインメソッドを使用します。 歩くピクセルは、深さを補い、また、世界空間位置(Phong)や頂点の正常(Gouraudの場合)などのパーバーテックス属性を補います。 ラムバートの拡散の式を適用します。 深さのテストが通過する場合、フレームバッファに最終色を書きます。

ステップ5 - ディスプレイ

SDL(Simple DirectMedia Layer)や、類似ライブラリを使用して、ウィンドウを作成し、フレームバッファを空白にします。例えば、SDL2:[]]、]]、 []]]、]、および []の各フレームで。

このソフトウェアパスはCPU上で実行されます。そのため、パフォーマンスはフレームごとに数千の三角形に制限されます。 快適にすると、Cで変換とシーンロジックを維持しながら、大作業をGPUにオフロードして、ラスタライゼーションレイヤーをOpenGLに置き換えることができます。

エンジンの最適化

基本エンジンは遅くなります。 リアルタイムのパフォーマンスには、いくつかの最適化が不可欠です。

  • [] バックフェイスの彫刻:[ カメラから離れた正規のポイントをスキップします。 投影された三角形の署名された領域を2Dで計算するか、ビューの方向で顔のノーマルのドット製品を確認してください。
  • フラストム culling: オブジェクトの境界ボックスを6面のビューフラストムに対してテストします。 完全に外に、オブジェクト全体をスキップします。
  • []固定ポイント算数:[]] は、整数の操作を、整数のループで整数で置換します。 多くのエンジンビルダーは、スキャンライン補間のために16.16固定ポイントを使用します。
  • []プリトランスフォームキャッシュ:[]]は、一度メッシュのすべての頂点を変換し、インデックスを使用して、複数の時間を変換しないでください。
  • ]ブロックされたフレームバッファが書きます:[ メモリオーダー(左から右、右上から下へ)でピクセルを書き込み、キャッシュがヒットする最大化します。

これら技術は、ソフトウェアのレンダラーを3〜5fpsから60fpsまで押し寄せ、適度な複雑さ(例えば、数百の三角形)のシーンを演出できます。

エンジンの拡張

固形基礎が存在すると、その機能が増分的に追加できます。

  • テクスチャマッピング:]] 2D画像を保存し、三角形の横にUV座標を補います。 滑らかな結果を得るためにバイリンガルフィルタリングを実行します。
  • 高度なシェーディング:[]] スペクトルハイライト(Blinn-Phong)、周囲のオクルージョン、または影マップを追加します。
  • シーン管理:]] は、オブジェクトが見えるかを迅速に判断するために、オクツリーまたはBSPツリーを使用します。
  • []ユーザインタラクション:]] キーボードとマウス入力を操作して、カメラを軌道にするか、オブジェクトをピックします。
  • []パイプライン抽象化:[]]シェーダーシステムの設計:関数ポインタとして頂点とフラグメント関数を定義し、再コンパイルなしで柔軟なレンダリングを有効にします。

リソースとさらなる読書

理解を深めるために、このエンジンを触発する古典的なテキストとオンラインチュートリアルを探索してください。

C の 3D エンジンをビルドすることは、グラフィックスプログラマのための通路の儀式です。 それは、効率的なコードを書くだけでなく、パフォーマンスクリティカルシステムを構成する3次元で考える方法だけでなく、あなただけを教えます。 単一の回転キューブから始め、さらには、三角形、テクスチャを追加し、最終的に GPU にオフにします。 未加工 C からフル機能エンジンへの旅は、画面上のすべてのピクセルの背後にある魔法を明らかにします。