
ピッチ:-10 °
ヨー角:-10 °
視野角:80 °
コンピュータグラフィックスにおいて、キューブマッピングとは、立方体の6つの面をマップ形状として使用する環境マッピング手法である。環境は立方体の側面に投影され、6つの正方形テクスチャとして保存されるか、あるいは1つのテクスチャを6つの領域に展開して保存される。
キューブマップは、まず視点からシーンを6回レンダリングすることによって生成され、各ビューは各キューブ面を表す90度の視錐台によって定義されます。 [ 1 ]または、環境が最初に球面に投影されているとみなされる場合、キューブの各面はそのグノモニック投影です。
ほとんどの場合、キューブマッピングは従来の球体マッピングよりも好まれます。なぜなら、キューブマッピングは、画像歪み、視点依存性、計算効率の悪さなど、球体マッピングに内在する多くの問題を解消するからです。また、キューブマッピングは、球体マッピングに比べて反射のリアルタイムレンダリングをサポートする能力がはるかに優れています。球体マッピングは、非効率性と視点依存性の組み合わせにより、視点が常に変化する場合には適用が著しく制限されるためです。
キューブマッピングのバリエーションは、360度ビデオプロジェクションでもよく使用されます。[ 2 ]
キューブマッピングは、ジム・ブリンとマーティン・ニューウェルが環境マッピングを初めて提唱してから10年後の1986年に、ネッド・グリーンが論文「環境マッピングとワールドプロジェクションのその他の応用」 [ 3 ]で初めて提案しました。しかし、6つのテクスチャ画像に同時にアクセスできるハードウェアの制限により、さらなる技術開発なしにはキューブマッピングを実装することは不可能でした。この問題は、1999年にNvidia GeForce 256がリリースされたことで解決されました。Nvidiaは、ハードウェアでのキューブマッピングを「GeForce 256の画期的な画像品質機能であり、開発者が正確なリアルタイム反射を作成できるようにする。ハードウェアで高速化されたキューブ環境マッピングにより、開発者は反射と鏡面照明効果を使用して興味深く没入感のある環境を作成する創造性を解放する」[ 4 ]と宣伝しました。今日でも、キューブマッピングはさまざまなグラフィックアプリケーションで環境マッピングの好ましい方法として使用されています。
キューブマッピングは、その比較的シンプルな構造から、他の環境マッピング手法よりも好まれています。また、キューブマッピングはレイトレーシングで得られる結果と類似した結果をもたらしますが、計算効率ははるかに優れています 。品質はやや低下するものの、効率性が大幅に向上することでその差は十分に補われます。
キューブマッピングよりも前に開発された球体マッピングには、多くの固有の欠点があり、ほとんどのアプリケーションでは実用的ではありませんでした。球体マッピングは視点に依存するため、視点ごとに異なるテクスチャが必要になります。したがって、視点が移動するアプリケーションでは、新しい視点ごとに新しい球体マッピングを動的に生成するか(または、すべての視点に対してマッピングを事前に生成する)、マッピングを作成する必要があります。また、球体の表面にマッピングされたテクスチャは伸縮する必要があり、その結果として歪みや変形(特に球体の縁に沿って)が発生します。これらの画像上の欠点は、「事前ストレッチ」などの特定のテクニックを使用することで軽減できますが、これは球体マッピングにさらに複雑さを加えるだけです。
放物面マッピングは球面マッピングの限界をある程度改善するものの、特殊な画像変形処理とより複雑な計算に加えて、2回のレンダリングパスが必要となる。
一方、キューブマッピングはレンダリングパスが1回だけで済み、そのシンプルさから開発者にとって理解しやすく、生成も容易です。また、球体マッピングや放物面マッピングとは異なり、キューブマッピングはテクスチャ画像の解像度全体を使用するため、同じ品質を得るために低解像度の画像を使用することが可能です。キューブマップの継ぎ目の処理は課題となりますが、継ぎ目の挙動を処理し、シームレスな反射を実現するアルゴリズムが開発されています。
欠点としては、不連続性、インデックス付けの多さ、ベクトルの線形補間(ハードウェアで計算する場合)、テクスチャマップ境界をまたいだフィルタリング、そして複数のテクスチャが必要になる可能性などが挙げられる。[ 5 ]
コンピュータ支援設計(CAD)プログラムは、 3Dオブジェクトをレンダリングする際に、表面の曲率感を伝える視覚的な手がかりとして鏡面反射光を使用します。しかし、多くのCADプログラムでは、鏡面反射光の計算がオブジェクトを表すメッシュの頂点でのみ実行され、オブジェクトの表面全体の照明を推定するために補間が使用されるため、鏡面反射光のサンプリングに問題が生じます。メッシュの頂点の密度が十分でない場合、鏡面反射光のサンプリングが不十分になり、問題が発生します。その結果、メッシュの頂点からの距離に比例した明るさの反射光が生じ、最終的に曲率を示す視覚的な手がかりが損なわれます。しかし、この問題は、単にメッシュの密度を上げるだけでは解決できません。なぜなら、メッシュの密度を上げると、オブジェクトのレンダリング効率が大幅に低下する可能性があるからです。
キューブマップは、安定した鏡面反射ハイライトをレンダリングするための、比較的シンプルで効率的なソリューションを提供します。複数の鏡面反射ハイライトをキューブマップテクスチャにエンコードし、サーフェスの反射ベクトルを補間して座標を取得することで、このテクスチャにアクセスできます。個々の頂点でのライティング計算と比較して、この方法はよりクリーンな結果をもたらし、曲率をより正確に表現します。この方法のもう1つの利点は、レンダリングコストを増やすことなく、追加の鏡面反射ハイライトをテクスチャにエンコードできるため、スケーリング性に優れていることです。ただし、このアプローチには、光源が遠方または無限遠の光源でなければならないという制限があります。これは、CADプログラムでは通常当てはまります。

