1 ポイント 投稿者 GN⁺ 5 시간 전 | 1件のコメント | WhatsAppで共有
  • Catlantean 3D は、1990年代初頭のPCゲーム風の制約で完成した一人称シューティングを作ろうとするサイドプロジェクトで、320x240解像度と256色パレットベースのレンダリングを目標としている
  • レンダラーはパレットインデックスだけを扱うため、距離に応じた減光表現のために32段階の colormap を事前計算し、実行中は O(1) 参照で暗い色を選ぶ
  • アセット制作は、Blenderベースの 事前レンダリングスプライト、手描きスプライト・テクスチャ、Pythonスクリプトで生成する手続き型テクスチャに分かれる
  • 手描きHUDとピクセル単位のスケール規則は、小さな解像度で鮮明さと可読性を保つための中核的な制約であり、ワールド1ユニットを64ピクセル基準に合わせている
  • Tiledの代わりに独自マップエディタを作成し、発売後はプレイヤーにも同じエディタを提供する計画で、ゲームのソースコードはGitHubでオープンソース公開する予定

プロジェクトの目標と制約

  • Catlantean 3Dは、1年以上にわたって余暇時間にゆっくり開発しているサイドプロジェクトで、翌年のSteam公開を目指している
  • 目標は、1990年代初頭によく使われていた技法で、完成して発売可能な一人称シューティングを作ること
  • 現代的なコンパイラとプラットフォーム抽象化レイヤーは許容するが、抽象化レイヤーはピクセルを書き込むフレームバッファ、キーボード・マウス入力、サンプルを書き込むオーディオバッファ、ファイルシステムI/O程度に制限する
  • ゲームはアセットも含めてすべてゼロから作る必要があり、レンダリングとサウンドミキシングもすべて自前で実装しなければならない
  • 目標解像度は320x240で、画面上のすべてのピクセルは256色のうち1色しか使えない
  • ゲームロジックは決定的動作を保証するため固定小数点を使い、レンダリングは決定性の重要度が低いため浮動小数点を使う
  • 成果物は技術デモではなく、楽しく遊べる完成度の高いゲームでなければならず、AI生成物は使わない
  • 表示されているすべての作業物は制作途中であり、大きく変わる可能性がある

パレットレンダリング

  • VGAグラフィックス

    • VGAハードウェアのMode 13hは320x200の256色グラフィックスモードで、1世代のPCゲームを規定した有名なモードだった
    • プログラマの視点では、Mode 13hは各ピクセルを256色パレットのインデックスとして1バイトで表す線形フレームバッファを提供する
    • ピクセルを描くには特定のアドレスに1バイト書き込めばよく、シェーダーやVRAMのような概念を扱う必要はなかった
    • 現代のゲームアセットは画像内で数百万色を使えるが、256色制限ではすべての色選びが慎重かつ意図的である必要がある
    • DoomやDuke Nukemのようなゲームは、技術的制約によってグラフィックスの鮮明さと明快さが生まれた例として挙げられる
    • Catlantean 3Dはその感覚の再現を目指すが、320x200ではなくVGA Mode-Xに近い320x240を選んでいる
    • 320x200を4:3ディスプレイに表示すると正方形でないピクセルになるが、この方式はより本格的ではあるものの、好みにより避けている
  • パレット

    • パレットは768バイトから始まり、何度もの試行錯誤と反復を経て選ばれた
    • パレットには透明色用の鮮やかなピンク、純白、純黒がそれぞれ1色ずつ予約されている
    • 血の表現のために赤系の色が多く必要で、赤・緑・青のキーや色分けされた扉のために緑系と青系の色も必要だった
    • 舞台は猫崇拝のため古代エジプトに似たパロディ世界 Catlantis に設定されており、黄や茶を中心とした砂漠色が多く必要になる
    • Catlantisはサイバネティックな犬人間に占領されている設定なので、技術施設を表現するためのグレー系も多く必要になる
    • グレーの単調さを崩し、暗くなったときに暖色寄りの代替色として使うため、ベージュ系も入っている
    • 残りの色はテクスチャ制作の過程で必要に応じて埋められ、「見た目に合っていた」という主観的判断で決められた
    • パレットは一度で完成したのではなく、アセット制作とテスト、反復の中で継続的に調整された

