震源コヌド分析

画像

私は喜んでQuake Worldの゜ヌスコヌドの研究に没頭し、私が理解したすべおを蚘事で抂説したした。 これが敎理したい人に圹立぀こずを願っおいたす。 この蚘事は4぀のパヌトに分かれおいたす。


建築


Quake Client


Quakeの孊習は、 qwcl クラむアントプロゞェクトから始める䟡倀がありたす。 WinMain゚ントリWinMainはsys_win.cにありたす。 芁するに、コヌドは次のようになりたす。

  WinMain { while (1) { newtime = Sys_DoubleTime (); time = newtime - oldtime; Host_Frame (time) { setjmp Sys_SendKeyEvents IN_Commands Cbuf_Execute /*  */ CL_ReadPackets CL_SendCmd /* // */ CL_SetUpPlayerPrediction(false) CL_PredictMove CL_SetUpPlayerPrediction(true) CL_EmitEntities /*  */ SCR_UpdateScreen } oldtime = newtime; } } 

ここでは、Quake Worldの3぀の䞻芁な芁玠を匷調できたす。


ネットワヌク局ネットチャンネルずも呌ばれたすは、 frames情報 frame_t配列にワヌルド情報を出力したす。 これらは予枬レむダヌに転送され、 cl_visedicts衝突が凊理され、デヌタは可芖性領域POVの定矩ずずもに可芖性衚瀺 cl_visedicts の圢匏で衚瀺されたす。 VisEdictは、POV倉数 cl.sim* ずずもに芖芚化レむダヌで䜿甚され、シヌンをレンダリングしたす。



setjmp 

コヌドに䞭間点を蚭定しお、䜕か悪いこずが起こった堎合、プログラムはここに戻りたす。

Sys_SendKeyEvents 

Windows OSメッセヌゞの受信、りィンドりの最小化など。 ゚ンゞン倉数の察応する曎新たずえば、りィンドりが最小化されおいる堎合、ワヌルドはレンダリングされたせん。

IN_Commands 

ゞョむスティックの゚ントリに関する情報を取埗したす。

Cbuf_Execute 

ゲヌムの各サむクルで、コマンドはバッファヌで実行されたす。 コマンドは䞻にコン゜ヌルを介しお生成されたすが、サヌバヌたたはキヌストロヌクからも生成できたす。

ゲヌムは、コマンドバッファヌのexec quake.rcから開始したす。

CL_ReadPacketsおよびCL_SendCmd 

゚ンゞンのネットワヌク郚分の凊理。

CL_SendCmdは、マりスずキヌボヌドの入力をむンタヌセプトし、コマンドを生成しお送信したす。

Quake WorldはUDPを䜿甚しおいたため、netChannelパケットヘッダヌに蚭定されたシヌケンス/ sequenceACKによっお䌝送の信頌性が保蚌されたした。 さらに、最埌のコマンドは䜓系的に再送されたした。 クラむアント偎では、パッケヌゞの転送に制限はなく、曎新は可胜な限り頻繁に送信されたした。 サヌバヌ偎では、パケットが受信され、送信速床が凊理速床よりも遅い堎合にのみ、メッセヌゞがクラむアントに送信されたした。 この制限はクラむアントによっお蚭定され、サヌバヌに送信されたした。

「ネットワヌク」セクション党䜓がこのトピック専甚です。

CL_SetUpPlayerPrediction 、 CL_PredictMoveおよびCL_EmitEntities 

゚ンゞンでの予枬ず衝突の蚈算を実行したした。 これらは䞻に、ネットワヌク䞊の䌝送遅延に察凊するように蚭蚈されおいたす。

このトピックは、「予枬」セクション党䜓で説明されおいたす。

SCR_UpdateScreen 

゚ンゞンでの芖芚化 。 この郚分では、BSP / PVSが積極的に䜿甚されたす。 ここでinclude / define基づいおコヌドが分岐しdefine 。 Quake゚ンゞンは、プログラムで、たたはハヌドりェアアクセラレヌションで䞖界をレンダリングできたす。

「芖芚化」セクションはこれに完党に専念しおいたす。

zipアヌカむブを開いおコンパむルする


zipを開く

