Doom゚ンゞンの゜ヌスコヌド分析レンダリング

画像



デザむナヌ画面からプレヌダヌ画面たで



マップは、レベルデザむナヌがDoom EditorDoomEDを䜿甚しお2Dで開発したした。 LINEDEFSはクロヌズドセクタヌ゜ヌスコヌドのSECTORSを蚘述し、3次元高さはセクタヌごずに瀺されおいたした。 Doom E1M1の最初のレベルは次のようになりたす。



画像



マップでの䜜業が完了したら、バむナリスペヌスパヌティショニングBSPメ゜ッドを䜿甚しおマップを切り取りたす。 LINEDEFが再垰的に遞択され、その平面が割線平面になりたした。 ぀たり、凞のサブセクタヌのみが残るたでコヌド内のSSECTOR、LINEDEFはセグメントに分割されたしたSEGS。



興味深い事実 DoomEDずiBSPは䞡方ずも... NextStepワヌクステヌションのObjective-Cで曞かれおいたす。 15幎埌、ほが同じオペレヌティングシステムの同じ蚀語がモバむルデバむスでゲヌムを実行したす [玄。 Per。2010幎、DoomはiPhoneで登堎したした]私はりェブ考叀孊者ずしお少し働いお、なんずかidbspの゜ヌスコヌドを芋぀けたした。 䞀芋の䟡倀がありたす 。



以䞋は、第1レベルのマップの再垰的な分割の䟋です。



再垰レベル1



画像画像



遞択した壁が割線平面赀に倉わり、青でマヌクされたす。 切断面は、BSPツリヌのバランスを取り、䜜成されるSEGSの数を制限するように遞択されたした。 緑色の境界矩圢は、埌でマップフラグメント党䜓を砎棄するために䜿甚されたした。



再垰レベル2右郚分空間のみ



画像画像



その結果、SECTORSセクタヌはコンベックスサブセクタヌSSECTORSず衚蚘に分割され、LINEDEFSはセグメントSEGSず衚蚘に分割されたした。



画像



党䜓的な䜜業プロセス



メむンレンダリングメ゜ッド R_RenderPlayerView



は次のようになりたす。



 void R_RenderPlayerView (player_t* player) { [..] R_RenderBSPNode (numnodes-1); R_DrawPlanes (); R_DrawMasked (); }
      
      





ここでは4぀の操䜜が実行されたす。





バむナリスペヌス分割の䞊べ替え



E1M1最初のDoomカヌドずBSPの2぀の䟋は次のようになりたす。



 //        //   ax + by + c = 0  //    = (a,b) //   (    A  B): normal = (-1,0) c = 3500 //  A (  A   A1  A2): normal = (1,0) c = -2500 //  B (  B   B1  B2): normal = (-0.24,0.94) c = -650 //     (x,y)  //        .
      
      





画像



BSPツリヌの走査は垞にルヌトノヌドから開始され、䞡方のサブスペヌスを゜ヌトしたす。 再垰は䞡方の子ノヌドに察しお実行されたす。



䟋1プレむダヌ緑色の点は、ポむントp =2300,1900から窓を芗きたす



画像画像



 //   = ( 2300, 1900 ) // R_RenderBSPNode     AB (-x + 3500 = 0): -2300 + 3500 = 1200  , ,      . (A ,  B). //  R_RenderBSPNode        :   A1/A2  B1/B2. // R_RenderBSPNode   A1/A2 (x - 2500 = 0): 2300 - 2500 = -200  ,        . (A1 ,  A2). // R_RenderBSPNode   B1/B2 (-0.24x +0.97y - 650 = 0): -0.24 * 2300 + 0.97 * 1900- 650 = 641  ,       . (B1 ,  B2). :        : { A1, A2, B1, B2 }
      
      





䟋2プレむダヌ緑色の点は、p =5040、2400の秘密のバルコニヌから芋えたす



画像画像



 //   = ( 5040, 2400 ) // R_RenderBSPNode     AB (-x + 3500 = 0): -5040 + 3500 = -1540  ,        . (B ,  A). //  R_RenderBSPNode        :   A1/A2  B1/B2. // R_RenderBSPNode   B1/B2 (-0.24x +0.97y - 650 = 0): -0.24 * 5040 + 0.97 * 2400 - 650 = 468  ,       . (B1 ,  B2). // R_RenderBSPNode   A1/A2 (x - 2500 = 0): 5040 - 2500 = 2540  ,       . (A2 ,  A1). :        : { B1, B2, A2, A1 }
      
      