colormapとライティング処理

  • raycaster構造

    • Catlantean 3Dは伝統的なraycasterで、マップはすべて同じ大きさのタイルで構成される
    • 一部のタイルは壁で、他のタイルは床と天井だけがある空間になっている
    • レンダラーは画面の各列ごとにDDAアルゴリズムを使ってタイルマップを進み、マップジオメトリにぶつかる位置を見つける
    • 衝突位置に応じて、適切なテクスチャ座標からサンプリングした壁の列を画面に描く
    • 床と天井はその後、水平スキャンラインでレンダリングされて画面の残りを埋める
    • 単にパレットだけでゲーム世界をレンダリングすると、平板で印象の弱い画面になる
    • プレイヤーから遠ざかるほど光が減り、マップタイルの片側の面が反対側より少し暗いと奥行き感が生まれる
  • パレットベースの減光

    • 現代のハードウェアアクセラレーションレンダラーでは、頂点距離に基づいて色ベクトルに浮動小数点係数を掛ければ、シェーダー内で簡単に暗くできる
    • パレットレンダラーは色そのものではなくパレットインデックスしか扱わないため、ある色をもっと暗い色にしたければ、パレット全体から探さなければならない
    • レンダリングする全ピクセルごとに256色パレットを探索すると遅すぎるため、実行前に事前計算して高速な色参照を用意する
    • パレットを1行に並べて32段階の明暗を選ぶと、各色には元色を除いて31個のより暗い変種が必要になる
    • 各色のRGB値と明暗インデックスから目標となる暗色を計算するが、その色が実際のパレット内に存在しないことがある
    • 目標色に最も近いパレット色を見つけるため、パレットを探索してcolormapを構築する
    • 当初はユークリッド距離を使っていたが、多くの色がグレー側へ引っ張られる傾向があり、暗色が冷たく生気のない見た目になっていた
    • その後、色をOklab色空間に変換し、人間の色差知覚により近い知覚距離の式を使うようにした
    • 色が暗くなるほど少し暖色方向へずらす、ピクセルアートの概念である色相シフト(hue shifting)も適用した
    • colormapは各色の明暗を表すパレットインデックスの2次元行列であり、依然としてパレット色しか使えないためグラデーションは完全ではない
  • 実行コスト削減

    • 距離ベースのcolormap行インデックスが決まれば、その明暗段階の行からN番目の項目を選ぶことで、暗くした色Nのパレットインデックスを得られる
    • この方式により、実行中の暗色選択は O(1) 参照で処理できる
    • 壁レンダリングでは壁の列が完全に垂直で、列内の全ピクセルがカメラと同じ距離にあるため、画面列ごとに一度だけcolormap行インデックスを計算する
    • 床レンダリングでは水平行の全ピクセルが同じ距離にあるため、画面行ごとに一度だけ計算する
    • スプライトは全ピクセルがカメラと同じ距離にある平坦なビルボードなので、見えているスプライトごとに一度だけ計算する
    • 壁は320回、床は最大240回、可視スプライトはそれぞれ1回だけ計算すればよく、raycastingは隠れたオブジェクトの除去も無料で提供する
    • Doomや他の多くのゲームも似たアプローチを使っている