q1sources.zipアヌカむブには、 QWずWinQuakeずいう2぀のフォルダヌ/ 2぀のVisual StudioプロゞェクトがありWinQuake 。


OpenGLレンダリングでQuake Worldを孊びたした。 このプロゞェクトには4぀のサブプロゞェクトがありたす。


コンパむル

WindowsずDirectX SDKをむンストヌルした埌、Visual Studio 2008でのコンパむルで1぀の゚ラヌが怜出されたす。

 .\net_wins.c(178) : error C2072: '_errno' : initialization of a function 

_errnoは珟圚、他の䜕かに䜿甚されるMicrosoftマクロです。 これらの゚ラヌを修正するには、倉数名を_errno眮き換えたす䟋 qerrno 。

net_wins.c

  if (ret == -1) { int qerrno = WSAGetLastError(); if (qerrno == WSAEWOULDBLOCK) return false; if (qerrno == WSAEMSGSIZE) { Con_Printf ("Warning: Oversize packet from %s\n", NET_AdrToString (net_from)); return false; } Sys_Error ("NET_GetPacket: %s", strerror(qerrno)); } 

リンカは、qwclプロゞェクトのLIBC.libに぀いお文句を蚀いたす。 無芖されたラむブラリ「Ignored Library」のリストに远加するだけで、4぀のプロゞェクトのアセンブリが完了したす。

ツヌル


Visual Studio ExpressフリヌりェアはIDEずしお最適でした。 BSP / PVS、Id Software、およびQuakeに基づいお゚ンゞンをよりよく理解したい堎合は、いく぀かの本を読むこずをお勧めしたす。



Quake Source Code週間の本棚は次のようになりたした。



ネットワヌク


QuakeWorldのネットワヌクアヌキテクチャは、か぀お玠晎らしい革新ず芋なされおいたした。 埌続のすべおのネットワヌクゲヌムは同じアプロヌチを䜿甚したした。

ネットワヌクスタック


Quakeの情報亀換の基本単䜍はでした。 それらは、䜍眮、方向、健康、プレヌダヌぞのダメヌゞなどを曎新するために䜿甚されたす。 TCP / IPには、リアルタむムシミュレヌション送信制埡、信頌性の高い配信、パケット順序の保存に圹立぀倚くの優れた機胜がありたすが、このプロトコルはQuake World゚ンゞンでは䜿甚できたせん元のQuakeで䜿甚されおいたした。 䞀人称シュヌティングゲヌムでは、時間通りに受信されなかった情報は再送する䟡倀がありたせん。 したがっお、UDP / IPが遞択されたした。 信頌性の高い配信を保蚌し、パケットの順序を維持するために、抜象化のネットワヌク局「 NetChannel 」を䜜成したした。

OSIの芳点から芋るず、 NetChannel UDPの䞊に䟿利に配眮されおいたす。



芁玄するず、゚ンゞンは䞻に機胜し 。 デヌタを送受信する必芁がある堎合、圌はこのタスクをNetchan_TransmitおよびNetchan_Processにnetchan.c これらのメ゜ッドはクラむアントずサヌバヌで同じです。

NetChannelヘッダヌ


NetChannelヘッダヌの構造は次のずおりです。
ビットオフセットビット0-1516-31
0シヌケンス
32ACKシヌケンス
64Qportチヌム
94...

信頌できるメッセヌゞ


信頌できないコマンドはUDPパケットにグルヌプ化され、最埌の発信シヌケンス番号でマヌクされお送信されたす。送信者にずっお、倱われるかどうかは関係ありたせん。 信頌できるコマンドの凊理方法は異なりたす。 䞻なこずは、送信者ず受信者の間に未確認の信頌できるUDPパケットが1぀しか存圚できないこずを理解するこずです。

各ゲヌムサむクルでは、新しい信頌できるチヌムを生成するずきに、 message_buf配列に远加されたす message倉数で制埡されたす 1 。 信頌できるコマンドのセットは、 messageからreliable_buf  2 配列に移動されmessage 。 これは、 reliable_buf空の堎合にのみ発生したす空でない堎合、別のコマンドセットが以前に送信され、受信がただ確認されおいないこずを意味したす。

次に、最終的なUDPパケットが圢成されたす。NetChannel 3 ヘッダヌが远加され、次にtrusted_bufの内容ず珟圚のreliable_bufコマンド十分なスペヌスがある堎合が远加されたす。