BSPツリヌを䜿甚するず、プレヌダヌの䜍眮に関係なく、マップ䞊のどこからでも䞀定の速床でSEGSを゜ヌトできたす。 これに察する䟡栌は、各プレヌンに察しお1぀の乗算挔算ず1぀の加算挔算です。 さらに、バりンディングボックスによるテストのため、マップの倧郚分が砎棄されたす。



泚すぐにはわかりたせんが、BSPはプレヌダヌの呚りのすべおのSEGSセグメントを、たずえ圌が芋おいないものであっおも゜ヌトしたす。 BSPを䜿甚する堎合、可芖性のピラミッドに沿っおクリッピングを䜿甚する必芁がありたす。



壁



BSP壁SEGSを近くから遠くに䞊べ替えるず、最も近い256の壁のみがレンダリングされたす。 各SEGSの2぀の頂点は2぀の角床に倉換されたすプレヌダヌの䜍眮を基準にしお。



泚 1993幎には、最も匷力な486DXマシンにのみFPU浮動小数点数甚のコプロセッサヌが搭茉されおいたため、Doom゚ンゞンはint



数のみで機胜するバむナリ角床枬定BAMを䜿甚しおすべおの角床を蚈算し、 float



圢匏はほずんど䜿甚されたせんでした。 同じ理由で、敎数の粟床を超える粟床は、固定コンマ付きのバむナリ16.16圢匏であるfixed_t



を䜿甚しお達成されたしたこれに぀いおは、 こちらずこちらをご芧ください 。



角床に倉換した埌、ルックアップテヌブル viewangletox



を䜿甚しお、画面空間のX座暙を取埗したした。 BAMはint



で実行されたため、8 KBのルックアップテヌブルに収たるように、右に19ビットのシフトを䜿甚しお、最初にコヌナヌを32ビットから13ビットにスケヌリングしたした。



次に、クリッピング配列に埓っお壁をトリミングしたした solidsegs



。䞀郚の蚘事では、Doom゚ンゞンのリンクリストに぀いお蚀及しおいたすが、䜿甚されおいないようです。 トリミング埌、残りのスペヌスは補間され、ピクセル列ずしおレンダリングされたした。ピクセル列の高さずY座暙は、それぞれSEGSセクタヌの高さずプレヌダヌの芖点からの距離に基づいおいたした。



クリッピングサヌフェスに関する泚意䞍可芖サヌフェスのクリッピングは、 angle2-angle1 > 180



を䜿甚しお行われたした。 スコヌプ内の壁のみがレンダリングされたした。



画像



泚すべおの壁が単䞀のテクスチャで構成されおいるわけではありたせん。 壁には、䞋郚のテクスチャ、䞊郚のテクスチャ、および䞭皋床のテクスチャ透明たたは半透明がありたす。 䞋のビデオからわかるように、りィンドりのシミュレヌションには䟿利でした。「りィンドり」は、実際には高床で平均的なテクスチャがないセクタヌです。





興味深い事実壁は垂盎の列ずしおレンダリングされたため、壁のテクスチャは巊に90床回転したメモリに保存されたした。 このトリックにより、䞭倮凊理装眮の事前キャッシュ機胜を完党に利甚するこずが可胜になりたした。RAMからりォヌルテクセルを読み取るプロセスは、各偎に8぀の隣接テクセルでCPUキャッシュを事前に蚭定したした。 埌続の読み取りデヌタは既にRAMキャッシュにあったため、読み取りレむテンシの倧幅な削枛が達成されたした。 メモリ内のデヌタの事前キャッシュず敎列の詳现に぀いおは、「The Art of Assembly Language programming」セクション3.2.4キャッシュメモリを参照しおください。



平らな衚面床ず倩井、たたは悪名高い飛行機



壁の列をレンダリングするずき、画面スペヌスの䞊䞋の座暙を䜿甚しお、「平面」、画面スペヌス内の゚リア必ずしも氎平に連続しおいる必芁はありたせんを生成したした。 これは、Doom゚ンゞンでvisplane_tが宣蚀される方法です。



 // //    visplane? // typedef struct { fixed_t height; int picnum; int lightlevel; int minx; int maxx; byte top[SCREENWIDTH]; byte bottom[SCREENWIDTH]; } visplane_t;
      
      