アセット制作方式

  • 3つのアセットカテゴリ

    • Catlantean 3Dのテクスチャとスプライトは3つのカテゴリに分かれる
    • 1つ目は、Blenderで作った3Dモデルをテクスチャとしてレンダリングした事前レンダリングスプライト
    • 2つ目は、手描きのスプライトとテクスチャ
    • 3つ目は、手描きアートを組み合わせる特殊なPythonスクリプトで生成した手続き型テクスチャ
  • 事前レンダリングスプライト

    • 複雑なアニメーションスプライトは複数フレームを修正しなければならないため、反復作業が難しく時間もかかる
    • より効率的な方法は、Blenderで3Dモデルを作り、リギングとアニメーションを行ったうえで、Blender Python APIを使うスクリプトで複数のテクスチャをレンダリングすること
    • 修正はモデル側で行い、レンダリングスクリプトが残りを処理するため、反復にかかる時間を大きく減らせる
    • 主な難点は、レンダリングされたスプライトが非常にぼやけて、色あせたように見えてしまうことだった
    • 高解像度でレンダリングしてからフィルタリングで縮小する方法は、ディテールがフィルタで潰れたり、輪郭の鮮明さが失われたりして、結果はまちまちだった
    • 最も効果的で再利用しやすい方法は、Blenderのコンポジット機能で適切なコントラストと鮮明さを得ることだった
    • 画像の準備ができると、特殊なPythonスクリプトがパレット量子化を行い、エンジンで使う1バイトピクセル画像を生成する
    • スクリプトは元画像の各ピクセルについて、Oklab基準で知覚的に最も近いパレット色を見つけ、その色のインデックスをピクセル値として使う
    • インデックス配列とサイズ情報は、ゲームで使うシンプルなTEX形式にパックされる
    • 敵スプライトは複数のアニメーションを持てて、各アニメーションにはスプライトが向ける8方向のフレームが必要になる
    • Pythonスクリプトはアニメーションごとにスプライトを回転させ、全フレームをレンダリングし、再び回転させる処理を繰り返す
    • スプライトのファイル名は、スプライト名、動作名、方向、フレームインデックスを表す規則で保存される
    • レンダリング済みスプライトはリポジトリには置かず、.gitignore対象とし、別のコンピュータではビルドスクリプトが全モデルをレンダリングしてスプライトを生成する
    • RTX 3070では約15モデルの処理に約10秒かかる
  • 手描きスプライトとテクスチャ

    • 開発初期には、ステータスバーの顔として使うため、猫 Vilko のテクスチャを貼った猫型の頭部をBlenderで作っていた
    • この成果物は手抜きで低労力に見え、感情表現も弱く、雰囲気に関するフィードバックで人々が最初に指摘する部分だった
    • 一部の要素はどうしても手描きである必要があり、アニメーション付きの手描き版のほうがはるかに良いと判断した
    • スプライトのサイズが小さいため、すべてのピクセルが意図的でなければならず、Blenderレンダラーに任せる余地がない
    • 同じ論理は多くのピックアップアイテムにも当てはまり、以前の事前レンダリング結果は小さいスケールでBlenderコンポジターが安定して良い結果を出せなかった
    • 人の手を入れた後は、ピックアップアイテムの鮮明さと可読性が大きく向上した
    • スプライト解像度を単純に上げればゲームのラスタライザでスケーリングはできるが、ピクセルスケールが一貫せず、結果は良くない
    • 画面の同じ行や列で前後に動くとき、ピクセルサイズは同じまま保たれると無意識に期待するため、スプライトごとにピクセルスケールが違うと不自然になる
    • Catlantean 3Dのワールド1ユニットは64ピクセルで、すべてのスプライトはこのスケールに合わせて作られる
    • ワールドユニットの4分の1の高さのスプライトは、64/4=16ピクセルの高さである必要がある

HUDと手続き型生成パイプライン

  • HUD

    • HUDとその構成要素はほぼすべて手作業で配置し、描いている
    • 画面下部のステータスバー、各種トランジションパネルと画面、フォントが手描きHUDのカテゴリに入る
    • すべての要素を直接塗るのではなく、Affinity Photoのレイヤー効果と合成を多用している
    • 使っている効果には、平坦な面に3D感を与えるemboss効果、ざらついた質感のためのノイズ生成とオーバーレイ、カラーオーバーレイ、ブレンドモード、glow効果がある
    • HUD要素は何度も反復して修正するため、レイヤーベースで再配置しやすいことも重要になる
    • 基本的にはAffinity Photoでまずtruecolorのまま作業し、多くの要素は単色の長方形に特殊効果とブレンドを適用したものになっている
    • Affinity Photoから書き出した画像には、アンチエイリアシングに関連していると思われる奇妙なアーティファクトが含まれており、これを安定して無効化できなかった
    • ピクセル単位で正確な作業には向いていないため、Asepriteでピクセルパーフェクトなテキスト、アートワークの分割、より鮮明な輪郭線の描き足しなどの追加作業を行う
  • 手続き型生成テクスチャ

    • 一部のテクスチャは直接描くのに十分シンプルまたは具体的だが、多くのテクスチャは基本素材の上に摩耗、埃、表面ディテールの変化を共有している
    • 各バリエーションを手で描くと退屈で一貫性も欠けるため、Pythonスクリプトで生成している
    • 生成パイプラインは、表面のreliefを定義するheightmap、変形用のnoise map、埃や摩耗用のgrime map、2つの基本色、brightmapを入力として受け取る
    • heightmapは実際にはnormal mapの生成に使われ、normal mapは単純なライティングと影のベイクに使われる
    • brightmapは、他のパラメータに関係なく色を維持する部分を指定する
    • スクリプトは最終テクスチャを作り、パレット量子化まで行って、エンジンでそのまま使えるようにする
    • テクスチャ修正はピクセルを描き直す代わりにパラメータ調整の作業になり、一人開発では時間を大幅に節約できる