キューブマッピングの最も高度な応用例は、事前にレンダリングされたパノラマの空画像を生成し、それをグラフィックエンジンによってキューブの面としてレンダリングすることです。視点はキューブの中心に位置し、ほぼ無限の距離にあります。グラフィックエンジンによるキューブ面の透視投影は、キューブマップを作成するために環境を投影した効果を打ち消すため、観察者はスカイボックスの生成に使用されたシーンに囲まれているような錯覚を体験します。この技術は、複雑な(ただし探索はできない)環境をパフォーマンスをほとんど犠牲にすることなくゲームに追加できるため、ビデオゲームで広く利用されています。
キューブマップは、屋外照明を正確にモデル化するのに役立ちます。太陽光を単一の無限光源として単純にモデル化すると、屋外照明が過度に単純化され、非現実的な照明になります。太陽からの光は確かに豊富ですが、大気中での光線の散乱により、空全体が光源として機能します(これはしばしば天窓照明と呼ばれます)。しかし、キューブマップを使用することで、天窓照明による拡散光の寄与を捉えることができます。反射ベクトルを使用する環境マップとは異なり、この方法は表面法線ベクトルに基づいてキューブマップにアクセスし、天窓からの拡散照明を高速に近似します。この方法の唯一の欠点は、天窓を適切に表現するキューブマップの計算が非常に複雑であることです。最近の手法の1つは、キューブマップからの低周波拡散照明を最もよく表現する球面調和基底を計算することです。しかし、天窓照明を効果的にモデル化するための研究は相当量行われています。

基本的な環境マッピングでは静的なキューブマップを使用します 。オブジェクトを移動したり変形させたりしても、反射される環境は一定に保たれます。しかし、キューブマップテクスチャを継続的に更新することで、動的に変化する環境(例えば、風に揺れる木々)を表現することができます。動的な反射を生成するシンプルながらコストのかかる方法は、実行時に各フレームごとにキューブマップを構築することです。これは追加のレンダリングステップが必要となるため、静的マッピングよりもはるかに効率が悪いものの、インタラクティブな速度で実行することは可能です。
しかし、この手法は、反射する物体が複数存在する場合には、拡張性に問題があります。通常、反射する物体ごとに固有の動的環境マップが必要となります。また、反射する物体同士が互いに反射し合う場合は、さらに複雑になります。 動的キューブマップを再帰的に生成することで、レイトレーシングで通常生成される効果を近似的に再現できるからです。
キューブマップデータ構造を使用したインタラクティブな速度でのグローバルイルミネーション計算アルゴリズムが、 ICCVG 2002で発表された。 [ 6 ]
ビデオゲームで広く利用されているもう一つの技術は、投影テクスチャマッピングです。これは、キューブマップを使用して環境の画像を周囲のシーンに投影する技術です。例えば、点光源は、ランタンケージや窓枠の内側から撮影されたパノラマ画像であるキューブマップに結び付けられます。これにより、ゲーム開発者はシーンのジオメトリを複雑にしたり、高コストなリアルタイムの影のボリューム計算に頼ったりすることなく、リアルなライティングを実現できます。