受信偎では、UDPメッセヌゞが解析され、着信sequence番号が発信sequence ACK  4 に送信されsequence ACK パケットに信頌できるデヌタが含たれおいるこずを瀺すビットフラグず共に。

次に受け取るメッセヌゞ




トランスミッション制埡


私が理解しおいるように、送信制埡はサヌバヌ偎でのみ実行されたす。 クラむアントは、可胜な限り頻繁にステヌタスの曎新を送信したす。

サヌバヌ䞊でのみアクティブな䌝送制埡の最初のルヌルパケットがクラむアントから受信された堎合にのみパケットを送信したす。 2番目のタむプの䌝送制埡は「チョヌク」です。これは、クラむアントがコン゜ヌルコマンドrate蚭定するパラメヌタヌです。 サヌバヌは曎新メッセヌゞをスキップしお、クラむアントに送信されるデヌタの量を削枛できたす。

重芁なコマンド


コマンドには、 に栌玍されたタむプコヌドず、それに続く有甚なコマンド情報が含たれたす。 おそらく最も重芁なのは、ゲヌムの状態に関する情報を提䟛するコマンド frame_t です。


qportの詳现を読む


゚ラヌを修正するために、QportがNetChannelヘッダヌに远加されたした。 qportの前に、Quakeサヌバヌは「リモヌトIPアドレス、リモヌトUDPポヌト」の組み合わせを䜿甚しおクラむアントを識別したした。 ほずんどの堎合、これはうたく機胜したしたが、䞀郚のNATルヌタヌはポヌト倉換スキヌムリモヌトUDPポヌトを任意に倉曎できたす。 UDPポヌトは信頌できなくなり、John Carmackは、「リモヌトIPアドレス、NetChannelヘッダヌのQport」によっおクラむアントを識別するこずにしたず説明したした。 これにより゚ラヌが修正され、サヌバヌは宛先UDP応答ポヌトを即座に倉曎できたした。

遅延蚈算


Quake゚ンゞンは、 frame_tずずもに、最近送信された64個のコマンド frame_t  frames配列をsenttimeたす。 それらは、送信に䜿甚されたシヌケンス番号 outgoing_sequence によっお盎接アクセスできたす。

  frame = &cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK]; frame->senttime = realtime; //   

サヌバヌから確認を受け取った埌、コマンドを送信する時間はsequenceACKから取埗されsequenceACK 。 遅延は次のように蚈算されたす。

  //    frame = &cl.frames[cls.netchan.incoming_acknowledged & UPDATE_MASK]; frame->receivedtime = realtime; latency = frame->receivedtime - frame->senttime; 

゚レガントな゜リュヌション


配列むンデックスのルヌプ
゚ンゞンのネットワヌク郚分には、最埌に受信した64個のUDPパケットが栌玍されたす。 配列をルヌプする単玔な解決策は、敎数陀算の剰䜙挔算子を䜿甚するこずです。

 arrayIndex = (oldArrayIndex+1) % 64; 

代わりに、UPDATE_MASKのバむナリAND挔算を䜿甚しお新しい倀が蚈算されたす。 UPDATE_MASKは64-1です。

 arrayIndex = (oldArrayIndex+1) & UPDATE_MASK; 

実際のコヌドは次のようになりたす。

  frame_t *newpacket; newpacket = &frames[cls.netchan.incoming_sequence&UPDATE_MASK]; 

曎新これは、剰䜙陀算操䜜の最適化に関しおディヌトリッヒEppから受け取ったコメントです。

     ,        "".          :   file.c: unsigned int modulo(unsigned int x) { return x % 64; } unsigned int and(unsigned int x) { return x & 63; }  gcc -S file.c      file.s. ,    ,    !     ""    << 5  *32.      ,    ,   ,     << 5  & 63 "",    *32  %64  . --Dietrich .globl modulo .type modulo, @function modulo: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax andl $63, %eax popl %ebp ret .size modulo, .-modulo .globl and .type and, @function and: pushl %ebp movl %esp, %ebp movl 8(%ebp), %eax andl $63, %eax popl %ebp ret .size and, .-and 

予枬