gibsと事前レンダリング効果

  • Gibs

    • 敵に point-blank shotgun blast や explosion のような過剰ダメージが入ると、通常はgibbingが発生する
    • 大ダメージの衝撃を伝えるため、敵が血まみれの破片となって吹き飛ぶアニメーションを使う
    • このパイプラインはPythonスクリプト主導で、スプライト、パレット、パラメータ群を受け取り、ゲームデータに入るアニメーションフレームを生成する
    • 最初の段階であるVoronoi decompositionでは、スプライトの不透明な本体からK個のseedピクセルをランダムに選び、すべてのピクセルを最も近いseedに割り当てる
    • こうしてできた各cellが、飛び散る破片1つになる
    • 第2段階のwound bleedingでは、異なる破片に隣接する境界ピクセルを深さ0の傷としてマークし、BFSが内側へ広がりながら深さ値を与える
    • レンダリング時には境界付近のピクセルを、ゲームパレットから派生したrampの血色側へブレンドし、破片の内側に入るほど元のスプライト色をより保つ
    • パレットrampの選択はパラメータ化されており、特定の敵には緑色や青色の「血」も使える
    • 第3段階のphysicsでは、各破片に中心点、スプライト中心から外向きへのランダムな拡散速度、回転速度、重力、dragを与える
    • 衝突判定はないが、破片は床にぶつかると止まり、粗いながらも十分な結果になる
    • 破片数、爆発力、重力、drag、拡散、傷の深さはパラメータで調整できる
    • 見栄えの良いseedを見つけるには多少の試行錯誤が必要だが、手でアニメーションを描くよりは速い
    • 同じ技法は植木鉢、バレル、箱のような破壊可能な環境オブジェクトにも使われる
    • 事前レンダリングアニメーションと同様に、gibsの生成結果もリポジトリには置かず、チェックアウト後に再生成され、実行時間は無視できる程度
  • 事前レンダリング粒子システム

    • ほとんどの粒子効果はAsepriteで手描きするが、一部はgibsと同じ方法で生成してベイクする
    • Pythonスクリプトがシミュレーションを実行してPNGフレーム列を作り、その後TEXへ量子化する
    • ランタイム粒子システムは存在せず、すべての効果を事前にベイクして、ソフトウェアラスタライザで可能な限り高速にレンダリングできるようにする
    • ここでいう「particle」という語はやや誤解を招きやすく、実際には粒子そのものをシミュレートしているわけではない
    • 各フレームはピクセルごとのradial energy fieldを計算し、複数の独立レイヤーを加算して合成される
    • coreはアニメーション中に外側へ広がる滑らかな円盤
    • raysはcoreの周囲に出る尖った光条で、sharpnessとlengthを設定でき、各rayにはRNGベースの長さの揺らぎが入り、不規則に見える
    • ringは任意で使える拡大するshockwaveで、noiseは全体エネルギーにvalue noiseを掛けて、整った形をざらついた不規則なものに変える
    • 累積したピクセルごとのエネルギーは、スクリプトのパラメータで指定したパレットrampに合わせて量子化される
    • パレット設計上、各行は明るい色から暗い色へのグラデーションのように扱えるため、ブレンドやアルファ計算なしでも、パレットインデックス演算だけでピクセルを暗くできる
    • 一定のしきい値を超えると、ピクセルを白方向へ押して white-hot core のような印象を与える
    • 必要に応じて小さなsparkleを上に散らすこともでき、この十字形は外側へ移動し、それぞれの寿命の間に消えていく
    • アニメーションは、explosionやteleport flashのように膨らんで消えるone-shotモードと、最初と最後のフレームが一致して継ぎ目なくループするloopモードをサポートする
    • loopモードはplasma boltsやenergy projectilesのような持続反復エフェクトに有用