立方体テクスチャは、6 つのテクスチャ マップを 0 から 5 の順にインデックス付けします: 正の X、負の X、正の Y、負の Y、正の Z、負の Z。[ 7 ] [ 8 ]画像は、画像の左下を原点として格納されます。正の X 面と Y 面は Z 座標を反転する必要があり、負の Z 面は X 座標を負にする必要があります。面とテクスチャ座標が与えられた場合、非正規化ベクトル以下の関数で計算できます。
void convert_cube_uv_to_xyz ( int index , float u , float v , float * x , float * y , float * z ) { // 範囲 0 ~ 1 を -1 ~ 1 に変換float uc = 2.0f * u - 1.0f ; float vc = 2.0f * v - 1.0f ; switch ( index ) { case 0 : * x = 1.0f ; * y = vc ; * z = - uc ; break ; // 正の X case 1 : * x = -1.0f ; * y = vc ; * z = uc ; break ; // 負の X case 2 : * x = uc ; * y = 1.0f ; * z = - vc ; break ; // 正の Y case 3 : * x = uc ; * y = -1.0f ; * z = vc ; break ; // 負の Yケース4 : * x = uc ; * y = vc ; * z = 1.0f ; break ; // 正の Zケース5 : * x = - uc ; * y = vc ; * z = -1.0f ; break ; // 負の Z } }同様に、ベクトル面インデックスとテクスチャ座標に変換できます関数を使用して:
void convert_xyz_to_cube_uv ( float x , float y , float z , int * index , float * u , float * v ) { float absX = fabs ( x ); float absY = fabs ( y ); float absZ = fabs ( z );int isXPositive = x > 0 ? 1 : 0 ; int isYPositive = y > 0 ? 1 : 0 ; int isZPositive = z > 0 ? 1 : 0 ;float maxAxis 、uc 、vc ;// 正の X if ( isXPositive && absX >= absY && absX >= absZ ) { // u (0 から 1) は +z から −z へ// v (0 から 1) は −y から +y へmaxAxis = absX ; uc = - z ; vc = y ; * index = 0 ; } // 負の X if ( ! isXPositive && absX >= absY && absX >= absZ ) { // u (0 から 1) は −z から +z へ// v (0 から 1) は −y から +y へmaxAxis = absX ; uc = z ; vc = y ; * index = 1 ; } // 正の Y if ( isYPositive && absY >= absX && absY >= absZ ) { // u (0 から 1) は −x から +x へ// v (0 から 1) は +z から −z へmaxAxis = absY ; uc = x ; vc = - z ; * index = 2 ; } // 負の Y if ( ! isYPositive && absY >= absX && absY >= absZ ) { // u (0 から 1) は −x から +x へ// v (0 から 1) は −z から +z へmaxAxis = absY ; uc = x ; vc = z ; * index = 3 ; } // 正の Z の場合 if ( isZPositive && absZ >= absX && absZ >= absY ) { // u (0 から 1) は −x から +x へ// v (0 から 1) は −y から +y へmaxAxis = absZ ; uc = x ; vc = y ; * index = 4; } // 負の Z if ( ! isZPositive && absZ >= absX && absZ >= absY ) { // u (0 から 1) は +x から −x へ// v (0 から 1) は −y から +y へmaxAxis = absZ ; uc = - x ; vc = y ; * index = 5 ; }// −1~1 の範囲を 0~1 に変換します。* u = 0.5f * ( uc / maxAxis + 1.0f ); * v = 0.5f * ( vc / maxAxis + 1.0f ); }