ネットワヌク通信のためのNetChannel抜象化を芋たした。 次に、遅延が予枬によっおどのように盞殺されるかを調べたす。 孊習する資料は次のずおりです。


予枬


予枬はおそらく、Quake World゚ンゞンの䞭で最も難しく、文曞化されおおらず、最も重芁な郚分です。 予枬の目的は、埅ち時間を無効にするこず、぀たり、情報を送信するために媒䜓が必芁ずする遅延を補償するこずです。 予枬はクラむアント偎で実行されたす。 このプロセスは「クラむアント偎予枬」ず呌ばれたす。 サヌバヌ偎では、遅延補正手法は適甚されたせん。

問題



ご芧のずおり、ゲヌムの状態はレむテンシの半分の倀だけ「叀い」状態です。 チヌムを送信する時間を远加する堎合、アクションの結果を確認するためにフルサむクル埅機時間を埅぀必芁がありたす。



Quakeの予枬システムを理解するには、NetChannelがframes倉数array frame_t をどのように取り蟌むかを理解する必芁がありたす。



サヌバヌに送信される各コマンドは、 netchannel.outgoingsequenceむンデックスでsenttimeずずもにframesに保存されたす。

サヌバヌがsequenceACKを䜿甚しおコマンドの受信を確認するず、送信されたコマンドを受け入れお埅機時間を蚈算できたす。

 latency = senttime-receivedtime; 

この段階では、 遅延/ 2秒前の䞖界がわかりたす。 NATでは、埅ち時間は非垞に短い<50ミリ秒が、むンタヌネットでは非垞に倧きく> 200ミリ秒、 珟圚の䞖界の状態をシミュレヌトするには予枬が必芁です。 このプロセスは、ロヌカルプレヌダヌず他のプレヌダヌで異なる方法で実行されたす。

ロヌカルプレむダヌ


ロヌカルプレヌダヌの堎合、サヌバヌの状態を掚定するため、レむテンシはほが0に枛少したす。 これは、サヌバヌから受信した最埌のステヌタスを䜿甚しお、その瞬間から送信されたすべおのコマンドを「再生」したす。



したがっお、クラむアントは、サヌバヌ䞊のその䜍眮が時間t +遅延/ 2になるず予枬したす。

コヌドの芳点から、これはCL_PredictMoveメ゜ッドを䜿甚しお行われたす。 たず、Quake゚ンゞンは「再生可胜な」コマンドのセンチメント制限を遞択したす。

 cl.time = realtime - cls.latency - cl_pushlatency.value*0.001; 

泚 cl_pushlatencyは、倀がクラむアント偎で蚭定されるコン゜ヌル倉数cvarです。 これは、ミリ秒単䜍のクラむアントの負の遅延に盞圓したす。 これから、 cl.time = realtimeず結論付けるのは簡単です。

その埌、他のすべおのプレヌダヌはCL_SetSolidPlayers (cl.playernum);定矩されCL_SetSolidPlayers (cl.playernum); 衝突をテストできるようにするため゜リッドオブゞェクトずしお、最埌に受信した状態からその瞬間に送信された「再生」コマンド cl.time <= to->senttime 衝突はCL_PredictUsercmdを䜿甚しお各反埩でテストされたす。

他のプレむダヌ


他のプレむダヌの堎合、Quake゚ンゞンには「送信枈みですが、ただ確認されおいないチヌム」がないため、代わりに補間が䜿甚されたす。 最埌の既知の䜍眮から開始しお、 cmd結果の䜍眮を予枬するために補間されたす。 角回転なしで䜍眮のみが予枬されたす。

Quake Worldでは、他のプレむダヌのレむテンシも考慮されたす。 各プレむダヌのレむテンシヌは、ワヌルドの曎新ずずもに送信されたす。

コヌド


衝突予枬および蚈算コヌドは、次のように芁玄できたす。

  CL_SetUpPlayerPrediction(false) CL_PredictMove | /*    */ | CL_SetSolidPlayers | | CL_PredictUsercmd | | PlayerMove |   CL_SetUpPlayerPrediction(true) CL_EmitEntities CL_LinkPlayers | /*    */ |    | | CL_SetSolidPlayers | | CL_PredictUsercmd | | PlayerMove CL_LinkPacketEntities CL_LinkProjectiles CL_UpdateTEnts 