マップエディタとツール生態系

  • マップ編集は当初Tiledで始めたが、概ね妥当なツールではあったものの、ゲームに必要な具体的機能が不足していた
  • Tiledにはセルごとのlight level painting、cell flags、ゲーム固有のproperty概念がなく、初期にはobject propertiesを乱用して回避していた
  • TiledのJSON出力をエンジンで使うバイナリ形式へ変換するPythonスクリプトも必要で、これはツールとゲーム要件の不一致を補うための追加部品だった
  • プレイヤーがマップを作るためにTiledをインストールし、インターフェースを学び、変換スクリプトを設定しなければならないなら、その負担はエディタが実際に使われる可能性をほぼなくすほど大きい
  • 独自エディタはlight level painting、cell flags、ゲームが認識するすべてのentityとproperty型をネイティブにサポートしている
  • ゲームが発売されたら、プレイヤーも開発に使ったのと同じエディタを受け取れる
  • エディタはplug and play方式で、エディタから直接レベルを実行できる
  • ツールバーのアイコンがひどいことは承知しており、まさにその理由でそのまま残している
  • エディタはwxPythonで作られており、tkinterよりもwidget、event handling、layoutの面で適していた
  • wxPythonの結果はよりネイティブに見え、反復作業も速く進んだ
  • MVPパターン中心の構造はUIロジックとマップデータをきれいに分離し、マップ形式がまだ安定しておらず両者が頻繁に変わる状況で重要になる
  • エディタのすべてがPythonで書かれているわけではなく、modelの多くは pybast ライブラリに依存している
  • pybast はpybind経由のエンジン内部Pythonバインディングで、game data archiveの読み込み、game texturesの読み込み、entity coordinates用fixed point class、serializationを提供する
  • これは、すでにC++で実装済みの機能をPythonで再実装しないための選択であり、エンジンとツールが小さく密接な生態系を形作っている

リリース計画と公開方法

  • Catlantean 3Dは2027年第1四半期の公開を見込んでいる
  • 現在の焦点は、レベルデザイン、敵と武器の追加、進行中のポリッシュ作業にある
  • 価格目標は5〜8ドル帯
  • ゲームのソースコードはGitHubでオープンソース公開する予定
  • グラフィックス、レベル、サウンド、音楽などが入った実際のdata archiveは、ゲームを購入しないと受け取れない
  • プロセスの透明性は、継続的な信頼を築く数少ない要素の1つと考えられている
  • インディーゲームはAAAと違ってより小さな観客層に依存するが、その観客はプロジェクトを追いかけ、応援し、他の人に伝えようとする意欲がより強い
  • 制作過程を見せることは、自分が作っているものを本当に大切にしていると示す最も率直な方法として提示されている

