
2026/05/30 23:25
ヴォクセルスペース (2017)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Voxel Space Engine は、高度なレイキャストおよびハイト・カラーマップを使用して、1990 年代のフライトシミュレーション 그래픽を再現します。このエンジンは GPU が珍しい時代にはゲーム『Comanche』などに構築されたものであり、現代の Web ブラウザ上で動作させることができます。2.5D エンジンとして機能し、1024×1024 の 1 バイトマップ(ハイトおよびカラー)を周期的にラスタライズすることで深さをシミュレートし、事前計算された陰影を使用して垂直ラインを描画します。これらのマップの周期性により、地形表現は位置ごとの単一のハイトに限定され、建物や樹木などの複雑な幾何学形状は除かれています。奥行き表現には改良された画家のアルゴリズムを採用し、回転機能には正弦関数と余弦関数を使用しています。性能面では、Y ブuffer と Level of Detail(LOD)技術を用いた前後方向のレンダリングにより最適化されており、距離に応じたレンダリングステップサイズを拡大することで処理能力を節約しました。現在、コアコードは MIT ライセンス下で自由かつオープンソースの Python ソフトウェアとして入手可能であり、開発者に初期のヴォーセルベースの地形レンダリングを模倣するレトロコンピューティングの代替手段を提供しています。元のデータマップは歴史的ゲームからリバースエンジニアリングされ、一部の技術が特定のカントリーで特許登録されているものの、このプロジェクトは後継ハードウェアを必要とせずに、初期の 3D ゲームを定義したイノベーションを探求しようとする愛好家にとって貴重な歴史的リソースとしての役割を果たしています。
本文
VoxelSpace エンジンの Web デモ:歴史と技術解説
歴史的背景
- 1990 年代初頭の環境
- CPU は現代に比べ約 1000 倍も低速 で、GPU を用いた加速技術は存在しなかった。
- 3D ゲームは CPU 計算に完全依存しており、レンダリングは単一色の塗りつぶし多角形で行われていた。
- 初期の代表作
- 「Gunship 2000」:MicroProse 社より 1991 年発売。
- 「Comanche」:NovaLogic 社より同年(1992 年頃)発売、翌年もリリースされた革新的な作品。
- 技術的な衝撃
- 当時の基準では驚異的な画質で、実質的に 3 年前の未来を予見したような存在 だった。
- 山や谷にテクスチャが施され、明確な陰影や影表現が可能になっていた(ピクセル化された画面は全ゲーム共通だが)。
レンダリングアルゴリズムの原理
ボクセル・スペース(Voxel Space)とは?
- **「Comanche」**で採用された技術。
- 基本原理は レイキャスト とほぼ同等であるが、厳密な意味での完全 3D エンジンではなく、2.5D エンジン に分類される。
- 通常の 3D エンジンが持つような完全な自由度には欠ける。
ハイトマップとカラーマップの利用
- 構造
- ハイトマップ:
ピクセルで、各画素に 1 バイトの値(高さ)を持つ。1024×1024 - カラーマップ: 同じく
で構成され、周期(反復)的な構造を持つ。1024×1024 - 本プロジェクトでは両マップをダウンロード可能としている。
- ハイトマップ:
- 制約と利点
- 制約: 「各座標に対し一意の高さのみ」という表現により、建物や樹木などの複雑な幾何形状の再現は不可能。
- 利点: カラーマップに 既に陰影や影の情報 が含まれているため、レンダリング時に照明計算を行う必要がない。これにより処理が簡素化される。
基本的な描画手順(コアアルゴリズム)
通常の 3D エンジンとは異なり、ハイトマップとカラーマップをラスタライズして縦方向のラインを描画する方式をとる。
- スクリーンクリア
- 奥から手前へ順に描画(被写体保証 / 隠蔽処理):「ペインターアルゴリズム」を使用。
- 光学的距離の等しいマップ上のライン特定:視野角と遠近法投影を考慮。
- ラスタライズ:スクリーンの横方向画素数に合わせてラインを離散化。
- 情報取得:2 次元マップから高さと色を読み取る。
- 遠近法適用:高度座標に投影計算を施す。
- 描画実行:読み取った情報に対応する縦線をスクリーン上に描く。
アルゴリズムの実装例(Python)
1. 簡易的な回転固定版
北方固定での表示のみ可能な基本実装です。
def Render(p, height, horizon, scale_height, distance, screen_width, screen_height): # 奥から手前へ描画(z コーディネートが高い順から低い順へ) for z in range(distance, 1, -1): # マップ上のラインを決定(視野角 90° に相当する計算) pleft = Point(-z + p.x, -z + p.y) pright = Point( z + p.x, -z + p.y) # ラインを区間化 dx = (pright.x - pleft.x) / screen_width # ラインをラスタライズし、各区間に対して縦線を描画 for i in range(0, screen_width): height_on_screen = (height - heightmap[pleft.x, pleft.y]) / z * scale_height + horizon DrawVerticalLine(i, height_on_screen, screen_height, colormap[pleft.x, pleft.y]) pleft.x += dx # 使用例 Render( Point(0, 0), 50, 120, 120, 300, 800, 600 )
2. 回転機能の追加版
カメラ角度($\phi$)を考慮し、座標系を回転させる計算を追加します。
def Render(p, phi, height, horizon, scale_height, distance, screen_width, screen_height): # 視野角のパラメータを事前計算 sinphi = math.sin(phi) cosphi = math.cos(phi) # 奥から手前へ描画(z コーディネートが高い順から低い順へ) for z in range(distance, 1, -1): # マップ上のラインを決定(座標回転計算) pleft = Point( (-cosphi*z - sinphi*z) + p.x, ( sinphi*z - cosphi*z) + p.y) pright = Point( ( cosphi*z - sinphi*z) + p.x, (-sinphi*z - cosphi*z) + p.y) # ラインを区間化 dx = (pright.x - pleft.x) / screen_width dy = (pright.y - pleft.y) / screen_width # ラインをラスタライズし、各区間に対して縦線を描画 for i in range(0, screen_width): height_on_screen = (height - heightmap[pleft.x, pleft.y]) / z * scale_height + horizon DrawVerticalLine(i, height_on_screen, screen_height, colormap[pleft.x, pleft.y]) pleft.x += dx pleft.y += dy # 使用例(回転角度 phi=0 のまま) Render( Point(0, 0), 0, 50, 120, 120, 300, 800, 600 )
パフォーマンス向上手法
1. 描画順序の変更(手前から奥へ)
- 手法: 「奥から手前」ではなく「手前から奥」の順序で描画。
- メリット: 毎フレームすべてのラインを下端まで描画する必要がなくなるため、被写体によって描画が必要な領域のみを絞れる。
- 必須要素: オクルージョン(隠蔽)を保証するため、Y バッファを追加維持する必要がある。
- 各列ごとに最も高い Y 位置を保存し、次のラインの可視部分をチェックする。
2. レベル・オブ・ディテール(LOD)
- 概念: 近くの物体は詳細に、遠くの物体は低解像度で描画することで処理負荷を削減。
- 実装例: Y バッファを用いて手前からの描画を行い、距離が大きくなるにつれてステップサイズ(移動幅)を増加させる方式。
def Render(p, phi, height, horizon, scale_height, distance, screen_width, screen_height): # 視野角のパラメータを事前計算 sinphi = math.sin(phi) cosphi = math.cos(phi) # 可視性バッファ(各列の現在の最高 Y)を初期化 ybuffer = np.zeros(screen_width) for i in range(0, screen_width): ybuffer[i] = screen_height # 手前から奥へ描画(z コーディネートが低い順から高い順へ) dz = 1. z = 1. while z < distance: # マップ上のラインを決定(座標回転計算) pleft = Point( (-cosphi*z - sinphi*z) + p.x, ( sinphi*z - cosphi*z) + p.y) pright = Point( ( cosphi*z - sinphi*z) + p.x, (-sinphi*z - cosphi*z) + p.y) # ラインを区間化 dx = (pright.x - pleft.x) / screen_width dy = (pright.y - pleft.y) / screen_width # ラインをラスタライズし、各区間に対して縦線を描画 for i in range(0, screen_width): height_on_screen = (height - heightmap[pleft.x, pleft.y]) / z * scale_height + horizon DrawVerticalLine(i, height_on_screen, ybuffer[i], colormap[pleft.x, pleft.y]) # Y バッファ更新(隠蔽処理) if height_on_screen < ybuffer[i]: ybuffer[i] = height_on_screen pleft.x += dx pleft.y += dy # 次のラインへ進み、距離が大きくなるとステップサイズを大きくする(LOD 効果) z += dz dz += 0.2 # 使用例 Render( Point(0, 0), 0, 50, 120, 120, 300, 800, 600 )
リンクと参照情報
- Web プロジェクトのデモページ
- ボクセル地形エンジンの解説記事
- 開発者の個人ウェブサイト
マップデータ
- カラーマップ: 色と照明情報を保持。
- ハイトマップ: 地形の高さを保持。
ライセンスと注意点
- ソフトウェアライセンス: MIT ライセンス(詳細はライセンシーファイルを参照)。
- 特許事項: 「ボクセル・スペース」という技術自体が一部の国で特許保護の対象である可能性があります。ご留意ください。
- データ元について: 提供されるカラーマップおよびハイトマップは、ゲーム『Comanche』からリバースエンジニアリングされたものであり、本プロジェクトの MIT ライセンスの範囲外となります。