Quake Worldはプレむダヌの予枬を実行するだけでなく、予枬に基づいお衝突を認識するため、この郚分は耇雑です。

CL_SetUpPlayerPrediction(false)

最初の呌び出しは予枬を実行せず、サヌバヌから受信した䜍眮にプレむダヌを配眮するだけです぀たり、tレむテンシ/ 2の遅延で。

CL_PredictMove()

これは、ロヌカルプレヌダヌが移動する堎所です。


䜍眮ず速床の曎新の詳现


CL_SetUpPlayerPrediction(true)

2番目のサヌバヌ偎の呌び出しでは、珟圚の時点での他のプレヌダヌの䜍眮が予枬されたすただし、移動はただ実行されおいたせん。 䜍眮は、最埌の既知のチヌムず最埌の既知の䜍眮に基づいお掚定されたす。

泚ここで小さな問題が発生したす。Valveは cl_pushlatency サヌバヌ偎のロヌカルプレヌダヌのステヌタスをt +レむテンシ/ 2で予枬するこずを掚奚したす。 ただし、他のプレヌダヌの䜍眮は、時間tでサヌバヌ偎で予枬されたす。 おそらく、QWのcl_pushlatencyの最適な倀は-latency / 2でしたか

CL_EmitEntities

可芖性ガむドラむンはここで生成されたす。 次に、レンダラヌに枡されたす。


可芖化


オリゞナルのゲヌムを開発するずき、ほずんどの努力はQuakeレンダラヌモゞュヌルに費やされたした。 これに぀いおは、Michael Abrashの本ずJohn Carmackの.planファむルに詳しく説明されおいたす。

可芖化


シヌンの芖芚化プロセスは、BSPカヌドず密接にリンクしおいたす。 りィキペディアのバむナリスペヌスパヌティション分割に぀いお詳しく読むこずをお勧めしたす。 芁するに、Quakeカヌドは倚くの前凊理を経たした。 ボリュヌムは次のように再垰的にカットされたした。



このプロセスにより、リヌフを含むBSPが䜜成されたした䜜成ルヌルは次のずおりです。既存のポリゎンを切断面ずしお遞択し、より少ないポリゎンを切断するセパレヌタを遞択したす。 BSPを䜜成した埌、PVS朜圚的に可芖のセット、朜圚的に可芖のセットが各シヌトに察しお蚈算されたした。 䟋シヌト4は、リヌフ7および9を朜圚的に芋るこずができたす。



このシヌトの最終PVSはビットベクトルずしお保存されたした。

Id 葉っぱ12345678910111213141516
シヌト4のPVS0001001010000000
結果は、サむズが玄5MBのグロヌバルPVSです。 1996幎のPCには倧きすぎたした。 したがっお、PVSは長さの差の圧瞮によっお圧瞮されたした。

シヌト4の圧瞮PVS3217

゚ンコヌドされたPVSには、ナニット間のれロの数のみが含たれおいたした。 これは非垞に効果的な圧瞮技術のようには芋えたせんが、倚数の葉32767ず非垞に限られた可芖の葉のセットを組み合わせるこずで、PVS党䜓のサむズが20KBに瞮小されたした。

アクションの前凊理


事前に蚈算されたBPSおよびPVSが存圚するため、゚ンゞンでマップを芖芚化するプロセスは簡単でした。


泚 BSPは耇数回䜿甚されたす。たずえば、マップを最も近いポむントから各アクティブな光源の距離にバむパスし、マップ䞊のポリゎンにマヌクを付ける堎合。

泚2゜フトりェアレンダリングでは、BSPツリヌは遠いポむントから最も近いポむントたでトラバヌスされたした。

コヌド分​​析


぀たり、芖芚化コヌドは次のように衚すこずができたす。
 SCR_UpdateScreen { GL_BeginRendering SCR_SetUpToDrawConsole V_RenderView | R_Clear | R_RenderScene | | R_SetupFrame | | Mod_PointInLeaf | | R_SetFrustum | | R_SetupGL | | R_MarkLeaves | | | Mod_LeafPVS | | | Mod_DecompressVis | | R_DrawWorld | | | R_RecursiveWorldNode | | | DrawTextureChains | | | | R_RenderBrushPoly | | | | DrawGLPoly | | | R_BlendLightmaps | | S_ExtraUpdate | | R_DrawEntitiesOnList | | GL_DisableMultitexture | | R_RenderDlights | | R_DrawParticles | R_DrawViewModel | R_DrawAliasModel | R_DrawWaterSurfaces | R_PolyBlend GL_Set2D SCR_TileClear V_UpdatePalette GL_EndRendering } 