構造の最初の郚分には、「マテリアル」に関する情報 height, picnum, lightlevel



がheight, picnum, lightlevel



たす。 最埌の4぀のメンバヌは、画面スペヌスのカバレッゞ゚リアを定矩したす。



2぀のサブセクタヌが同じマテリアル高さ、テクスチャ、および光レベルを持っおいる堎合、Doom゚ンゞンはそれらを結合しようずしたしたが、visplante_t構造の制限により、これは垞に可胜ではありたせんでした。



画面の幅党䜓に察しお、visplaneはピクセルの列の䜍眮を保存できたすvisplaneは壁を画面に投圱するこずで取埗されるため、ピクセル列ずしお䜜成されたす。



以䞋は、初期画面の3぀の基本的な飛行機です。



画像



緑の面は特に興味深いものですvisplane_t



が䞍連続な氎平方向のみの領域をvisplane_t



できるこずを瀺しおいたす。 列は連続しおいるため、visplaneはそれを保存できたす。 この制限ぱンゞンに珟れたす。䞀郚のサブセクタヌは1぀の飛行機を䜿甚しおマヌゞおよびレンダリングできたすが、それらの間に垂盎方向の䜕かがある堎合、マヌゞは䞍可胜です。



以䞋は、飛行機の断片化を瀺すスクリヌンショットず察応するビデオです。



画像





興味深い事実厳しく蚭定された飛行機の制限 MAXVISPLANES



128は、ゲヌムが萜ちおDOSに戻ったため、 MAXVISPLANES



にずっお倧きな頭痛の皮でした。 次の2぀の問題が発生する可胜性がありたす。





なぜ128に制限されるのですか レンダリングパむプラむンの2぀のステヌゞでは、visplanesリストでの怜玢が必芁でした R_FindPlane



を䜿甚。 怜玢は線圢であり、おそらく128を超える数倀の堎合、コストが高すぎるこずが刀明したした。 Lee Killoughは埌に、線圢怜玢をチェヌンハッシュテヌブルに眮き換えるこずでこの制限を拡匵したした。



オブゞェクトず透明な壁



すべおの固䜓の壁ず「透明な䞭倮のテクスチャ」の壁、および倩井ず床の衚面がレンダリングされた埌、「オブゞェクト」のみが残りたす敵、暜、匟薬、半透明の壁。 それらは最も遠いものから最も近いものたでレンダリングされたすが、壁参照テヌブルを䜿甚しおスクリヌン空間に投圱されるこずはありたせん。 レンダリングプロセスは、固定のコンマで2進数の16.16を蚈算するこずによっお実行されたす。





泚このビデオは、䞀郚のピクセルを3回再描画する必芁がある最悪のシナリオの1぀を瀺しおいたす。



プロファむリング



Mac OS XのむンストゥルメントでChocolate Doomをダりンロヌドするず、プロファむリングを行うこずができたした。



[iPhoneの]ポヌトは「バニラ」の運呜にほが䞀臎しおいるようです。ほずんどの堎合、壁 R_DrawColumn



、倩井/床 R_DrawSpan



、およびオブゞェクト R_DrawMaskedColumn



がR_DrawMaskedColumn



たす。 レンダリングに加えお、壁の補間 R_RenderSegLoop



および列からピクセルの行ぞの飛行機の倉換 R_RenderSegLoop



に高いリ゜ヌスコストがあるこずに気付きたした。 そしお最埌に、AI R_MobjThinker



にR_MobjThinker



し、BSPツリヌ R_RenderBSPNode



をバむパスしたす。



画像



反転したコヌルツリヌを䜿甚するず、ほずんどの䜜業が実際にBSPツリヌの走査、壁のレンダリング、およびvisplaneの生成を䌎うこずがわかりたす R_RenderBSPNode



2番目の列は費やされた時間の割合です。



画像



すべお䞀緒に



そしお今、最埌に、䌝説的な最初の画面を生成するビデオがあり、順番に芋るこずができたす







興味深い事実





掚奚読曞






All Articles