1件のコメント

 
GN⁺ 5 시간 전
Hacker Newsの意見
  • ソフトウェアレンダリングで遊んでみたいなら、SDL2とCで、メインメモリ上のARGB8888の2D配列を全プラットフォームで効率よく画面に載せるための、ほぼ最短コードに近い例がある: https://gist.github.com/CoryBloyd/6725bb78323bb1157ff8d4175d...
    320x200x8ビットのパレットフレームバッファをARGBに変換する処理は自分でやる必要がある ;)
    パレットフレームバッファで何ができるかのインスピレーションが欲しければ、http://www.effectgames.com/demos/canvascycle/でShow Optionsを押すか、そのアーティストのGDC発表 https://youtu.be/aMcJ1Jvtef0 を見るとよい
    そのあと、クラシックなDeluxe Paint IIeっぽさが欲しければ https://github.com/mriale/PyDPainter を、もう少しモダンなツールが欲しければ https://www.aseprite.org/ を起動すればよい

    • 少なくとも SDL3 では、もうレンダラーやテクスチャは不要。SDL_GetWindowSurfaceでサーフェスを取得し、SDL_UpdateWindowSurfaceで表示すればよい
      ライブラリの理解が正しければ、これが最もソフトウェアグラフィックスに近いやり方で、SDLは引き続きダブルバッファリングを面倒見てくれる

    • たしかに最も基本的なやり方。内側のループで少し最適化したいなら、ピクセルループに入る前に スキャンラインオフセット を先に計算しておけばよい:
      int s = y*screenRect.w;

      for (int x = 0; x < screenRect.w; x++) {
      pixels[s + x] = argb(255, frame>>3, y+frame, x+frame);
      }

    • 共有ありがとう。すでに人気のあるQuakeフォークはいくつもあるが、Planimeterは変更を加えない Quake-VS2026 フォークを配布している
      チームはx64ビルドに取り組んでいて、そのために古いSciTech Multi-platform Graphics Library(x86専用)をSDL3に置き換える必要がある。あるいはscitech-mglをx64へ移植する手もあるが、その可能性は低そうで、最後に聞いた時点ではソフトウェアレンダラーが外れる可能性もあった
      ただ、ソフトウェアレンダラーとSDL_Textureで維持できるかもしれない

  • この記事はDoomから多くの影響を受けているが、実際の レイキャスティングエンジン は、Doomより前の作品群、なかでも最も有名なWolfenstein 3Dにより近い
    垂直な壁と、一定の床・天井の高さを使う方式。Wolf3Dには性能上の理由でテクスチャ付きの床や天井はなかったが、似た別のゲームにはそれがあるものもあった
    Doomと、記憶が正しければDuke Nukemも、はるかに柔軟なBSPエンジンを使っていて、壁が任意の角度で交差したり、床や天井の高さを変えたりできた。ただしレベルは依然として「平面的」だったので、1つのレベル内に複数階層を作ることはできず、たとえば上下の両方を通行できる橋は設計できなかった

    • Buildエンジンは BSP を使っていなかった。セクター間の接続をポータルとして扱い、そのポータルに対してクリッピングしながら、壁を90度回転した台形のようにラスタライズしていた
      そのおかげで、動く列車や回転する照明のような動的な壁ジオメトリが可能で、同時に2つの部屋を見渡せない限りは「部屋の上の部屋」のような構成も可能だった
      BloodやShadow Warriorでは、同じ形のセクターを作り、あるセクターの床を別のセクターの天井へつながるポータルのように使う回避策で、より「3D」に近い空間を作っていた。エンジンが本来サポートしていた機能ではなかったが、ソースアクセス権すらなかったスタジオが自力で実現できるほどには柔軟だった
      Duke Nukem 3Dの最初のレベルでも、いくつかBuildのトリックが使われている。たとえばスプライトはカメラに追従して回転せず、軸揃えにでき、衝突判定も持たせられるので、各スプライトを軸揃えの長方形として扱えば、基本的な3Dジオメトリを作れる。最初のレベルでは、出口ボタンの直前にある2つの建物の間の橋を作るのに使われている

    • Blake StoneとRise of the TriadはWolf3Dエンジンの後期バージョンを使っていて、テクスチャ付きの床と天井 があった
      Duke NukemのBuildエンジンはBSPを使っていなかった

      https://www.jonof.id.au/forum/topic-137.html#msg1548

    • その後のShadow Warriorでは、そういうことも可能だった気がする。ポータルで実装していたと記憶しているが、エディタで設定するのはかなりつらかった

    • 床について言えば、知る限り DOOM ですら正確には処理していなかった。垂直な壁では、特定の壁片についてピクセル列ごとに遠近除算を1回行えば済む
      だが床では残念ながらそんな贅沢はできず、記憶が正しければDOOMは床をパッチに分割し、隅でだけ正しい遠近を計算して、その間は補間していた

    • 最初はただのスキン違いのWolfenstein 3Dだと思っていた。それはかなり不公平な見方で、実際には本当に多くの作業が入っていた

  • 素晴らしい記事だった。特に gibアニメーション を作るアプローチが面白かった。
    技術デモではあったが、90年代半ばごろに私も似たようなものを作ったことがある。この記事では触れられていなかった点として、テクスチャに 8x8 または 16x16 のライトマップを使うと、ちらつくたいまつや、廊下を飛びながら光を投げかけるロケットのような効果を簡単に作れた。必要なら照明を「焼き込む」のにもライトマップを使えた。
    ライトマップは「たった」 8x8 なので、各ルクセル、つまりライトマップの各単位ごとに光源までの距離と視線を計算して明るさの値を求める程度の数学なら十分に処理できた。テクスチャをレンダリングするときは、ルクセルをルックアップテーブルと組み合わせて、実際に描画するピクセルの色を決めていた。
    性能のため、記憶ではライトマップは毎秒15回更新していた。DJGPP のおかげでレンダリングにはインラインアセンブリを使えたし、当時は浮動小数点演算が遅かったので、よく最適化される固定小数点演算を使っていた。当時のコンピュータ基準では、レンダリング性能は驚くほどだった。

    • 固定小数点 という発想は、あまりにも使われず過小評価されている気がする。こちらの方が良い選択になる分野は本当に多いし、性能まで良いことも多い。
  • 1990年代前半から中盤の グラフィックスプログラミング はかなり楽しかった。メモリマップされたビデオ RAM にピクセルデータを書き込めば、そのまま画面に表示された。
    0xA0000 を指すポインタひとつで十分で、API のようなものは必要なかった。言及されていた非正方ピクセルの 320×200 VGA モードの理由は、ビデオバッファが 64000 バイトで 16 ビットセグメント内に収まり、16 ビットコードと CPU でアドレッシングしやすかったからだ。

    • 当時、コンソールに比べると PC の CPU は怪物じみていたのに、グラフィックスアーキテクチャのせいで 1985 年の NES の Mario みたいな 滑らかなスクロール を実装するのに苦労していた、というのがいつも面白かった。
      だがその弱点のおかげで、画面の1ピクセルごとにずっと多くのことができたし、だからこそこのようなレイキャスティングや BSP ツリーのシステムが可能だった。
      スプライトや背景レイヤー用の専用プロセッサはなかったが、その分 PC にできることは硬直した固定機能アーキテクチャに閉じ込められていなかった。
      90年代中盤から後半に専用 3D プロセッサが登場してからはもう問題ではなくなったが、90年代初頭のしばらくの間は、独特なビジュアルレンダリングの遊び場があった。
    • 0xA0000 ポインタひとつで十分ではあったが、使っている エクステンダ によってはそこが少し面倒になることもあった :-P
      DJGPP と Free Pascal は DJ Delorie の同じ go32 エクステンダを使っていたが、完全な線形マッピングをしていなかったので、画面に何かを表示するには少し手を入れる必要があった。
    • VGA が出る前は、話はずっと複雑だった。
  • いちばん興味深いのは内部ツール群だ。gib アニメーションを作る Python スクリプトや、Blender から 2D スプライトシート を生成する別の Python スクリプトのようなものだ。
    元記事の作者は良い絵まで描ける 10x エンジニアであることが明らかで、こういう例は本当に珍しいと思う。一貫したアートディレクションがある点もかなり驚かされた。

    • 90年代にこのジャンルのファンだった立場からすると、こういう ルネサンス型エンジニア たちが主要ヒット作の裏にはいつもいた気がする。いまでも何人かの名前は覚えているし、彼らは本物のアーティストだった。
      この15年のゲーム業界では、CEO やリードディレクターを除けば、ほとんど誰の名前も知らない。
  • このゲームは、女性主人公が出る珍しいシューターのひとつかもしれないと今気づいた。猫が 三毛柄 で、そういう猫はほとんど常にメスだからだ (https://en.wikipedia.org/wiki/Calico_cat)

    • 女性主人公のシューターってそんなに珍しいだろうか? すぐ思いつくかなりメジャーな作品だけでも、Perfect Dark、Mirror's Edge、Dishonored 1 か 2、Metroid などはどれもある種のシューターで、女性主人公だ。
      もちろん Mirror's Edge は、100% 厳密に言えば「シューター」より「一人称視点」に近いけれど。
      そのうえ「RPG + FPS」には男女どちらでもプレイできる作品も多い。
      作者自身も模様と猫の性別の可能性は分かっているようだ:

      After all, I do need to give the protagonist his fair share. [image] (Yes, I know it's a female, but call it convention rooted in dialect.)

    • これは Perfect Dark ではない。

    • 最近の ブーマーシューター には女性主人公がかなり多い。たとえば Selaco[0]、Supplice[1]、The Citadel[2] とその続編[3]、Zortch[4] と予定されている続編[5]、Nightmare Reaper[6]、COVEN[7]、Viscerafest[8]、Hedon[9] などがある。
      むしろ最近は、女性主人公のブーマーシューターの方がそうでないものより多い気さえする :-P Steam 検索で “boomer shooter” と “female protagonist” のタグを組み合わせると 143 件出てくるが、キャラクターの性別を選べるものや、大半は男性でプレイするが一部区間で女性を操作するゲームも含まれている。

      [0] https://store.steampowered.com/app/1592280/Selaco/

      [1] https://store.steampowered.com/app/1693280/Supplice/

      [2] https://store.steampowered.com/app/1378290/The_Citadel/

      [3] https://store.steampowered.com/app/3371240/Beyond_Citadel/

      [4] https://store.steampowered.com/app/2443360/Zortch/

      [5] https://store.steampowered.com/app/3807500/Zortch_2/

[6] https://store.steampowered.com/app/1051690/Nightmare_Reaper/

[7] [https://store.steampowered.com/app/1785940/COVEN/](<https://store.steampowered.com/app/1785940/COVEN/>;)

[8] [https://store.steampowered.com/app/1406780/Viscerafest/](<https://store.steampowered.com/app/1406780/Viscerafest/>;)

[9] [https://store.steampowered.com/app/1072150/Hedon_Bloodrite/](<https://store.steampowered.com/app/1072150/Hedon_Bloodrite/>;)
  • 意図的だったとは思えないが、全体としてそういう点にはあまり感心しないし、価値も感じない。Hollywoodで女性が自分の2倍の大きさの男を叩きのめす描写も同じ。
    非現実的で滑稽で有害だと思う

  • 本当に素晴らしい。90年代に使われていたもう1つの面白いトリックはパレットアニメーションだった。パレットを変えるだけで実行コストを低く抑えつつ、ものすごく格好いい効果を作れた

    • その通り。この技法の素晴らしい作例を見るなら、このウェブサイトを強くおすすめする

      http://www.effectgames.com/demos/canvascycle/

    • フレームの途中でパレットを切り替えるのも面白い。PCにはAmigaのcopperのようなものがないので、タイミングにはずっと気を遣う必要があるが、それでも可能だ

    • Diablo 1と2の多くの敵は、実際には同じスプライトに別のパレットを当てたものだったと記憶している。これも同じトリック?

    • 青は水、紫はプラズマ、赤/オレンジは血や溶岩

  • レンダリング後の量子化されたスプライトがかなり良く見えて、本当に驚いた。その高速な変換のおかげでとてもシャープに見えた

  • ばかげているほど厳しい制約を課した3Dエンジンを作っている同業開発者として、ここで説明されている細部や試行の過程を見るのが本当に楽しい

  • PlayStationのホームブルー向けにボクセル空間レンダリングの技術デモをいじっている。週末に1〜2日作業しただけでも10〜15 FPSくらいでなかなか良い結果が出ていて、まだDMAやGTEはもちろん、ポリラインの基本プリミティブすら使っていない
    三角法や昔ながらの低レベル最適化のコツを引っ張り出すのが新鮮だ。スクラッチバッファが1KiBで、スタックはその一部しか使えないとなると、仕事で使っているマイクロコントローラがいかに贅沢かを思い知らされる。あちらではスレッドごとに8KiBのスタックが割り当てられ、C++テンプレート関数が50個以上積み重なったバックトレースまで出てくるのだから