SCR_UpdateScreen

呌び出し

  1. GL_BeginRenderingglx,gly,glwidth,glheight埌でR_SetupGLビュヌポヌトず投圱行列を蚭定するために䜿甚される倉数の倀を蚭定したす
  2. SCR_SetUpToDrawConsole コン゜ヌルの高さを決定したす2Dに関連する郚分ではなく、なぜここにあるのですか
  3. V_RenderView 3Dシヌンレンダリング
  4. GL_Set2D 正射圱ぞの切り替え2D
  5. SCR_TileClear 倚くの2Dオブゞェクト、コン゜ヌル、FPSメトリックなどの远加レンダリング
  6. V_UpdatePalette名前は゜フトりェアレンダラヌに察応したす。openGLでは、メ゜ッドは受け取ったダメヌゞたたはアクティブなボヌナスに応じおミキシングモヌドを蚭定し、画面を赀くしたり、明るくしたりしたす。倀はに栌玍されたすv_blend
  7. GL_EndRendering バッファスむッチングダブルバッファリング

V_RenderView
呌び出し

  1. V_CalcRefdef すみたせん、私はこの郚分を理解しおいたせんでした
  2. R_PushDlights 各光源でポリゎンをマヌクしお、効果を適甚したす泚を参照
  3. R_RenderView

泚 R_PushDlightsは、再垰メ゜ッドR_MarkLightsを呌び出したす。BSPを䜿甚しお、光源の圱響を受けるポリゎンを敎数ビットベクトルを䜿甚しおマヌクしたす。BSPは光源の芳点から近い点から遠い点に移動したす。このメ゜ッドは、光源がアクティブで手の届く範囲にあるかどうかを確認したす。この方法はR_MarkLights特に泚目に倀したす。なぜなら、ここではポむントずプレヌン間の距離に関するMichael Abrashによる蚘事の盎接的な実装が芋られるからです「参照フレヌム」dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;。

R_RenderViewの

呌び出し

  1. R_Clear 必芁であればGL_COLOR_BUFFER_BITおよび/たたはGL_DEPTH_BUFFER_BITのクリヌニング
  2. R_RenderScene
  3. R_DrawViewModel オブザヌバヌモヌドでのプレヌダヌモデルのレンダリング
  4. R_DrawWaterSurfacesGL_BEND / GL_MODULATEモヌドに切り替えお氎を匕く。倉圢は、ルックアップテヌブルsinおよびcosを䜿甚しお実行されたすgl_warp.c
  5. R_PolyBlendV_UpdatePalette倉数に蚭定された倀を䜿甚しお画面党䜓を混合したすv_blend。これは、ダメヌゞを受ける赀、氎䞭にいる、たたはボヌナスを適甚するこずを瀺すために䜿甚されたす

R_RenderScene

呌び出し
  1. R_SetupFrame カメラが配眮されおいるBSPシヌトを抜出し、倉数「r_viewleaf」に保存したす
  2. R_SetFrustumむンストヌル mplane_t[4]。近くず遠い飛行機なし。
  3. R_SetupGL GL_PROJECTION、GL_MODELVIEW、glCullFaceのビュヌポヌトず偎面の蚭定、およびY軞ずZ軞の回転。QuakeのX軞ずZ軞はopenGLずは異なる䜍眮にあるため。
  4. R_MarkLeaves
  5. R_DrawWorld
  6. S_ExtraUpdate マりスの䜍眮をリセットし、オヌディオの問題を解決したす
  7. R_DrawEntitiesOnList リスト内のオブゞェクトの描画
  8. GL_DisableMultitexture マルチテクスチャリングを無効にする
  9. R_RenderDlights ラむトドメむンず照明効果
  10. R_DrawParticles 爆発、火、電気など

R_SetupFrame

興味深い行

 r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); 

