Microsoft DirectX 8 开发人员常见问题
Microsoft DirectX 8 開發人員常見問題
:
Microsoft DirectX 8 開發人員常見問題
?
摘要:本文對與 Microsoft DirectX 8.0 版有關的常見開發問題進行解答,其中包括有關 Direct3D、DirectSound 和 DirectPlay 的章節。
目錄
一般性 DirectX 開發事宜
Direct3D
???一般問題
???幾何(頂點)處理
???性能調諧
???Direct3DX 實用程序庫
DirectSound
DirectPlay
一般性 DirectX 開發事宜
我在試圖編譯示例時,為何得到那么多錯誤消息?
您可能沒有將 include 路徑設置正確。許多編譯器(包括 Microsoft? Visual C++?)包含 SDK 的一個較早版本,因此如果您的 include 路徑首先搜索標準的編譯器 include 目錄,則您會得到不正確版本的頭文件。為解決這一問題,請確保 include 路徑和庫路徑被設為搜索 DirectX include 和庫路徑。另請參見 SDK 中的 dxreadme.txt 文件。如果您安裝 DirectX SDK 而您又在使用 Visual C++,則可以選擇讓安裝程序為您設置各個 include 路徑。
我得到關于全局唯一標識符 (GUID) 符號重復或缺失的連接器錯誤,怎么辦?
您使用的各種 GUID 應該得到一次性定義,且只能定義一次。如果您在插入 DirectX 頭文件之前用 #define 定義 INITGUID 符號,則會插入 GUID 的定義。因此,你應確保只對一個編譯單元進行此類操作。這一方法的一個替代方案就是用 dxguid.lib 庫進行連接,其中包含所有 DirectX GUID 的定義。 如果您使用這一方法(建議),則您永遠不要通過 #define 定義 INITGUID 符號。
我能否將指針指向一個到較低版本號的 DirectX 接口?
不能。DirectX 接口屬于 COM 接口。 這意味著不要求將較高版本號的接口從相應的低版本號導出。因此,獲得到 DirectX 對象的一個不同接口的唯一安全方法就是使用接口的 QueryInterface 方法。該方法是標準的 IUnknown 接口的一部分,所有 COM 接口必須從其導出。
我能在同一應用程序中將 DirectX 8 組件和 DirectX 7 或更早的組件混用嗎?
您可以隨意混用不同版本的“不同組件”;例如,您可以在將 DirectPlay 8 和 DirectDraw 7 用在同一應用程序中。但是,您通常不可以將“同一組件”的不同版本混用在同一應用程序中;例如,您不能混用 DirectDraw 7 和 Direct3D 8 (鑒于這些實際上是同一組件,因為 DirectDraw 已被含入 DirectX 8 的 Direct3D)。
Release 或 AddRef 方法的返回值有何含義?
返回值將是對象的當前參照計數。但是,COM 規范聲明,您不應依賴該返回值;該值通常僅供用于調試目的。您觀察到的值可能并非所期待的,因為各種其它系統對象可能保持著對你所創建的 DirectX 對象的參照。 因此,您不應編寫反復調用 Release 的代碼,一直到參照計數為零,因為此時可以將對象釋放,即使另一組件可能仍舊在對其進行參照。
我釋放 DirectX 接口的次序很重要嗎?
應當沒有問題,因為 COM 接口是參照計數的。 但是,在某些 DirectX 版本中,接口的釋放次序有一些已知的缺陷。 安全起見,在可能的情況下,建議您以與創建時相反的次序釋放接口。
智能指針是什么,我要用它們嗎?
智能指針是一個 C++ 模板類,旨在封裝指針功能。尤其有一些標準智能指針類,用于封裝 COM 接口指針。這些指針自動進行 QueryInterface,而不是進行造型,并替您處理 AddRef 和 Release。您是否使用這些指針,大體上是個人偏好。如果您的代碼包含大量的接口指針復制操作,即使用多重 AddRefs 和 Releases,則智能指針可能會使您的代碼更加簡潔和不易出錯。否則,不用也罷。Visual C++ 包含一個標準的 Microsoft COM 智能指針,是在 "comdef.h" 頭文件中定義的(請在幫助中查找 com_ptr_t)。
我在調試 DirectX 應用程序時遇到問題,能提示一下嗎?
調試 DirectX 應用程序時最常見的問題就是試圖在 DirectDraw 表面被鎖定時進行調試。這一情形會在 Microsoft Windows? 9x 系統上導致 "Win16 Lock" ,因此而無法繪制調試窗口。在鎖定表面時指定 D3DLOCK_NOSYSLOCK 旗標,通常會消除該現象。Windows 2000 沒有這一問題。在開發一個應用程序時,最好運行調試版本的 DirectX 運行時(在安裝 SDK 時進行選擇);該版本進行某些參數證實,并將一些有用的消息輸出到調試程序的輸出窗口。
如何正確地檢查返回代碼?
使用 SUCCEEDED 和 FAILED 宏。 DirectX 方法可以返回多個成功和失敗代碼,因此一個簡單的 "==D3D_OK" 或類似的測試結果不總是夠用的。
DirectDraw 有何變化?
DirectDraw 的大多數功能現已被含入新的 Direct3D8 接口。編制單純 2D 應用程序的開發人員可能會希望繼續使用舊的 DirectX 7 接口。對于編制帶有某些 2D 元素的 3D 應用程序的開發人員,鼓勵其使用 Direct3D 替代程序(例如點對象和公告牌紋理),因為這會改善性能和靈活性。
我如何禁用 ALT+TAB 以及其它的任務切換功能?
請切勿這樣做。
有什么值得推薦的對 COM 進行解釋的書嗎?
Inside COM (《COM 內幕》),Dale Rogerson 著,Microsoft Press 出版,其中對 COM 進行了很好的介紹。如要詳細考察 COM,Essential COM (《COM 精解》),Don Box 著,Longman 出版,這本書也很值得推薦。
有什么關于一般性 Windows 編程的書嗎?
很多。但筆者認為值得推薦的書有:
- Programming Windows (《Windows 編程》),Charles Petzold 著(Microsoft Press 出版)
- Advanced Windows (《Windows 進階》),Jeffrey Richter 著(Microsoft Press 出版)
Direct3D
一般問題
我在何處可以找到有關 3D 圖形技巧的信息?
關于這一主題的標準書是 Computer Graphics: Principles and Practice (《計算機圖形:原理與實踐》),Foley, Van Dam 等著;對于任何想要了解幾何、光柵化以及照明技巧的人來講,這都是一個寶貴的資源。comp.graphics.algorithms 新聞組的 FAQ (“常見問題解答”)也包含有用的資料。
Direct3D 能夠仿真硬件未提供的功能嗎?
這要依具體情況而定。Direct3D 具有一個特性齊全的頂點處理流水線(包含對定制頂點著色器的支持)。但是,沒有為像素級操作提供任何的仿真功能;應用程序必須檢查相應的帽位,并使用 ValidateDevice API 來確定是否支持。
Direct3D 包含有軟件光柵器嗎?
沒有。Direct3D 現在支持插件式軟件光柵器。但是,目前并不默認提供任何軟件光柵器。
Direct3D 幾何代碼使用 3DNow! 和/或 Pentium III SIMD 指令嗎?
使用。 Direct3D 幾何流水線有多個不同的代碼路徑(具體取決于處理器類型),并將使用 3DNow! 或 Pentium III SIMD 指令所提供的特殊的浮點操作(如果這些指令可用的話)。其中包括定制頂點著色器的處理。
我如何防止透明的像素被寫到 z 緩沖區?
您可以借助高于或低于某一給定門限的 alpha 值來將像素濾除。您通過描繪狀態 ALPHATESTENABLE、ALPHAREF 和 ALPHAFUNC 來控制這一操作。
模板緩沖區是什么?
模板緩沖區是一個記錄每個像素信息的附加的緩沖區,很象一個 z 緩沖區。 實際上,該緩沖區就駐在 z 緩沖區的某些位中。常見的模板/z 緩沖區格式為 15 位的 z 和 1 位的模板,或 24 位的 z 和 8 位的模板。在描繪多邊形時,可以針對每個像素,對模板的內容進行簡單的算術操作。例如,可以增加或減少模板緩沖區,或在模板值沒能通過一項簡單的比較測試時,拒絕像素。可以將幀緩沖區的一個區域標出,然后只對標出(或未標出)的區域進行描繪,上述操作對于此類效果十分有用。各種體積效果就是很好的例子,比如陰影量。
我如何使用模板緩沖區來描繪陰影量?
這一效果以及其它體積模板緩沖區效果的關鍵在于模板緩沖區和 z 緩沖區之間的交互作用。帶有陰影量的場景是分三個階段描繪的。首先,照常使用 z 緩沖區來描繪沒有陰影的場景。然后,在模板緩沖區中將陰影標出,如下所示。使用不可見的多邊形繪制陰影量的正面,其中 z 測試被啟用,而 z 寫入被禁用,且在每有一個像素通過 z 測試時,就將模板緩沖區增加一次。以同樣方式描繪陰影量的背面,但是要減少模板值。
現在,請考慮單獨一個像素的情形。假設攝像機不在陰影量中,場景中的相應點就有有四種可能性。如果從攝像機到點的光線不與陰影量相交,則不會繪制任何的陰影多邊形,而模板緩沖區依舊為零。否則,如果點在陰影量的前面,則陰影多邊形會被輸出 z 緩沖區,而模板依舊保持不變。如果點位于陰影量下面,則會描繪同樣多的正面陰影,而模板為零,即增加的次數與減少的次數一樣多。
最后一種可能性就是點位于陰影量中。在這種情況下,陰影量的背面會被輸出 z 緩沖區,但正面則不然,因而模板緩沖區會為非零。結果就是,幀緩沖區位于陰影中的一些部分具有非零的模板值。最后,要實際描繪陰影,整個場景會被一個 alpha 混色的多邊形集充溢一遍,其中僅模板值非零的像素受到影響。在隨 DirectX SDK 一起提供的 "Shadow Volume" 示例中有關于該技巧的一個示例。
Texel (特塞爾)對齊規則是什么?我怎樣才能得到一一映射?
這一點在 DirectX 8 文檔中得到了全面的解釋(在文章標題 Directly Mapping Texels to Pixels(直接將 Texel 映射到像素)下)。 但是總而言之,您應將屏幕坐標偏移一個像素的 –0.5,以便正確地與 texel 對齊。 大多數的插卡正確符合對齊規則,但是有一些較老的插卡或驅動程序則不然。要解決這些問題,建議您最好與相關的硬件廠商取得聯系,請求得到更新過的應驅動程序或其所建議的變通辦法。
D3DCREATE_PUREDEVICE 旗標有何用途?
如果在創建設備時指定了 D3DCREATE_PUREDEVICE 旗標,則 Direct3D 將創建一個“純粹”的設備。這禁用 Get* 族類的方法,并使頂點處理僅限于硬件。這使得 Direct3D 運行時能夠進行某些優化,以提供到驅動程序的最佳路徑,而不必跟蹤那么多的內部狀態。也就是說,您使用 PUREDEVICE 時可以見到一定的性能優勢,但卻犧牲了某些便利條件。
我如何使用顏色鍵控?
DirectX 8 并不支持顏色鍵控。您應當換用 alpha 混色/測試,大體上這是一個更加靈活的技巧,沒有與顏色鍵控相關的一些問題。
我如何枚舉多監視器系統中的所有顯示設備?
與其它的枚舉功能相同,該功能已從基于回調變為由應用程序借助 IDirect3D8 接口的各種方法來進行簡單的反復。調用 GetAdapterCount 來確定系統中顯示適配器的數目。調用 GetAdapterMonitor 來確定適配器所連接的物理監視器(該方法返回一個 HMONITOR,您然后就可以在 Win32 API GetMonitorInfo 中使用該值,以確定關于物理監視器的信息)。確定某一具體顯示適配器的特征,或在該適配器上創建一個 Direct3D 設備,簡單到在調用 GetDeviceCaps、CreateDevice 或其它方法時,通過替代 D3DADAPTER_DEFAULT 來傳遞相應的適配器編號。
幾何(頂點)處理
D3DVERTEX 等等頂點類型有何變動?
不再顯式支持“預罐裝”的頂點類型。多重頂點流系統允許對頂點數據進行更加靈活的裝配。如果您想使用其中一個“傳統”的頂點格式,則您可以建立一套相應的 FVF 代碼。
我對頂點流不大清楚,其工作原理如何?
Direct3D 對從一個或多個頂點流饋入流水線的每個頂點進行組裝。只有一個頂點流時,就對應于 DirectX 8 以前的老模型,即頂點來自單獨一個源。借助 DirectX 8,不同的頂點組件可以來自不同的源;例如,一個頂點緩沖區可能含有位置和法線,而另一個則含有顏色值和紋理坐標。
頂點著色器是什么?
頂點著色器是一個用于處理單一頂點的過程。這是借助一種類似于匯編的簡單語言來進行定義的,由 D3DX 實用程序匯編為一個 Direct3D 接受的令牌流。頂點著色器接受單獨一個頂點和一組常量值的輸入,并輸出一個頂點位置(在剪貼空間),還可能輸出一組用于光柵化的顏色和紋理坐標。請注意,在您有一個定制的頂點著色器時,頂點組件就不再有任何由 Direct3D 施加給它們的語義,而頂點就只是由您所創建的頂點著色器進行解釋的任意數據。
頂點著色器進行透視劃分或剪裁嗎?
不。頂點著色器在已變換的頂點位置的剪貼空間輸出一個純系坐標。透視分割和剪裁是由后著色器自動進行的。
我能借助頂點著色器生成幾何圖形嗎?
頂點著色器無法創建或消滅頂點;其一次只對單一頂點進行操作,即作為輸入接收一個未經處理的頂點,而輸出單獨一個經過處理的頂點。因此可以將其用于操作已有的幾何圖形(應用變形或進行外觀變換操作),但實際上無法生成新的幾何圖形。
我能將一個定制的頂點著色器應用到固定功能幾何流水線(或者進行相反的操作〕嗎?
不能。您必須選擇其一。如果您正在使用一個定制的頂點著色器,則您負責進行整個頂點變換操作。
如果我的硬件并不支持定制的頂點著色器,我可以使用嗎?
可以。Direct3D 軟件頂點處理引擎完全支持定制的頂點著色器,且性能指標出奇的高。
我如何確定硬件是否支持我的定制的頂點著色器?
能夠硬件支持頂點著色器的設備被要求填充 D3DCAPS8::VertexShaderVersion 字段,以指示其所支持的頂點著色器的版本級別。所有聲稱支持某一級別的頂點著色器的設備,必須支持所有合法的頂點著色器,這些頂點著色器符合針對該級別或較低級別的規范。
有多少個常量寄存器可以用于頂點著色器?
要求支持 DX8 頂點著色器的設備至少支持 96 個常量寄存器。設備的支持能力可能會超過這一最低數目,且可以通過 D3DCAPS8::MaxVertexShaderConst 字段進行報告。
我可以在帶有不同紋理坐標的頂點之間共享位置數據嗎?
該情形的一個通常示例就是一個立方體,其中您想為每個面使用一個不同的紋理。很不幸,答案是不行;目前還還不能獨立索引每個頂點組件。即使是多頂點流,也是所有的頂點一起索引。
在我提交一列帶索引的原語時,Direct3D 是處理緩沖區中所有的頂點,還是只處理我索引過的頂點?
在使用軟件幾何流水線時,Direct3D 首先轉換您所提交的范圍中的所有的頂點,而不是“根據要求”按照索引對其進行轉換。這對于密集數據(即其中使用了大多數的頂點)效率更高,尤其是在可以使用 SIMD 指令時。如果您的數據比較松散(即很多頂點未被使用),則您可能需要考慮重新排列您的數據,以避免多余的轉換。在使用硬件幾何加速時,頂點經常是根據需要進行轉換的。
索引緩沖區是什么?
索引緩沖區與頂點緩沖區極其類似,但其包含的是用于 DrawIndexedPrimitive 調用的索引。強烈建議您盡可能使用索引緩沖區,而不要使用原始的由應用程序分配的內存,其道理與頂點緩沖區相同。
我注意到 32 位的索引現在是一種支持類型;我可以將其用在所有的設備上嗎?
不可以。你必須檢查 D3DCAPS8::MaxVertexIndex 字段,以確定設備所支持的最大索引值。該值必須大于 216-1 (0xffff) 才能支持 D3DFMT_INDEX32 類型的索引緩沖區。另外請注意,某些設備可能支持 32 位的索引,但其所支持的最大索引值卻小于 232-1 (0xffffffff);這樣,應用程序必須遵從設備所報告的限制。
將多重頂點流用于固定功能流水線有何限制?
固定功能流水線要求每條頂點流水線是一個嚴格的 FVF 子集,即根據一個完整的 FVF 聲明預定的。 另外請注意,您必須遵從 D3DCAPS8::MaxStreams 字段所報告的流水線數目的限制(現在的許多設備和/或驅動程序僅支持單一流水線)。
性能調諧
我如何能夠改善我的 Direct3D 應用程序的性能?
在優化性能時,需要考察下列幾個關鍵問題:
- 批處理大小:Direct3D 已為大批量原語進行過優化。一次調用所能發送的多邊形越多,其效果也就越好。憑經驗而論,建議平均每次調用 100 個以上的多邊形。低于該水平,您可能不會得到最好的性能,而高于該水平,您收到的效果會遞減,且可能會與并行事項發生沖突(參見下面的論述)。
- 狀態更改:更改描繪狀態這種操作可能會很昂貴,尤其是在更改紋理時。因此,每幀所作的狀態更改應盡可能地少,這一點很重要。另外,請盡量降低對頂點或索引緩沖區的更改。
注意:在 DirectX 8 中更改緩沖區已不在象在以前版本中那樣昂貴了,但依舊建議盡量避免更改頂點緩沖區。
- 并行:如果能夠安排描繪與其它處理同時進行,則您可以充分利用系統性能。這一目標可能會與降低描繪狀態更改的目標相抵觸。您需要在進行批處理以降低狀態更改和較早將數據推出到驅動程序以達到并行目的之間找到一個平衡點。以循環方式使用多個頂點緩沖區,會有助于并行功能。
- 紋理上載:將紋理上載到設備會消耗帶寬并導致與頂點數據爭用帶寬。 因此,不要占用過多的內存這一點很重要,因為這會強制緩存方案為每一幀上載過多的紋理。
- 頂點緩沖區和索引緩沖區: 您應當一直使用頂點緩沖區和索引緩沖區,而不是由應用程序分配的普通內存塊。頂點緩沖區和索引緩沖區的鎖定語義至少可以避免多于的復制操作。對于某些驅動程序,頂點緩沖區和索引緩沖區可能是更理想的存儲器中的某些區域(可能是在視頻或 AGP 存儲器中),供硬件進行訪問。
- 狀態宏鎖定:這些是在 DX 7.0 中推出的,為將一系列的狀態更改(包括照明、材質和矩陣更改)記錄成一個宏提供了一個機制,該宏然后就可以通過單一的調用來重放了。這有兩個優勢:
- 您進行一次調用而不是多次調用,從而降低調用開銷。
- 有感悟能力的驅動程序可以對狀態更改進行預分析和預編譯,從而使到圖形硬件的提交速度快得多。
- 僅使用單獨一個 Direct3D 設備:如果您需要描繪到多個目標,則請使用 SetRenderTarget。如果您是要創建一個帶有多個 3D 窗口的窗口化程序,則請使用 CreateAdditionalSwapChain API。運行時已為單一設備進行過優化,使用多個設備時會有相當多的速度折扣。
狀態更改可能依舊很昂貴,但使用狀態宏至少會有助于降低部分成本。
我應當使用哪些基本類型(條形、扇形、列表等)?
在真實數據中遇到的許多網格,都具有多個多邊形共享頂點的特性。為將性能最大化,最好將所轉換的頂點中的重復率降低,并橫跨總線將其發給描繪設備。使用簡單的三角列表根本實現不了任何頂點共享,因而這是最不理想的方法。這一點已很清楚。然后所要作的選擇就是使用條形和扇形(暗示多邊形之間的具體連接關系),還是使用索引列表。在數據自然歸入各種條形和扇形的情況下,這些就是最為合適的選擇,因為發給驅動程序的數據被降至最低。但是,將網格分解條形和扇形經常會造成大量分離塊,暗示有大量的 DrawPrimitive 調用。因此,最富效率的方法通常是使用帶三角列表的單獨一個 DrawIndexedPrimitive 調用。使用索引列表的另一個優勢就是,這在連續三角形僅共享單獨一個頂點時也有益處。總而言之,如果您的數據自然歸入各種較大的條形和扇形,就使用條形和扇形,否則就使用索引列表。
如果我要生成動態數據,怎樣才算是較好地使用頂點緩沖區了呢?
Direct3DX 實用程序庫
D3DX 圖象文件加載器函數支持哪些文件格式?
D3DX 圖象文件加載器函數支持 BMP、TGA、PNG、JPG、DIB、PPM 和 DDS 文件。
D3DX 中的文字描繪函數好象失效,我的操作有什么問題嗎?
使用 ID3DXFont::DrawText 功能時的一個常見錯誤就是為顏色參數指定一個零 alpha 組件,從而導致完全透明(即不可見)的文本。對于完全不透明的文本,請確保色彩參數的 alpha 成分完全飽和 (255)。
對于字體描繪,我應當使用 ID3DXFont 還是 SDK 框架 CD3DFont 類?
ID3DXFont 類能夠處理字間距,因為它使用 GDI 來繪制字符串。這可能會有點慢,因為每次均需要調用 GDI。
CD3DFont 設計用于加速和使用紋理化基本類型來繪制字符。它只能處理簡單字體,并不支持 ID3DXFont 可用的全套格式選項,但適用于簡單而快速的顯示,諸如幀速率計數等等。
對于產品代碼,您可能需要實施您自己的字形描繪功能,即借助紋理化基本類型和/或基于 GDI 的方案(帶避免重新繪制的緩存功能)。
DirectSound
我的應用程序啟動時,為何為發出一陣凈噪聲?我注意到其它應用程序也有這個問題。
您可能安裝了調試用 DirectX 運行時。運行時的調試版本用靜噪聲填充緩沖區,以便幫助開發人員捕捉未經初始化緩沖區的缺陷。您無法保證 DirectSound 緩沖區在創建后的內容;尤其是您無法將緩沖區清零。
DirectPlay
我如何確保我的游戲將能夠與各種 Network Address Translator (網絡地址轉換器,NAT) 和 Internet Connection Sharing (Internet 連接共享,ICS)設置正常工作?
NAT 和 ICS 是較為復雜的主題,在 MSDN 上的另一篇文章中有更詳盡的論述。但是,下列提示可以作為很好的一般性指導:
- 通過 IDirectPlay8Client 和 IDirectPlay8Server 接口,使用一種客戶端-服務器而不是點對點網絡拓撲。
- 將服務器放在清澈的 Internet 上,而不是在一個 NAT 后面。
- 直接枚舉游戲端口,而不是使用 DPNSVR。
- 不要在您的消息中內嵌 IP 地址或端口號。
有關點對點游戲、將服務器駐于 NAT 后面的事宜,以及針對各種不同的 Windows 操作系統上的 ICS 的具體建議,請參考更詳盡的文檔。
DPNSVR 是作什么用的?
DPNSVR 是一種用于枚舉請求的轉發服務,消除了多個 DirectPlay 應用程序在端口使用上的沖突所導致的各種問題。使用 DPNSVR 使得 DirectPlay 能夠自動選擇要使用的端口,同時又允許客戶端對您的游戲進行枚舉。默認為,DirectPlay 會使用 DPNSVR,因為這通常為應用程序提供了最大的靈活性;但是,您可以將其禁用,方法是在創建您的會話時指定 DPNSESSION_NODPNSVR 旗標。如果客戶端使用 DPNSVR 端口來枚舉主機,而主機又使用自己的端口來作出響應的話,使用 DPNSVR 可能會導致客戶端一側的 NAT 發生問題;NAT 可能會拒絕將數據包轉遞給客戶端,因為數據包不是來自請求被發往的同一端口。
IDirectPlay8LobbyClient::Initialize 為何返回 DPNERR_NOTALLOWED?
DirectPlay 不允許每個進程有一個以上的前端客戶端或應用程序,因而試圖創建多個客戶端會導致返回這一錯誤。
總結
以上是生活随笔為你收集整理的Microsoft DirectX 8 开发人员常见问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 东北大学软件项目管理与过程改进复习提纲(
- 下一篇: 上网痕迹查询助手Viewurl 2017