DirectX Frequently Asked Questions
Microsoft Corporation
August 2005
Introduction
This is a collection of Frequently Asked Questions (FAQ) about Microsoft DirectX.
Contents:
- General DirectX Development Issues
- Direct3D Questions
- DirectSound Questions
- DirectX Extensions for Alias Maya
- XInput Questions
内容:
一般 DX开发事项
D3D问题
DirectSound问题
DX Maya扩展问题
XInput问题
General DirectX Development Issues
一般 DX开发事项
Should game developers still be publishing games for Windows 95, Windows 98 or Windows ME?
游戏开发者仍然只能在 Win95 , Win98 或 Win ME 上(用 DX9 )制作游戏吗?
Not anymore for two reasons: performance and feature set.
对,有两个原因:性能和特性集合。
If the minimum CPU speed required for your game is 1.2GHz or above (which is more common for high performance titles), then the vast majority of these machines will be running Windows XP. By the time machines with CPU speeds above 1.2GHz were being sold, Windows XP was installed as the default operating system by almost all manufacturers. This means that there are many features found in Windows XP that today's game developers should be taking advantage of including:
如果你的游戏对最小 CPU速度要求是 1.2GHz或者更高(这对高性能游戏来说很普遍)那么这些机器中的大部分会在 Windows XP上运行。到现在( 2005.4)为止,当一台 CPU速度高于 1.2GHz的机器在售出时,厂商基本上会把 Windows XP作为默认操作系统(吹牛??)。这意味着 Windows XP的许多特性会被现在的游戏开发者采用,包括(吹吧……):
- Improved multitasking - which results in a better, smoother experience for video, audio and gaming.
- 改进的多任务-提供对视频,音频和游戏更好的更平稳的体验
- More stable video driver model - which allows easier debugging, smoother game play and better performance.
- 更稳定的视频驱动模型-调试更容易,游戏运行更平稳,性能更好
- Easier configuration for networking - which allows easier access to multi-player games.
- 对网络的描述更简单-对多人游戏的操作更简单
- Support for DMA transfers by default from hard drives - which results in smoother, faster loading applications.
- 默认对硬件驱动支持 DMA传送-平稳,快速的载入程序
- Windows error reporting - which results in a more stable OS, drivers and applications.
- Windows错误报告-更稳定的操作系统,驱动和程序
- Unicode support - which greatly simplifies localization issues.
- 支持 Unicode-简化多语种支持
- Better security and stability - which results in better consumer experiences.
- 更好的安全性和稳定性-更好的客户体验
- Better support for modern hardware - most of which no longer uses Windows 98 drivers.
- 对当前硬件更好的支持-大多数比 Windows98驱动用的更久
- Improved memory management - which results in better stability and security.
- 改进内存管理-提供更高的稳定性和安全性
- Improved NTFS file system - which is more resistant to failure, and has better performance with security features.
- 改进 NTFS文件系统-提供更好的容错性,保证安全的同时提供更高的性能
Should game developers still be publishing games for Windows 2000?
游戏开发者仍然需要在 Windows 2000 上编程吗?
Not anymore. In addition to the reasons listed in Should game developers still be publishing games for Windows 95, Windows 98 or Windows ME? , Windows 2000 does not have these features:
不需要。作为对上个问题的补充, Windows 2000不支持这些特性:
- Windows XP supports advanced processor features such as Hyper-Threading, Multi-Core and x64.
- XP支持高级处理器特性比如超线程,多内核和 64位程序
- Windows XP supports side-by-side components which significantly reduces application versioning conflicts.
- XP支持并行组件技术,能够有效减少程序版本冲突
- Windows XP supports no-execute memory protection which helps prevent malicious programs and can aid debugging.
- XP支持未执行程序保护,这能够阻止恶意程序访问和辅助调试
- Windows XP has improved support for advanced AGP and PCI Express based video cards.
- XP改进了对使用高级 AGP和 PCIE显卡的支持
- Windows XP supports fast user switching, remote desktop and remote assistance which can help lower product support costs.
- XP支持快速用户切换,远程桌面和远程帮助,这能够帮助降低产品支持消耗
- Performance tools like Reference (in the DirectX Developer SDK) no longer support Windows 2000.
- 2000不再支持类似于 PIX, PIXWIN之类的性能工具
In short, Windows 2000 was never designed or marketed as a consumer operating system.
简而言之, Windows 2000不再作为个人用户操作系统而设计和销售。
I think I have found a driver bug, what do I do?
我想我找到了一个驱动 Bug,应该怎么办?
First, ensure you have checked the results with the Reference Rasterizer. Then check the results with the latest WHQL certified version of the IHVs driver. You can programmatically check the WHQL status using the GetAdapterIdentifier() method on the IDirect3D9 interface passing the D3DENUM_WHQL_LEVEL flag. With a WHQL certified driver issue, send a description of the bug, the output from dxdiag and a repro case to [email protected] with a note in the subject line "WHQL Driver Bug".
首先,使用参考光栅化程序检查你的结果,然后检查最后一次由 WHQL( Windows Hardware Quality Labs,视窗硬件质量实验室 )认证的 IHVs( Independent Hardware Vendors,独立硬件开发商)驱动运行结果。你可以在程序中使用 DX9的 GetAdapterIdentifier()函数并传入 D3DENUM_WHQL_LEVEL 标记检查 WHQL状态。发送 WHQL认证的驱动, bug的描述、 dx窗口的输出和重现 bug的例子到 [email protected],题目标为 "WHQL Driver Bug"。
Why do I get so many error messages when I try to compile the samples?
为什么我在编译 sample 的时候有这么多的错误信息?
You probably don't have your include path set correctly. Many compilers, including Microsoft Visual C++, include an earlier version of the SDK, so if your include path searches the standard compiler include directories first, you'll get incorrect versions of the header files. To remedy this issue, make sure the include path and library paths are set to search the Microsoft DirectX include and library paths first. See also the dxreadme.txt file in the SDK. If you install the DirectX SDK and you are using Visual C++, the installer can optionally set up the include paths for you.
你可能没有正确设定你的 include路径。许多编译器,包括 MS VC++在内,设定了早期版本的 SDK路径,所以如果你的 include路径在标准编译器从前设定的路径下搜寻,你会得到版本不正确的头文件。为了解决这个问题,必须首先保证 include路径和 lib路径设置到当前的 DX SDK include 目录和 lib目录。你可以参考 SDK中的 dxreadme.txt文件。如果你安装了 DX SDK并在使用 VC++,安装程序会可选择的为你设定 include路径。
I get linker errors about multiple or missing symbols for globally unique identifiers (GUIDs), what do I do?
我(在编译过程中)产生一个找不到全局一致标记符( GUIDs )定义的错误,应该怎么办?
The various GUIDs you use should be defined once and only once. The definition for the GUID will be inserted if you #define the INITGUID symbol before including the DirectX header files. Therefore, you should make sure that this only occurs for one compilation unit. An alternative to this method is to link with the dxguid.lib library, which contains definitions for all of the DirectX GUIDs. If you use this method (which is recommended), then you should never #define the INITGUID symbol.
你使用的大量的 GUIDs必须并且只能定义一次。如果你在 include DX头文件之前使用 #define定义了宏 INITGUID,对 GUID的定义会被插入到你的程序中。但是你必须保证在一次编译中这个定义只出现一次。另一个办法是在程序中链接 dxguid.lib 库文件,这个文件包含所有的 DX GUIDs的定义。如果你使用这个(我们推荐的)方法,你就不需要使用 #define INITGUID了。
Can I cast a pointer to a DirectX interface to a lower version number?
我能够使用低版本号的 DX 接口指针吗?
No. DirectX interfaces are COM interfaces. This means that there is no requirement for higher numbered interfaces to be derived from corresponding lower numbered ones. Therefore, the only safe way to obtain a different interface to a DirectX object is to use the QueryInterface method of the interface. This method is part of the standard IUnknown interface, from which all COM interfaces must derive.
不行。 DX接口是 COM接口,这意味着高版本的接口不是从低版本接口上派生得到。使用不同版本接口唯一安全的办法是使用该接口 QueryInterface函数。这个函数是标准 IUnknown接口的一部分,所有的 COM接口都从 IUnknown派生。
Can I mix the use of DirectX 9 components and DirectX 8 or earlier components within the same application?
我能够在相同的程序中混合使用 DX9 组件和 DX8 (或者更早版本的)组件吗?
You can freely mix different components of differing version; for example, you could use DirectInput 8 with Direct3D 9 in the same application. However, you generally cannot mix different versions of the same component within the same application; for example, you cannot mix DirectDraw 7 with Direct3D 9 (since these are effectively the same component as DirectDraw has been subsumed into Direct3D as of DirectX 8). There are exceptions, however, such as the use of Direct3D 9 and Direct3D 10 together in the same application, which is allowed.
你能够自由混合使用不同版本的 DX组件。举个例子说,你能够在同一个程序中使用 DirectInput8和 D3D9。当然,你不能在同一程序中使用不同版本的相同组件。比如你不能混合使用 DirectDraw7和 Direct3D9(因为 DirectDraw从 DirectX8起成为 Direct3D的一部分)。当然也有例外,比如在程序中允许同时使用 Direct3D9和 Direct3D10。
Can I mix the use of Direct3D 9 and Direct3D 10 within the same application?
我能够在同一程序中混合使用 Direct3D9 和 Direct3D10 吗?
Yes, you may use these versions of Direct3D together in the same application.
是的,猪头,我刚才说过了。
What do the return values from the Release or AddRef methods mean?
Release 函数和 AddRef 函数的返回值是什么意思?
The return value will be the current reference count of the object. However, the COM specification states that you should not rely on this and the value is generally only available for debugging purposes. The values you observe may be unexpected since various other system objects may be holding references to the DirectX objects you create. For this reason, you should not write code that repeatedly calls Release until the reference count is zero, as the object may then be freed even though another component may still be referencing it.
返回值是当前对象的 reference数量。当然, COM组件定义中说你不需要用到它,这个值通常用作调试。你看到的值可能不是你所期望的,因为大量的其他系统对象会保存你创建的 DirectX对象的 reference。因为如此,你不能在程序中重复调用 Release()知道它的返回值为 0,否则这个对象会被真正释放,而同时还有其他组件保存有它的 reference(要使用它)。
Does it matter in which order I release DirectX interfaces?
我释放 DirectX 接口的顺序重要吗?
It shouldn't matter because COM interfaces are reference counted. However, there are some known bugs with the release order of interfaces in some versions of DirectX. For safety, you are advised to release interfaces in reverse creation order when possible.
没关系,因为 COM接口有 reference的计数。当然,在一些版本的 DirectX中有一些和释放顺序相关的已知的 Bug,为了安全,你最好尽可能的使用和创建接口相反的顺序来释放。
What is a smart pointer and should I use it?
什么是 smart pointer (智能指针),我必须用它吗?
A smart pointer is a C++ template class designed to encapsulate pointer functionality. In particular, there are standard smart pointer classes designed to encapsulate COM interface pointers. These pointers automatically perform QueryInterface instead of a cast and they handle AddRef and Release for you. Whether you should use them is largely a matter of taste. If your code contains lots of copying of interface pointers, with multiple AddRefs and Releases, then smart pointers can probably make your code neater and less error prone. Otherwise, you can do without them. Visual C++ includes a standard Microsoft COM smart pointer, defined in the "comdef.h" header file (look up com_ptr_t in the help).
智能指针是一个 C++模板类,设计为封装指针的功能。通常情况下,我们有专门封装 COM接口指针的的标准智能指针类。这些指针自动执行 QueryInterface函数,不需要做类型转换。它们也会为为你执行 AddRef和 Release函数。你是否使用只能只能完全看你个人喜好。如果你的代码里包含大量的接口指针拷贝,同时还有多种 AddRef和 Release操作,使用智能指针能够使你的代码更简洁和减少出错。当然你也可以不用它们。 VC++包含一个标准 MS COM只能指针类,在文件 ”comdef.h”中定义(在 help中查找 com_ptr_t)
I have trouble debugging my DirectX application, any tips?
我在调试 DirectX 程序时有问题,有什么建议吗?
The most common problem with debugging DirectX applications is attempting to debug while a DirectDraw surface is locked. This situation can cause a "Win16 Lock" on Microsoft Windows 9x systems, which prevents the debugger window from painting. Specifying the D3DLOCK_NOSYSLOCK flag when locking the surface can usually eliminate this. Windows 2000 does not suffer from this problem. When developing an application, it is useful to be running with the debugging version of the DirectX runtime (selected when you install the SDK), which performs some parameter validation and outputs useful messages to the debugger output.
调试 DX程序时最常见的问题就是在 DirectDraw surface被锁定的时候尝试调试。这种情况会导致 MS Win 9x系统产生一个“ Win16 Lock”的错误,阻止调试器窗口绘制。当锁定 surface时定义 D3DLOCK_NOSYSLOCK宏通常可以消除这个错误。 Win 2000没有这个问题。开发程序时,在 dubug模式下运行 DirectX runtime(在你安装 SDK时选择)会很有效,因为它会做一些参数有效性检查和输出有用信息到调试器输出窗口。
What's the correct way to check return codes?
检查代码返回值的正确方法是什么?
Use the SUCCEEDED and FAILED macros. DirectX methods can return multiple success and failure codes, so a simple:
== D3D_OK
or similar test will not always suffice.
使用 SUCCEEDED和 FAILED宏检查。 DX函数会返回多个不同的成功和错误值,所以一个简单的 == D3D_OK或者类似的检查通常是不够的。
How do I disable ALT+TAB and other task switching?
我怎么阻止 ALT+TAB 切换程序和其他任务切换?
You don't!
你丫民工,俺都不希说你!
Is there a recommended book explaining COM?
有解释 COM 接口的推荐阅读材料吗?
Inside COM by Dale Rogerson, published by Microsoft Press, is an excellent introduction to COM. For a more detailed look at COM, the book Essential COM by Don Box, published by Longman, is also highly recommended.
《深入 COM编程》,作者 Dale Rogerson,微软出版社出版。此书是对 COM接口最好的一本入门书。想要对 COM有深入了解,我们强烈推荐《 Essential COM》,作者 Don Box, Longman出版社出版。(国内有影印版)
What is managed code?
什么是 Managed code (可控制代码)?
Managed code is code that has its execution managed by the .NET Framework Common Language Runtime (CLR). It refers to a contract of cooperation between natively executing code and the runtime. This contract specifies that at any point of execution, the runtime may stop an executing CPU and retrieve information specific to the current CPU instruction address. Information that must be query-able generally pertains to runtime state, such as register or stack memory contents.
Managed code是在 .NET框架通用语言运行时( CLR)程序管理下执行的代码。它指的是原始的执行代码和运行时程序协同工作时之间的协定。该协定定义在程序运行的任何地方,运行时能够停止 CPU工作并获得当前 CPU的指令地址。能够被查询的信息通常是那些运行时状态,比如寄存器状态或者堆栈内容。
Before the code is run, the IL is compiled into native executable code. And, since this compilation happens by the managed execution environment (or, more correctly, by a runtime-aware compiler that knows how to target the managed execution environment), the managed execution environment can make guarantees about what the code is going to do. It can insert traps and appropriate garbage collection hooks, exception handling, type safety, array bounds and index checking, and so forth. For example, such a compiler makes sure to lay out stack frames and everything just right so that the garbage collector can run in the background on a separate thread, constantly walking the active call stack, finding all the roots, chasing down all the live objects. In addition because the IL has a notion of type safety the execution engine will maintain the guarantee of type safety eliminating a whole class of programming mistakes that often lead to security holes.
在代码运行前, IL被编译到可执行的代码中。因为编译在可控制执行环境下(或者,更正确的说法是,在清楚运 行时各种信息并知道如何应对可控制执行环境的编译器)进行,可控制执行环境能够知道代码将会做什么。它能够插入陷阱、合适的垃圾搜集钩子程序(??),异 常处理,类型安全性,数据边界和索引检查之类的跟踪程序。这种编译器保证设置栈帧和其他一切正常,所以垃圾搜集器可以在另一个线程上在后台运行,连续访问 激活的堆栈,找到堆栈根部,跟踪到任意一个激活的对象。因为 IL会做类型安全性工作,执行引擎会得到类型安全的保证,所以会剔除许多经常导致安全漏洞的编程错误。
In contrast this to the unmanaged world: Unmanaged executable files are basically a binary image, x86 code, loaded into memory. The program counter gets put there and that's the last the OS knows. There are protections in place around memory management and port I/O and so forth, but the system doesn't actually know what the application is doing. Therefore, it can't make any guarantees about what happens when the application runs.
与此相反的是不可控制的世界:不可控制的执行文件基本上是一个 2进制镜像, x86代码,载入内存中。程序计数器从里面读取指令,最后只有操作系统知道怎么执行。操作系统会保护内存管理和 I/O端口,但是系统不知道应用程序实际做什么,并且它不保证在应用程序运行时会发生什么。
What books are there about general Windows programming?
一般 Windows 编程看什么参考书?
Lots. However, the two that are highly recommended are:
好多。推荐这两本:
- Programming Windows by Charles Petzold (Microsoft Press)
- Programming Applications for Windows by Jeffrey Richter (Microsoft Press)
How do I debug using the Windows symbol files?
用了 Windows 符号文件之后怎么调试?
Microsoft publish stripped symbols for all system DLLs (plus a few others). To access them add the following to your symbol path in the project settings inside Visual Studio:
MS对所有的系统 DLL列出了符号定义。为了得到这些定义,需要把下面路径加到 Visual Studio中项目设置的符号路径中:
srv*http://msdl.microsoft.com/download/symbols
for caching symbols locally use the following syntax:
从本地缓存符号使用下列语法:
srv*c:\cache*http://msdl.microsoft.com/download/symbols
Where c:\cache is a local directory for caching symbol files.
c:\cache代表 cache文件的本地路径。
Direct3D Questions
D3D 问题
- General Direct3D Questions
- Geometry (Vertex) Processing
- Performance Tuning
- D3DX Utility Library
General Direct3D Questions
一般 D3D 问题
Where can I find information about 3D graphics techniques?
我怎么样才能找到 3D 图形技术的信息?
The standard book on the subject is Computer Graphics: Principles and Practice by Foley, Van Dam et al. It is a valuable resource for anyone wanting to understand the mathematical foundations of geometry, rasterization and lighting techniques. The FAQ for the comp.graphics.algorithms Usenet group also contains useful material.
这个方面的标准参考书是:《计算机图形学:原理与实践》作者 Foley, Van Dam等。对于希望理解图形学几何,光栅化和光照技术的数学基础的人来说,这是本有价值的书。 comp.graphics.algorithms Usenet组的 FAQ也有很多有用的信息。
Does Direct3D emulate functionality not provided by hardware?
硬件不提供 D3D 的模拟功能?
It depends. Direct3D has a fully featured software vertex-processing pipeline (including support for custom vertex shaders). However, no emulation is provided for pixel level operations; applications must check the appropriate caps bits and use the ValidateDevice API to determine support.
D3D模拟功能依赖于硬件。 D3D有着完整的软件顶点处理流水线(包括处理用户的 VS)。当然,像素操作没有提供模拟功能;应用程序必须使用 ValidateDevice检查合适的 Caps位,判断是不是支持像素操作。
Is there a software rasterizer included with Direct3D?
D3D 中做软件光栅化吗?
Not for performance applications. A reference rasterizer is supplied for driver validation but the implementation is designed for accuracy and not performance. Direct3D does support plug-in software rasterizers.
对性能要求高的程序不做软件光栅化。 D3D提供参考光栅化作为驱动的参照,但它的设计是为了精确性而不是为了性能。 D3D支持软件光栅化插件。
How can I perform color keying with DirectX graphics?
在 DX 中怎么做颜色索引?
Color keying is not directly supported, instead you will have to use alpha blending to emulate color keying. The D3DXCreateTextureFromFileEx() function can be used to facilitate this. This function accepts a key color parameter and will replace all pixels from the source image containing the specified color with transparent black pixels in the created texture.
颜色索引并没有直接被支持,但是你可以使用 alpha混合来模拟颜色索引。 D3DXCreateTextureFromFileEx()函数也可以协助实现这个功能。这个函数接受一个颜色索引参数并在创建的纹理中把 所有源图像中和颜色索引相同的像素替换程黑色。
Does the Direct3D geometry code utilize 3DNow! and/or Pentium III SIMD instructions?
D3D 几何代码使用了 3DNow !或者奔三 SIMD 指令吗?
Yes. The Direct3D geometry pipeline has several different code paths, depending on the processor type, and it will utilize the special floating-point operations provided by the 3DNow! or Pentium III SIMD instructions where these are available. This includes processing of custom vertex shaders.
是的。 D3D几何流水线有依赖于处理器类型的几个不同的代码路径,如果可以的话,它会使用 3D Now!或者奔三提供的特殊的 SIMD浮点处理指令,包括执行用户的 VS在内。
How do I prevent transparent pixels being written to the z-buffer?
我怎么样阻止透明像素写到 z 缓存中?
You can filter out pixels with an alpha value above or below a given threshold. You control this behavior by using the renderstates ALPHATESTENABLE, ALPHAREF and ALPHAFUNC.
你可以通过设置一个超过阀值的 Alpha值滤除像素,这需要设置绘制状态 ALPHATESTENABLE, ALPHAREF和 ALPHAFUNC来控制。
What is a stencil buffer?
什么是模板缓存?
A stencil buffer is an additional buffer of per-pixel information, much like a z-buffer. In fact, it resides in some of the bits of a z-buffer. Common stencil/z-buffer formats are 15-bit z and 1-bit stencil, or 24-bit z and 8-bit stencil. It is possible to perform simple arithmetic operations on the contents of the stencil buffer on a per-pixel basis as polygons are rendered. For example, the stencil buffer can be incremented or decremented, or the pixel can be rejected if the stencil value fails a simple comparison test. This is useful for effects that involve marking out a region of the frame buffer and then performing rendering only the marked (or unmarked) region. Good examples are volumetric effects like shadow volumes.
模板缓存是一个保存逐像素信息的附加缓存,和 Z缓存非常类似。实际上,它使用 Z缓存的一些比特位来实现。普通的 S/Z缓存格式是 15位 Z值和 1位 S值,或者 24位 Z值和 8位 S值。在绘制多边形时可以对模板缓存中的数组做逐像素的简单算术操作。比如说模板缓存可以递增或者递减,或者在模板测试失败的时候剔除像素。 这样操作可以标记屏幕上一块区域然后值绘制标记好的区域。使用模板缓存最好的例子是 Shadow Volumes算法。
How do I use a stencil buffer to render shadow volumes?
我怎么样使用模板缓存来绘制 Shadow Volume ?
The key to this and other volumetric stencil buffer effects, is the interaction between the stencil buffer and the z-buffer. A scene with a shadow volume is rendered in three stages. First, the scene without the shadow is rendered as usual, using the z-buffer. Next, the shadow is marked out in the stencil buffer as follows. The front faces of the shadow volume are drawn using invisible polygons, with z-testing enabled but z-writes disabled and the stencil buffer incremented at every pixel passing the z-test. The back faces of the shadow volume are rendered similarly, but decrementing the stencil value instead.
这个问题和其他体素模板缓存效果的关键是如何让模板缓存和 Z缓存做交互。使用 Shadow Volume绘制场景分三步。首先,打开 Z缓存使用无阴影方式绘制一次。接下来使用这样的手段标记阴影:绘制不可见的 Shadow Volume的正面,打开 Z测试关闭 Z写入,模板缓存在每个像素通过 z测试时加 1。 Shadow Volume的背面使用同样方法绘制,只是在通过 z测试时减 1。
Now, consider a single pixel. Assuming the camera is not in the shadow volume there are four possibilities for the corresponding point in the scene. If the ray from the camera to the point does not intersect the shadow volume, then no shadow polygons will have been drawn there and the stencil buffer is still zero. Otherwise, if the point lies in front of the shadow volume the shadow polygons will be z-buffered out and the stencil again remains unchanged. If the points lies behind the shadow volume then the same number of front shadow faces as back faces will have been rendered and the stencil will be zero, having been incremented as many times as decremented.
现在考虑单个像素。假设相机不在 Shadow Volume中,对于场景中的点有四种可能。如果相机发出的光线没有和 Shadow Volume相交,那么没有多边形被画到这个像素上,模板缓存值位 0。如果点在 Shadow Volume之前,那么在绘制 Shadow Volume时它不会通过 z测试,因此模板缓存保持为 0。如果点在 Shadow Volume之后,那么模板缓存递增的次数和递减的次数相同,因此模板缓存值还是 0。
The final possibility is that the point lies inside the shadow volume. In this case the back face of the shadow volume will be z-buffered out, but not the front face, so the stencil buffer will be a non-zero value. The result is portions of the frame buffer lying in shadow have non-zero stencil value. Finally, to actually render the shadow, the whole scene is washed over with an alpha-blended polygon set to only affect pixels with non-zero stencil value. An example of this technique can been seen in the "Shadow Volume" sample that comes with the DirectX SDK.
最后一种可能是在 Shadow Volume中的像素点。在这种情况下背面 Shadow Volume不通过 z测试而正面通过,所以模板缓存是一个非 0的值。这样的结果就是模板缓存不为 0的像素处于阴影中。最后,实际绘制阴影,整个场景用 Alpha混合只对阴影中的区域绘制多边形。这种技术的一个例子参见 DX SDK中的 Shadow Volume sample程序。
What are the texel alignment rules? How do I get a one-to-one mapping?
什么是纹理对齐规则?我们怎么得到 1 比 1 采样?
This is explained fully in the Direct3D 9 documentation. However, the executive summary is that you should bias your screen coordinates by -0.5 of a pixel in order to align properly with texels. Most cards now conform properly to the texel alignment rules, however there are some older cards or drivers that do not. To handle these cases, the best advice is to contact the hardware vendor in question and request updated drivers or their suggested workaround. Note that in Direct3D 10, this rule no longer holds.
这在 D3D9的文档中已经完全解释过了。在执行的细节上,你需要注意把你的屏幕坐标向左偏移 0.5以完成像素的对齐。大部分显卡现在都支持纹元对齐规则,但是一些老的卡没有支持。对于这种情况,你最好和硬件制造商联系,要求更新驱动 或者按照他们的建议设置工作环境。注意在 D3D10中,这种规则已经不存在了。
What is the purpose of the D3DCREATE_PUREDEVICE flag?
D3DCREATE_PUREDEVICE 标记的作用是什么?
Use the D3DCREATE_PUREDEVICE flag during device creation to create a pure device. A pure device does not save the current state (during state changes), which often improves performance; this device also requires hardware vertex processing. A pure device is typically used when development and debugging are completed, and you want to achieve the best performance.
在创建设备过程中使用 D3DCREATE_PUREDEVICE标记来创建纯设备。纯设备并(在状态切换时)不保存当前状态,这样能提高性能。这种设备同时也需求 硬件顶点处理。纯设备在调试和开发结束后使用,用作或者最好性能。
One drawback of a pure device is that it does not support all Get* API calls; this means you can not use a pure device to query the pipeline state. This makes it more difficult to debug while running an application. Below is a list of all the methods that are disabled by a pure device.
纯设备的缺点是它不支持 Get*API() 调用,这意味着你不能够使用纯设备来查询设备状态。在运行调试程序时,这会比一般设备更困难。下面是在使用纯设备是不能 调用的函数:
- ID3D10Device9::GetClipPlane
- ID3D10Device9::GetClipStatus
- ID3D10Device9::GetLight
- ID3D10Device9::GetLightEnable
- ID3D10Device9::GetMaterial
- ID3D10Device9::GetPixelShaderConstantF
- ID3D10Device9::GetPixelShaderConstantI
- ID3D10Device9::GetPixelShaderConstantB
- ID3D10Device9::GetRenderState
- ID3D10Device9::GetSamplerState
- ID3D10Device9::GetTextureStageState
- ID3D10Device9::GetTransform
- ID3D10Device9::GetVertexShaderConstantF
- ID3D10Device9::GetVertexShaderConstantI
- ID3D10Device9::GetVertexShaderConstantB
A second drawback of a pure device is that it does not filter any redundant state changes. When using a pure device, your application should reduce the number of state changes in the render loop to a minimum; this may include filtering state changes to make sure that states do not get set more than once. This trade-off is application dependent; if you use more than a 1000 Set calls per frame, you should consider taking advantage of the redundancy filtering that is done automatically by a non-pure device.
纯设备的第二个缺点是它不会滤除任何冗余状态变化。当使用纯设备时,应用程序应该把状态改变减到最少,包括滤除那些对相同状态设置超过 两次的操作。是否手动设置是依赖于应用程序的,如果你每帧使用超过 1000次状态设置,你应该考虑滤除冗余状态设置,虽然这种操作会在使用非纯设备时会被自动执行。
As with all performance issues, the only way to know whether or not your application will perform better with a pure device is to compare your application's performance with a pure vs. non-pure device. A pure device has the potential to speed up an application by reducing the CPU overhead of the API. But be careful! For some scenarios, a pure device will slow down your application (due to the additional CPU work caused by redundant state changes). If you are not sure which type of device will work best for your application, and you do not filter redundant changes in the application, use a non-pure device.
和所有的性能问题一样,唯一知道你的程序在纯设备和非纯设备下哪个性能更好的方法就是比较它们在两种设备下的运行速度。纯设备具备提高 程序性能的潜力,因为它减少了程序 CPU开支。但是要特别注意对于某些场景纯设备会减慢你程序的运行速度(因为由于冗余状态改变增加了附加 CPU操作)。如果你不知道哪种类型设备效率最高,同时你也不想做应用程序状态的冗余状态改变,你应该使用非纯设备。
How do I enumerate the display devices in a multi-monitor system?
我如何在多显示器系统中列出各个显示设备?
Enumeration can be performed through a simple iteration by the application using methods of the IDirect3D9 interface. Call GetAdapterCount to determine the number of display adapters in the system. Call GetAdapterMonitor to determine which physical monitor an adapter is connected to (this method returns an HMONITOR, which you can then use in the Win32 API GetMonitorInfo to determine information about the physical monitor). Determining the characteristics of a particular display adapter or creating a Direct3D device on that adapter is as simple as passing the appropriate adapter number in place of D3DADAPTER_DEFAULT when calling GetDeviceCaps, CreateDevice, or other methods.
可以通过使用 IDirect3D9接口的函数做一个简单的遍历就能够完成这个操作。调用 GetAdapterCount来确定系统的显卡数目,使用 GetAdapterMonitor来确定哪个显示器和哪块显卡连接(这个函数返回一个 HMONITOR值,然后你可以使用 Win32 API GetMonitorInfo来得到显示器的信息)。确定某个显卡特性或者创建 D3D设备的过程都很简单,只要用合适的显卡编号替换 GetDeviceCaps, CreateDevice或者其他函数中的 D3DADAPTER_DEFAULT参数。
What happened to Fixed Function Bumpmapping in D3D9?
D3D9 中固定管线的 Bumpmapping 做了什么?
As of Direct3D 9 we tightened the validation on cards that could only support > 2 simultaneous textures. Certain older cards only have 3 texture stages available when you use a specific alpha modulate operation. The most common usage that people use the 3 stages for is emboss bumpmapping, and you can still do this with D3D9,
在 D3D9中我们严格定义了一块显卡必须能够支持同时采样 2张以上纹理。一般老的卡当你打开 Alpha乘操作时最多只有 3个纹理阶段。最普通的使用 3个纹理阶段的操作就是凹凸贴图,在 D3D9中你仍然能够这样做。
The height field has to be stored in the alpha channel and is used to modulate the lights contribution i.e.:
高度场被保存在 Alpha通道中,被用作和光照效果叠加,如下:
// Stage 0 is the base texture, with the height map in the alpha channel
m_pd3dDevice->SetTexture(0, m_pEmbossTexture );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0 );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,
D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,
D3DTOP_SELECTARG1 );
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
if( m_bShowEmbossMethod )
{
// Stage 1 passes through the RGB channels (SELECTARG2 = CURRENT), and
// does a signed add with the inverted alpha channel.
// The texture coords associated with Stage 1 are the shifted ones, so
// the result is:
//
(height - shifted_height) * tex.RGB * diffuse.RGB
m_pd3dDevice->SetTexture( 1, m_pEmbossTexture );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_ADDSIGNED );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE|D3DTA_COMPLEMENT );
m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
// Set up the alpha blender to multiply the alpha channel
// (monochrome emboss) with the src color (lighted texture)
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
}
This sample, along with other older samples, are no longer shipped in the current SDK release, and will not be shipped in future SDK releases.
这个 sample和其他更老的一些 sample一样不会出现在当前的 SDK中,也不会在将来发布的 SDK中出现。
Geometry (Vertex) Processing
几何(顶点)处理问题
Vertex streams confuse me how do they work?
顶点流数据让我觉得有些糊涂,它们是怎么工作的?
Direct3D assembles each vertex that is fed into the processing portion of the pipeline from one or more vertex streams. Having only one vertex stream corresponds to the old pre-DirectX 8 model, in which vertices come from a single source. With DirectX 8, different vertex components can come from different sources; for example, one vertex buffer could hold positions and normals, while a second held color values and texture coordinates.
D3D把管线中同时操作的多个数据流中的不同数据集中到一起放在同一个数据流中。只使用一个数据流和老的 DX8之前的模型相对应,这样顶点就只源自同一个数据流。举个例子,一个顶点缓存可能保存位置和法向而另一个保存颜色和纹理坐标。
What is a vertex shader?
什么是顶点渲染器?
A vertex shader is a procedure for processing a single vertex. It is defined using a simple assembly-like language that is assembled by the D3DX utility library into a token stream that Direct3D accepts. The vertex shader takes as input a single vertex and a set of constant values; it outputs a vertex position (in clip-space) and optionally a set of colors and texture coordinates, which are used in rasterization. Notice that when you have a custom vertex shader, the vertex components no longer have any semantics applied to them by Direct3D and vertices are simply arbitrary data that is interpreted by the vertex shader you create.
顶点渲染器( VS)是处理单个顶点的过程。它使用类汇编的语言定义,可以被 D3DX使用库编译为 D3D接受的符号流数据。 VS把单个顶点和一系列常数作为输入,输出顶点位置(在裁减空间中的)和可选的一系列颜色和纹理坐标,在光栅化时被使用。注意当你使用自己定 义的 VS时,顶点数据就不再具备 D3D定义的语法属性,只是作为你创建的 VS的单纯数据来解析。
Does a vertex shader perform perspective division or clipping?
VS 做透视除法和裁减吗?
No. The vertex shader outputs a homogenous coordinate in clip-space for the transformed vertex position. Perspective division and clipping is performed automatically post-shader.
不。 VS输出裁减空间中变换后齐次坐标。透视除法和裁减在 VS之后被自动执行。(嘿嘿,现在未必这样了 ^_^)
Can I generate geometry with a vertex shader?
我能用 VS 创建几何吗?
A vertex shader cannot create or destroy vertices; it operates on a single vertex at a time, taking one unprocessed vertex as input and outputting a single processed vertex. It can therefore be used to manipulate existing geometry (applying deformations, or performing skinning operations) but cannot actually generate new geometry per se.
VS不能够创建或者删除顶点。它每次只是对单个顶点做操作,输入一个没输入的顶点,输出一个处理过的顶点。它能用作操作已有顶点(做变 形或者表面细节操作)但是实际上不能够实际创建几何。
Can I apply a custom vertex shader to the results of the fixed-function geometry pipeline (or vice-versa)?
我能够对固定管线的几何操作结果使用自己定义的 VS 吗(或者相反)?
No. You have to choose one or the other. If you are using a custom vertex shader, then you are responsible for performing the entire vertex transformation.
不。你只能选择做固定管线或者 VS。如果使用 VS,你就必须做完整的顶点变换操作。
Can I use a custom vertex shader if my hardware does not support it?
如果我硬件不支持 VS ,我能使用 VS 吗?
Yes. The Direct3D software vertex-processing engine fully supports custom vertex shaders with a surprisingly high level of performance.
是的, D3D软件顶点处理引擎完全支持用户 VS,性能之高让人惊奇。
How do I determine if the hardware supports my custom vertex shader?
我怎么知道硬件是否支持我的 VS ?
Devices capable of supporting vertex shaders in hardware are required to fill out the D3DCAPS9::VertexShaderVersion field to indicate the version level of vertex shader they support. Any device claiming to support a particular level of vertex shader must support all legal vertex shaders that meet the specification for that level or below.
硬件被要求填充 D3D设备特性中的 D3DCAPS9::VertexShaderVersion域表明它支持的 VS版本等级。任何声称支持某个等级的 VS的设备必须支持所有官方的 VS,满足包括这个等级在内之前的所有特性。
How many constant registers are available for vertex shaders?
VS 能够支持多少个常数寄存器?
Devices supporting vs 1.0 vertex shaders are required to support a minimum of 96 constant registers. Devices may support more than this minimum number and can report this through the D3DCAPS9::MaxVertexShaderConst field.
支持 VS1.0的设备要求支持最小 96个常数寄存器。设备能够支持更多的常数寄存器,并通过设置 D3DCAPS9::MaxVertexShaderConst域让用户知道。
Can I share position data between vertices with different texture coordinates?
我能够对于有不同纹理坐标的顶点共享相同的位置数据吗?
The usual example of this situation is a cube in which you want to use a different texture for each face. Unfortunately the answer is no, it's not currently possible to index the vertex components independently. Even with multiple vertex streams, all streams are indexed together.
这种情况最普通的一个例子就是绘制每个面有不同纹理的立方体。不幸的是,这个问题的答案是不行。现在对顶点数据独立进行索引还是不可能 的。即使对于多数据流,所有数据流都使用相同的索引。
When I submit an indexed list of primitives, does Direct3D process all of the vertices in the buffer, or just the ones I indexed?
当我提交了图元的索引列表后, D3D 会处理缓存中所有顶点吗,还是只处理我的索引列表里的?
When using the software geometry pipeline, Direct3D first transforms all of the vertices in the range you submitted, rather than transforming them "on demand" as they are indexed. For densely packed data (that is, where most of the vertices are used) this is more efficient, particularly when SIMD instructions are available. If your data is sparsely packed (that is, many vertices are not used) then you may want to consider rearranging your data to avoid too many redundant transformations. When using the hardware geometry acceleration, vertices are typically transformed on demand as they are required.
当你使用软件几何处理流水线时, D3D首先处理你提交的所有顶点,而不是按照它们在索引列表里的顺序操作。对于密集打包的数据(就是大部分顶点被使用的缓存)这会更高效,部 分因为 SIMD指令在处理它们。如果你的数据被分散打包(许多数据没有被使用),你可以考虑重新安排数据以避免太多的冗余变换。当使用够硬件几何加 速时,硬件只会处理你要求变换的数据。
What is an index buffer?
什么是索引缓存?
An index buffer is exactly analogous to a vertex buffer, but instead it contains indices for use in DrawIndexedPrimitive calls. It is highly recommended that you use index buffers rather than raw application-allocated memory when possible, for the same reasons as vertex buffers.
索引缓存和顶点缓存类似,但是它保存的是 DrawIndexedPrimitive调用需要的索引数据。我们强烈推荐你尽可能使用使用索引缓存而不是直接程序分配内存,同样也推荐使 用顶点缓存。
I notice that 32-bit indices are a supported type; can I use them on all devices?
我注意到 32位索引是 D3D支持的类型,我能够用吗?
No. You must check the D3DCAPS9::MaxVertexIndex field to determine the maximum index value that is supported by the device. This value must be greater than 2 to the 16th power -1 (0xffff) in order for index buffers of type D3DFMT_INDEX32 to be supported. In addition, note that some devices may support 32-bit indices but support a maximum index value less than 2 to the 32nd power -1 (0xffffffff); in this case the application must respect the limit reported by the device.
不,你必须首先检查 D3DCAPS9::MaxVertexIndex域确定设备支持的最大的索引值。这个值必须大于 2^16- 1才能真正支持 D3DFMT_INDEX32。同时还要注意有些设备支持 32位索引但是它的最大索引不是 2^32 - 1。在这种情况下程序必须遵循设备的限制。
Does S/W vertex processing support 64 bit?
软件顶点处理支持 64位操作吗?
There is an optimized s/w vertex pipeline for x64, but it does not exist for IA64.
对于 x64有优化过的软件顶点流水线,但是不支持 IA64。
X64 就是基于 x86 架构的 64 位 CPU AMD 64 位 CPU 就是用这种的全称应该是 X86-64
IA64 是 intel 面向高端的新架构 IPF 的 64 位 CPU 这种 CPU 是不能兼容原先的 X86 下使用的程序,也就是说现在的 windows 程序都无法在这种 CPU 下面运行。
Performance Tuning
性能问题
How can I improve the performance of my Direct3D application?
我怎么样才能提高 D3D 程序的性能?
The following are key areas to look at when optimizing performance:
下面是提高性能的一些要点:
Batch size
批处理数据量
Direct3D is optimized for large batches of primitives. The more polygons that can be sent in a single call, the better. A good rule of thumb is to aim to average 1000 vertices per primitive call. Below that level you're probably not getting optimal performance, above that and you're into diminishing returns and potential conflicts with concurrency considerations (see below).
D3D对大量图元数据处理有优化。一次函数调用处理的多边形越多,效率越高。一个比较好的规则就是平均每次函数调用处理 1000个图元。在这个数量之下你很难优化性能,在此之上你则会减少返回次数以及与其他优化考虑(看下文)的潜在冲突。
State changes
状态改变
Changing render state can be an expensive operation, particularly when changing texture. For this reason, it is important to minimize as much as possible the number of state changes made per frame. Also, try to minimize changes of vertex or index buffer.
改变绘制状态会成为代价昂贵的操作,特别是在改变纹理时。因为如此,所以要尽可能的减少每帧的状态改变操作。同样也要尽量减少顶点缓存 或者索引缓存的切换。
Note As of DirectX 8, the cost of changing vertex buffer is no longer as expensive as it was with previous versions, but it is still good practice to avoid vertex buffer changes where possible.
注意:和 DX8一样,改变顶点缓存不再和从前版本一样耗时,但是减少顶点缓存切换仍然是良好的操作。
Concurrency
并行操作
If you can arrange to perform rendering concurrently with other processing, then you will be taking full advantage of system performance. This goal can conflict with the goal of reducing renderstate changes. You need to strike a balance between batching to reduce state changes and pushing data out to the driver early to help achieve concurrency. Using multiple vertex buffers in round-robin fashion can help with concurrency.
如果你能够把绘制操作和其他操作并行执行,你的性能能得到显著提高。这个目标可能和减少绘制状态改变相重度。你需要平衡批处理数据量以 减少绘制状态改变,并且在早期就把数据发送到驱动中以获得并行性。使用多顶点缓存轮流操作能够促进并行性。
Texture uploads
纹理上传
Uploading textures to the device consumes bandwidth and causes a bandwidth competition with vertex data. Therefore, it is important to not to over commit texture memory, which would force your caching scheme to upload excessive quantities of textures each frame.
上传纹理到设备上会消耗带宽并引起和顶点数据的带宽冲突。同时还要注意纹理不要超过纹理内存大小,否则你的高速缓存机制会被强迫每帧上 传大量的纹理数据。
Vertex and index buffers
顶点缓存和索引缓存
You should always use vertex and index buffers, rather than plain blocks of application allocated memory. At a minimum, the locking semantics for vertex and index buffers can avoid a redundant copy operation. With some drivers, the vertex or index buffer may be placed in more optimal memory (perhaps in video or AGP memory) for access by the hardware.
你应该尽量使用顶点和索引缓存而不是完全由程序分配内存,因为至少顶点(索引)缓存的锁定机制能够避免冗余的拷贝操作。在一些驱动中, 顶点(索引)缓存会被放到更优化的内存中(可能是在显存或者 AGP内存中)被硬件读取。
State macro blocks
状态宏模块
These were introduced in DirectX 7.0. They provide a mechanism for recording a series of state changes (including lighting, material and matrix changes) into a macro, which can then be replayed by a single call. This has two advantages:
这是在 DX7中引入的概念。它提供了一个机制记录一系列状态改动(包括光照,材质和矩阵改变)到宏中,并且能用一个函数调用重现。它由两个优点:
- You reduce the call overhead by making one call instead of many.
- 减少了函数调用次数
- An aware driver can pre-parse and pre-compile the state changes, making it much faster to submit to the graphics hardware.
- 驱动能够预解析和编译状态改动,使之对硬件效率更高
State changes can still be expensive, but using state macros can help reduce at least some of the cost. Use only a single Direct3D device. If you need to render to multiple targets, use SetRenderTarget. If you are creating a windowed application with multiple 3D windows, use the CreateAdditionalSwapChain API. The runtime is optimized for a single device and there is a considerable speed penalty for using multiple devices.
状态改动仍然是耗时的,但是使用状态宏能够帮助你降低一些代价。尽量使用一个 D3D设备,如果你需要绘制到多个对象上就使用 SetRenderTarget函数来切换对象。如果你要创建一个拥有多个 3D窗口的 Windows窗口程序,使用 CreateAdditionalSwapChain函数即可完成。对单个设备运行时间会有优化,而使用多个设备还会降低单个运行速度。
Which primitive types (strips, fans, lists and so on) should I use?
我应改使用哪种类型图元?
Many meshes encountered in real data feature vertices that are shared by multiple polygons. To maximize performance it is desirable to reduce the duplication in vertices transformed and sent across the bus to the rendering device. It is clear that using simple triangle lists achieves no vertex sharing, making it the least optimal method. The choice is then between using strips and fans, which imply a specific connectivity relationship between polygons and using indexed lists. Where the data naturally falls into strips and fans, these are the most appropriate choice, since they minimize the data sent to the driver. However, decomposing meshes into strips and fans often results in a large number of separate pieces, implying a large number of DrawPrimitive calls. For this reason, the most efficient method is usually to use a single DrawIndexedPrimitive call with a triangle list. An additional advantage of using an indexed list is that a benefit can be gained even when consecutive triangles only share a single vertex. In summary, if your data naturally falls into large strips or fans, use strips or fans; otherwise use indexed lists.
许多 mesh会相交在一些被多个多边形共享的顶点上。为了得到最优性能,应该尽量减少对相同顶点重复的变换 和发送到设备的数据总线上。对于没有共享顶点的数据可以使用简单的三角形链表,它是优化最少的方法。选择在三角形条带和三角形扇面和使用索引链表之间的展 开,条带和扇面分别默认定义了多边形之间特殊的连接关系。如果数据自然形成条带或者扇面,它们分别就是最合适的选择,因为这就是送往显卡的最小数据。当 然,把 mesh分解为条带或者扇形通常会导致大量的小碎片,这意味中大量的 DrawPrimitive调用。因为如此,最有效的方法通常是使用 DrawIndexedPrimitive函数调用索引链表。使用索引链表的另一个好处是当连续的三角形共享一个顶点时能够被优化。总之,除 非你的数据天生就是三角形条带或者扇形,否则还是使用索引链表比较合适。
How do you determine the total texture memory a card has, excluding AGP memory?
怎么确定一块显卡总的纹理显存是多少,不包括 AGP 显存?
IDirect3DDevice9::GetAvailableTextureMem() returns the total available memory, including AGP. Allocating resources based on an assumption of how much video memory you have is not a great idea. For example, what if the card is running under a Unified Memory Architecture (UMA) or is able to compress the textures? There might be more space available than you might have thought. You should create resources and check for 'out of memory' errors, then scale back on the textures. For example, you could remove the top mip-levels of your textures.
IDirect3DDevice9::GetAvailableTextureMem()返回包括 AGP显存在内总的显存数量。基于有多少显存来分配资源并不是一个好主意。举个例子说,如果你的卡使用统一内存架构( UMA)或者能够压缩纹理,它的显存是多少?它会比你想像的多的多。你应该创建资源并判断它有没有返回“超出内存”错误,然后减少纹理大小, 比如移除最高层的 Mipmap。
What's a good usage pattern for vertex buffers if I'm generating dynamic data?
创建动态数据时,应该按怎么样的模式操作?
- Create a vertex buffer using the D3DUSAGE_DYNAMIC and D3DUSAGE_WRITEONLY usage flags and the D3DPOOL_DEFAULT pool flag. (Also specify D3DUSAGE_SOFTWAREPROCESSING if you are using software vertex processing.)
使用 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY和 D3DPOOL_DEFAULT创建顶点缓存 (如果使用软件顶点缓存的话使用 D3DUSAGE_SOFTWAREPROCESSING)
- I = 0.
- Set state (textures, renderstates and so on).
检查状态(纹理状态,绘制状态等等)
- Check if there is space in the buffer, that is, for example, I + M <= N? (Where M is the number of new vertices).
检查缓存中是否有多余空间,比如 I+M<=N?(M代表新顶点数据 )
- If yes, then Lock the VB with D3DLOCK_NOOVERWRITE. This tells Direct3D and the driver that you will be adding vertices and won't be modifying the ones that you previously batched. Therefore, if a DMA operation was in progress, it isn't interrupted. If no, goto 11.
如果有,使用 D3DLOCK_NOOVERWRITE锁定顶点缓存。这告诉 D3D和设备你要添加新的顶点到缓存中,但是不改变原有顶点数据。并且如果使用 DMA操作的话,它不会被打断。如果没有,跳转到 11
- Fill in the M vertices at I.
在 I处填充 M个顶点
- Unlock.
解除锁定
- Call Draw[Indexed]Primitive. For non-indexed primitives use I as the StartVertex parameter. For indexed primitives, ensure the indices point to the correct portion of the vertex buffer (it may be easiest to use the BaseVertexIndex parameter of the SetIndices call to achieve this).
调用 Draw[Indexed]Primitive。对于没有索引的图元,使用 I作为开始顶点参数。对于索引数据,保证索引指向 VB中正确的位置(最简单的,使用 BaseVertexIndex作为 SetIndeces调用的参数)。
- I += M.
- Goto 3.
- Ok, so we are out of space, so let us start with a new VB. We don't want to use the same one because there might be a DMA operation in progress. We communicate to this to Direct3D and the driver by locking the same VB with the D3DLOCK_DISCARD flag. What this means is "you can give me a new pointer because I am done with the old one and don't really care about the old contents any more."
如果超出范围,就创建一个新的 VB。我们不想用相同的数据因为当前可能有一个 DMA操作。我们使用 D3DLOCK_DISCARD标记通知 D3D和设备锁定相同的 VB。这告诉它们“你们能够给我一个新的指针因为我已经用过了旧的数据并不再需要它们了。”
- I = 0.
- Goto 4 (or 6).
Why do I have to specify more information in the D3DVERTEXELEMENT9 structure?
我为什么在 D3DVERTEXELEMENT9 结构中要定义更多的信息?
As of Direct3D 9, the vertex stream declaration is no longer just a DWORD array, it is now an array of D3DVERTEXELEMENT9 structures. The runtime makes use of the additional semantic and usage information to bind the contents of vertex streams to vertex shaders input registers/variables. For Direct3D 9, vertex declarations are decoupled from vertex shaders, which makes it easier to use shaders with geometries of different formats as the runtime only binds the data that the shader needs.
在 D3D9中,顶点数据流申明不再是一组 DWORD数组,它现在是一个 D3DVERTEXELEMENT9数据结构。运行时程序使用附加的语法和用法信息把顶点数据流内容绑定到 VS的数据寄存器和变量上。对于 D3D9,顶点申明和 VS的申明是对应的,不同格式的几何能够仅仅绑定 VS需要的数据到 shader上,使 shader的使用更简单。
The new vertex declarations can be used with either the fixed function pipeline or with shaders. For the fixed function pipeline, there is no need to call SetVertexShader. If however, you want to switch to the fixed function pipeline and have previously used a vertex shader, call SetVertexShader(NULL). When this is done, you will still need to call SetFVF to declare the FVF code.
新的顶点申明既能被固定管线使用也能被 shader使用。对于固定管线就不必调用 SetVertexShader。如果你需要在固定管线和 VS之前切换,可以调用 SetVertexShader( NULL)。如果这样做的话,你仍然需要调用 SetFVF来申明 FVF格式。
When using vertex shaders, call SetVertexShader with the vertex shader object. Additionally, call SetFVF to set up a vertex declaration. This uses the information implicit in the FVF. SetVertexDeclaration can be called in place of SetFVF because it supports vertex declarations that cannot be expressed with an FVF.
当使用 VS时,调用 SetVertexShader设置 VS对象。调用 SetFVF使用 FVF定义的信息设置顶点申明。 SetVertexDeclaration能够替代 SetFVF,因为它能够支持 FVF所不能表达的顶点申明。
D3DX Utility Library
D3DX 实用库问题
What file formats are supported by the D3DX image file loader functions?
D3DX 图像文件导入函数支持那些格式图像?
The D3DX image file loader functions support BMP, TGA, JPG, DIB, PPM and DDS files.
支持 BMP, TGA, JPG, DIB, PPM和 DDS文件。
The text rendering functions in D3DX don't seem to work, what am I doing wrong?
D3DX 的文本绘制函数似乎不工作,是我做错了吗?
A common mistake when using the ID3DXFont::DrawText functions is to specify a zero alpha component for the color parameter; resulting in completely transparent (that is, invisible) text. For fully opaque text, ensure that the alpha component of the color parameter is fully saturated (255).
使用 ID3DXFont::DrawText函数常犯的错误就是给颜色参数定义了一个 alpha通道为 0的颜色值,导致文本完全透明(也就是不可见)。对于不透明文本,保证颜色参数 alpha通道为最大值( 255)。
How can I save the contents of a surface or texture to a file?
我怎么样才能保存一个 surface 或者纹理到文件中?
The DirectX 8.1 SDK added two functions to the D3DX library specifically for this purpose: D3DXSaveSurfaceToFile() and D3DXSaveTextureToFile(). These functions support saving an image to file in either BMP or DDS format. In previous versions you will have to lock the surface and read the image data, then write it to a bitmap file. An article on writing a function to store bitmaps can be found at Windows GDI: Storing an Image.
DX8.1SDK为 D3DX库增加两个库函数来完整这个操作: D3DXSaveSurfaceToFile()和 D3DXSaveTextureToFile()。这两个函数支持保存图像到 BMP或者 DDS格式中。在过去的版本中,你不得不锁定 surface然后读取图像数据,然后写入 bmp文件中。编写保存 bmp文件的文章可以在 GDI: Storing an Image一节中找到。
Alternatively, GDI+ could be used to save the image in a wide variety of formats, though this requires additional support files to be distributed with your application.
同样的, GDI+能够用做保存图像到大量的格式中,虽然这需要你的程序支持文件分发。
How can I make use of the High Level Shader Language (HLSL) in my game?
在我的游戏中怎么使用 HLSL ?
There are three ways that the High Level Shading Language can be incorporated into your game engine:
有三种方法支持 HLSL在游戏中插入:
- Compile your shader source into vertex or pixel shading assembly (using the command line utility fxc.exe) and use D3DXAssembleShader() at run time. This way even a DirectX 8 game can even take advantage of the power of the HLSL.
- 编译 Shader源代码成 VS或者 PS汇编(使用 fxc.exe)并在运行时调用 D3DXAssembleShader()。这种方法可以使 DX8以上的游戏都能使用 HLSL
- Use D3DXCompileShader() to compile your shader source into token stream and constant table form. At run time load the token stream and constant table and call CreateVertexShader() or CreatePixelShader() on the device to create your shaders.
- 使用 D3DXCompileShader()编译 Shader为符号流和常数表,在运行时符号流和常数表被 CreateVertexShader()或者 CreatePixelShader()导入到设备中。
- The easiest way to get up and running is to take advantage of the D3DX Effects system by calling D3DXCreateEffectFromFile() or D3DXCreateEffectFromResource() with your effect file.
- 最简单的方法是使用 D3DX Effect系统,调用 D3DXCreateEffectFromFile()或者 D3DXCreateEffectFromResource()打开效果文件。
What is the correct way to get shaders from an Effect?
从 Effect 中得到 shader 的正确方法是什么?
Use D3DXCreateEffect to create an ID3DXEffect and then use GetPassDesc to retrieve a D3DXPASS_DESC. This structure contains pointers to vertex and pixel shaders.
使用 D3DXCreateEffect创建 ID3DXEffect对象然后使用 GetPassDesc获得 D3DXPASS_DESC结构,这个结构包含 VS和 PS指针
Do not use ID3DXEffectCompiler::GetPassDesc. Vertex and pixel shader handles returned from this method are NULL.
不要使用 ID3DXEffectCompiler::GetPassDesc,这个函数返回的 VS和 PS指针为 NULL
What is the HLSL noise() intrinsic for?
HLSL 的 noise() 函数是做什么的?
The noise intrinsic function generates perlin noise as defined by Ken Perlin. The HLSL function can currently only be used to fill textures in texture shaders as current h/w does not support the method natively. Texture shaders are used in conjuction with the D3DXFill*Texture() functions which are useful helper functions to generate procedurally defined textures during load time.
噪音内置函数产生 perlin噪音。这个 HLSL函数目前只能在纹理 shader中用作填充纹理,因为当前的硬件还没有直接支持这个函数。纹理 shader在 D3DXFill*Texture()中使用。这个函数在载入时创建过程纹理非常有用。
How do I detect whether to use pixel shader model 2.0 or 2.a?
我怎么确定是否使用 PS2.0还是 PS2.a
You can use the D3DXGetPixelShaderProfile() and D3DXGetPixelShaderProfile() functions which return a string determining what HLSL profile is best suited to the device being ran.
你能够使用 D3DXGetPixelShaderProfile()和 D3DXGetPixelShaderProfile()函数,它们会返回一个字符串,确定哪个 HLSL profile是最适合在设备上运行的。
How do I access the Parameters in my Precompiled Effects Shaders?
在我预编译好的 Effect Shader 中怎么操作参数值?
Through the ID3DXConstantTable interface which is used to access the constant table. This table contains the variables that are used by high-level language shaders and effects.
通过 ID3DXConstantTable操作常数表。这个表保存了 HLSL shader和 effect的变量内容。
Is there a way to add user data to an effect or other resource?
有办法添加用户数据到 effect 或者其他数据上吗?
Yes, to set private data you call SetPrivateData (pReal is the D3D texture object, pSpoof is the wrapped texture object).
是的,你可以通过调用 SetPrivateData设置个人数据( pReal是 D3D纹理对象, pSpoof是包含用户数据的纹理对象)
hr = pReal->SetPrivateData(IID_Spoof, &pSpoof,
sizeof(IDirect3DResource9*), 0)));
To look up the wrapped pointer:
查找用户数据纹理对象指针:
IDirect3DResource9* pSpoof;
DWORD dwSize = sizeof(pSpoof);
hr = pReal->GetPrivateData(IID_Spoof, (void*) &pSpoof, &dwSize);
Why does rendering of an ID3DXMesh object slow down significantly after I define subsets?
在我定义了 mesh 子集之后,为什么绘制 ID3DXMesh 对象会明显慢下来呢?
You probably have not optimized the mesh after defining the face attributes. If you specify attributes and then call ID3DXMesh::DrawSubset(), this method must perform a search of the mesh for all faces containing the requested attributes. In addition, the rendered faces are likely in a random access pattern, thus not utilizing vertex cache. After defining the face attributes for your subsets, call the ID3DXMesh::Optimize or ID3DXMesh::OptimizeInPlace methods and specifying an optimization method of D3DXMESHOPT_ATTRSORT or stronger. Note that for optimum performance you should optimize with the D3DXMESHOPT_VERTEXCACHE flag, which will also reorder vertices for optimum vertex cache utilization. The adjacency array generated for a D3DX Mesh has three entries per face, but some faces may not have adjacent faces on all three edges. How is this encoded? Entries where there are no adjacent faces are encoded as 0xffffffff.
你可能在定义了面属性之后没有优化 mesh。如果你定义了属性后就调用 ID3DXMesh::DrawSubset(),这个函数就会搜索 mesh的所有表面找到拥有所需的属性的表面。同时,这些表面也是随机被绘制,很难利用 vertex cache加速。在定义了表面子集属性后,调用 ID3DXMesh::Optimize或 ID3DXMesh::OptimizeInPlace并使用 D3DXMESHOPT_ATTRSORT或者更好的排序准则来优化。注意要得到最优性能的话,你必须 D3DXMESHOPT_VERTEXCACHE优化,这样可以充分利用 vertex cache。一个 D3DX mesh的邻接数据对每个表面有三个顶点,但是一些表面可能在所有三条边上都没有邻接顶点。这种情况下怎么编码呢?那么对于没有邻 接顶点的表面邻接值设置为 0xffffffff。
I've heard a lot about Pre-computed Radiance Transfer (PRT), where can I learn more?
俺听说 PRT很牛叉,咋整的呐?
PRT is a new feature of D3DX added in the Summer 2003 SDK Update. It enables rendering of complex lighting scenarios such as global -llumination, soft shadowing and sub-surface scatter in real time. The SDK contains documentation and samples of how to integrate the technology into your game. The PRT Demo Sample and LocalDeformablePRT Sample samples demonstrate how to use the simulator for per vertex and per pixel lighting scenarios respectively. Further information about this and other topics can also be found at Peter Pike Sloan's Web page.
PRT是 MS的镇派绝学,闲杂人等一概回避,要学先投个简历先。
How can I render to a texture and make use of Anti Aliasing?
我怎么样才能绘制到一张纹理上,并且用上反走样?
Create a multisampled render target using Direct3DDevice9::CreateRenderTarget. After rendering the scene to that render target, StretchRect from it to a render target texture. If you make any changed to the offscreen textre (such as blurring or blooming it), copy it back to the back buffer before you present().
使用 Direct3DDevice9::CreateRenderTarget创建多采样 RenderTarget。在把场景绘制到这个 RenderTarget后,用 StretchRet把它拷到一个 Rendertarget纹理上。如果你对屏幕外的纹理作合任何操作(比如模糊或者扩散),在你调用 persent() 显示之前把它拷回到 back buffer上。