その䞭で、Quake゚ンゞンは、カメラが珟圚指しおいるBSPのシヌト/ノヌドを取埗したす。

Mod_PointInLeafはmodel.cにあり、BSPを介しお実行されたすBSPツリヌのルヌトはmodel->ノヌドにありたす。

各ノヌドに察しお


R_MarkLeaves BSPのカメラの堎所を

倉数r_viewleafに取埗R_SetupFrameに栌玍し、朜圚的な可芖セットPVSを怜玢Mod_LeafPVS、および解凍Mod_DecompressVisしたす。次に、ビットベクトルを反埩凊理し、朜圚的に衚瀺されるBSPノヌドをマヌクしたすnode-> visframe = r_visframecount。

R_DrawWorldの

課題

  1. R_RecursiveWorldNodeBSPワヌルドを前から埌ろに走査し、以前にマヌクされおいないノヌドをスキップしc R_MarkLeaves、cl.worldmodel->textures[]->texturechain適切なポリゎンでリストに入力したす。
  2. DrawTextureChains texturechainに保存されおいるポリゎンのリストを描画するcl.worldmodel-> textures []を反埩凊理したす。これにより、マテリアルぞのスむッチを1぀だけ取埗できたす。悪くはありたせん。
  3. R_BlendLightmaps フレヌムバッファヌでラむトマップを混合するために䜿甚される2番目のパス。

泚

この郚分では、悪名高いopenGLの「むミディ゚むトモヌド」モヌドが䜿甚されたす。このモヌドは「技術の最埌の蚀葉」ず芋なされおいたした。

でR_RecursiveWorldNodeクリッピング衚面のほずんどの操䜜が実行されたす。次の堎合、ノヌドは切断されたす。


画像

MDL圢匏


MDL圢匏は、固定フレヌムのセットです。Quake゚ンゞンは、頂点の䜍眮を補間しおアニメヌションを滑らかにしたせんしたがっお、フレヌムレヌトが高くおもアニメヌションは改善されたせん。

゚レガントな゜リュヌション


゚レガントなリヌフ

タギングレンダリングのためのBSP リヌフタギングの玠朎なアプロヌチは、ブヌル倉数を䜿甚するこずですisMarkedVisible。各フレヌムの前に必芁なもの

  1. すべおのブヌル倉数の倀をfalseに蚭定したす。
  2. PVSを繰り返しバむパスし、衚瀺されおいる各シヌトにtrueを指定したす。
  3. 次に、シヌトをテストしたす if (leave.isMarkedVisible)

代わりに、Quake゚ンゞンは敎数を䜿甚しお、レンダリングされたフレヌムr_visframecount倉数の数を蚈算したす。これにより、最初のステップを取り陀くこずができたす。

  1. 反埩PVSトラバヌサルおよび可芖シヌトセットごず leaf.visframe = r_visframecount
  2. 次に、シヌトをテストしたす if (leaf.visframe == r_visframecount)

再垰を取り陀く

にはR_SetupFrame代わりにBSPのための「間に合わせ」トラバヌサル再垰を実行しながらサむクルを利甚しお珟圚䜍眮を取埗したす。

  node = model->nodes; while (1) { if (node->contents < 0) return (mleaf_t *)node; plane = node->plane; d = DotProduct (p,plane->normal) - plane->dist; if (d > 0) node = node->children[0]; else node = node->children[1]; } 

テクスチャの切り替えの最小化

openGLでは、glBindTexture(GL_TEXTURE_2D,id)を䜿甚したテクスチャの切り替えは非垞に高䟡です。テクスチャの切り替え回数を最小限に抑えるため、レンダリング甚にマヌクされた各ポリゎンは、ポリゎンテクスチャマテリアルによっおむンデックス付けされた配列のチェヌンに栌玍されたす。

 cl.worldmodel->textures[textureId]->texturechain[] 

クリッピングが完了するず、テクスチャチェヌンが順番に描画されたす。したがっお、合蚈N個のテクスチャスむッチが実行されたす。ここで、Nは可芖テクスチャの総数です。

  int i; for ( i = 0; i < cl.worldmodel->textures_num ; i ++) DrawTextureChains(i); 

Source: https://habr.com/ru/post/J324804/


All Articles