坐标系与基本图元(7)
场景提交概述
场景提交即将在后台缓冲区绘制好的场景提交到前台缓冲区,从而在屏幕上显示出来。提交接口函数是一组控制特定的渲染设备状态的方法,这些设备影响显示器的显示。
(1)前台缓冲区:这是一块由显卡转换来的矩形存储区,这块矩形存储区的内容显示在显示器或其他输出设备上。
(2)后台缓冲区:后台缓冲区是一个表面,其内容可以提交到前台缓冲区。
(3)交换链:一组后台缓冲区集合,它们被顺序地提交到前台缓冲区。一般情况下,一个全屏交换链通过翻转设备驱动接口(DDI)来提交随后的显示内容,窗口交换链通过位块传送DDI提交显示内容。
前台缓冲区不能直接在Direct3D API中使用。所以,应用程序不能对前台缓冲区进行锁定或渲染。DirectX 9.0应用程序中没有主表面的概念,不能创建一个带有主表面的对象。
窗口模式下的多视口(视区)
Direct3D设备对象拥有并控制自己的交换链,此外,应用程序可以使用函数IDirect3DDevice9::CreateAdditionalSwapChain()创建附加交换链,用来在同一个设备中提交多个视口。一般地说,应用程序为每个视口创建一个交换链,每个交换链对应一个特定的视口。应用程序在每个视口的后台缓冲区内渲染图形,然后用函数 IDirect3DDevice9::Present()将它们分别提交。注意:对于任何Direct3D设备对象,一次只能有一个交换链用于全屏显示。
多显示器操作
当一个设备被成功设置为全屏操作时,创建该设备的Direct3D对象被标识为拥有系统的所有显卡。这种状态称为独占模式(exclusive mode),也就是说,Direct3D对象为独占模式。独占模式是指,这时其他所有的Direct3D对象创建的设备都不能进行全屏操作,也不能申请资源空间。此外,当一个对象是独占模式时,所有未在全屏模式下的设备都将被设为丢失状态。当Direct3D对象的最后一个全屏设备被设置为窗口模式或被销毁时,独占模式被取消。
当一个Direct3D设备是独占模式时,设备将被分为两大类,第一类设备有下列属性:
(1)它们都是由同一个创建全屏设备的Direct3D对象创建的。
(2)因为设备是全屏的,它们具有同一个焦点窗口。
(3)它们代表不同于任何全屏设备的显卡。
对于这种类型的设备,不用关心它们能否被重新设置或创建,因为它们不处于丢失状态。甚至,这种类型的设备都可以被设置为全屏状态。
不属于第一类的设备即由其他Direct3D对象创建的设备,或和当前全屏设备不具有相同的焦点窗口,或和当前全屏设备使用不同的显卡。这一类Direct3D设备不能被重新设置,将一直处于丢失状态,直至当前全屏设备的独占模式取消。这样一来,一个多显示器应用程序可在全屏模式下拥有多个设备,但是,这些设备必须由相同的Direct3D对象创建,对应于不同的物理显卡并且共享同一个焦点窗口。
操作深度缓冲区
深度缓冲区与设备相关。当应用程序设置渲染目标时,需要访问深度缓冲区。可以使用函数IDirect3DDevice9::GetDepthStencilSurface()和IDirect3DDevice9::SetDepthStencilSurface()来操作深度缓冲区。
访问前台缓冲区
可以通过函数IDirect3DDevice9::GetFrontBufferData()访问前台缓冲区,这是得到一个反锯齿场景屏幕快照的唯一方法。
图形反锯齿(antialiasing)
图形像素在颜色缓冲区或屏幕中以一个二维坐标(x, y)表示当前位置。如果实际计算的像素值是浮点数,则将被转换为整数坐标显示,这种光栅化的处理方法可能使图形出现锯齿形外观。图形学中称这种由于采样频率不足而造成的失真为锯齿(alisasing),Direct3D采用图形反锯齿(通过多重采样)来改善图形的锯齿效果,增加图形边缘的平滑度。
查询设备是否支持多重采样
使用IDirect3D::CheckDeviceMultiSampleType()函数检查当前设备是否支持图形多重采样:
Determines if a multisampling technique is available on this device.
HRESULT CheckDeviceMultiSampleType( UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels);
Parameters
- Adapter
- [in] Ordinal number denoting the display adapter to query. D3DADAPTER_DEFAULT is always the primary display adapter. This method returns FALSE when this value equals or exceeds the number of display adapters in the system. See Remarks.
- DeviceType
- [in] Member of the D3DDEVTYPE enumerated type, identifying the device type.
- SurfaceFormat
- [in] Member of the D3DFORMAT enumerated type that specifies the format of the surface to be multisampled. For more information, see Remarks.
- Windowed
- [in] bool value. Specify TRUE to inquire about windowed multisampling, and specify FALSE to inquire about full-screen multisampling.
- MultiSampleType
- [in] Member of the D3DMULTISAMPLE_TYPE enumerated type, identifying the multisampling technique to test.
- pQualityLevels
- [out] The number of quality stops available for a given multisample type. This can be NULL if it is not necessary to return the values.
Return Values
If the device can perform the specified multisampling method, this method returns D3D_OK. D3DERR_INVALIDCALL is returned if the Adapter or MultiSampleType parameters are invalid. This method returns D3DERR_NOTAVAILABLE if the queried multisampling technique is not supported by this device. D3DERR_INVALIDDEVICE is returned if DeviceType does not apply to this adapter.
Remarks
This method is intended for use with both render-target and depth-stencil surfaces because you must create both surfaces multisampled if you want to use them together.
The following code fragment shows how you could use IDirect3D9::CheckDeviceMultiSampleType to test for devices that support a specific multisampling method.
if( SUCCEEDED(pD3D->CheckDeviceMultiSampleType( pCaps->AdapterOrdinal, pCaps->DeviceType, BackBufferFormat, FALSE, D3DMULTISAMPLE_3_SAMPLES, NULL ) ) && SUCCEEDED(pD3D->CheckDeviceMultiSampleType( pCaps->AdapterOrdinal, pCaps->DeviceType, DepthBufferFormat, FALSE, D3DMULTISAMPLE_3_SAMPLES, NULL ) ) ) return S_OK;
The preceding code will return S_OK if the device supports the full-screen D3DMULTISAMPLE_3_SAMPLES multisampling method with the surface format.
Defines the levels of full-scene multisampling that the device can apply.
typedef enum D3DMULTISAMPLE_TYPE{ D3DMULTISAMPLE_NONE = 0, D3DMULTISAMPLE_NONMASKABLE = 1, D3DMULTISAMPLE_2_SAMPLES = 2, D3DMULTISAMPLE_3_SAMPLES = 3, D3DMULTISAMPLE_4_SAMPLES = 4, D3DMULTISAMPLE_5_SAMPLES = 5, D3DMULTISAMPLE_6_SAMPLES = 6, D3DMULTISAMPLE_7_SAMPLES = 7, D3DMULTISAMPLE_8_SAMPLES = 8, D3DMULTISAMPLE_9__SAMPLES = 9, D3DMULTISAMPLE_10_SAMPLES = 10, D3DMULTISAMPLE_11_SAMPLES = 11, D3DMULTISAMPLE_12_SAMPLES = 12, D3DMULTISAMPLE_13_SAMPLES = 13, D3DMULTISAMPLE_14_SAMPLES = 14, D3DMULTISAMPLE_15_SAMPLES = 15, D3DMULTISAMPLE_16_SAMPLES = 16, D3DMULTISAMPLE_FORCE_DWORD = 0xffffffff,} D3DMULTISAMPLE_TYPE, *LPD3DMULTISAMPLE_TYPE;
Constants
- D3DMULTISAMPLE_NONE
- No level of full-scene multisampling is available.
- D3DMULTISAMPLE_NONMASKABLE
- Enables the multisample quality value. See Remarks.
- D3DMULTISAMPLE_2_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_3_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_4_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_5_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_6_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_7_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_8_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_9__SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_10_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_11_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_12_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_13_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_14_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_15_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_16_SAMPLES
- Level of full-scene multisampling available.
- D3DMULTISAMPLE_FORCE_DWORD
- Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used.
Remarks
In addition to enabling full-scene multisampling at IDirect3DDevice9::Reset time, there will be render states that turn various aspects on and off at fine-grained levels.
Multisampling is valid only on a swap chain that is being created or reset with the D3DSWAPEFFECT_DISCARD swap effect.
The multisample antialiasing value can be set with the parameters (or sub-parameters) in the following methods.
Method | Parameters | Sub-parameters |
---|---|---|
IDirect3D9::CheckDeviceMultiSampleType | MultiSampleType and pQualityLevels | |
IDirect3D9::CreateDevice | pPresentationParameters | MultiSampleType and pQualityLevels |
IDirect3DDevice9::CreateAdditionalSwapChain | pPresentationParameters | MultiSampleType and pQualityLevels |
IDirect3DDevice9::CreateDepthStencilSurface | MultiSampleType and pQualityLevels | |
IDirect3DDevice9::CreateRenderTarget | MultiSampleType and pQualityLevels | |
IDirect3DDevice9::Reset | pPresentationParameters | MultiSampleType and pQualityLevels |
It is not good practice to switch from one multisample type to another to raise the quality of the antialiasing.
D3DMULTISAMPLE_NONE enables swap effects other than discarding, locking, and so on.
Whether the display device supports maskable multisampling (more than one sample for a multiple-sample render-target format plus antialias support) or just non-maskable multisampling (only antialias support), the driver for the device provides the number of quality levels for the D3DMULTISAMPLE_NONMASKABLE multiple-sample type. Applications that just use multisampling for antialiasing purposes only need to query for the number of non-maskable multiple-sample quality levels that the driver supports.
The quality levels supported by the device can be obtained with the pQualityLevels parameter of IDirect3D9::CheckDeviceMultiSampleType. Quality levels used by the application are set with the MultiSampleQuality parameter of IDirect3DDevice9::CreateDepthStencilSurface and IDirect3DDevice9::CreateRenderTarget.
See D3DRS_MULTISAMPLEMASK for discussion of maskable multisampling.
创建使用多重采样的Direct3D设备
创建使用多重采样的Direct3D设备,需要将函数CreateDevice()的第5个参数D3DPRESENT_PARAMETERS结构体的MultiSampleType成员设为将要设置的多重采样类型,SwapEffect成员设为D3DSWAPEFFECT_DISCARD。
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
启用多重采样的全景图形反锯齿
调用渲染状态设置函数IDirect3DDevice9::SetRenderState(),将第一个参数设置为D3DRS_MULTISAMPLEANTIALIAS,将第二个参数设为TRUE将激活多重采样,设置FALSE将禁用多重采样。
图形反锯齿示例程序
示例程序AntiAlisa演示了图形反锯齿效果。目前很多显示硬件可能不支持图形反锯齿,所以在创建渲染设备前应进行设备检查,如果当前显示硬件不支持,可以创建参考设备来测试图形反锯齿效果。在示例程序AntiAlisa运行时通过单击鼠标左键,可以切换是否启用图形反锯齿操作。
启用反锯齿
禁用反锯齿
完整源代码:
#include <d3d9.h>
#define CLASS_NAME "GameApp"
#define release_com(p) do { if(p) { (p)->Release(); (p) = NULL; } } while(0)
IDirect3D9* g_d3d;
IDirect3DDevice9* g_device;
IDirect3DVertexBuffer9* g_vertex_buffer;
BOOL g_support_anti_aliasing = TRUE;
struct sCustomVertex
{
float x, y, z, rhw;
DWORD color;
};
#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
void init_vertices()
{
sCustomVertex vertices[] =
{
{ 50.0f, 250.0f, 0.5f, 1.0f, 0xffff0000, },
{ 150.0f, 50.0f, 0.5f, 1.0f, 0xff00ff00, },
{ 250.0f, 250.0f, 0.5f, 1.0f, 0xff0000ff, },
};
// push vertex data into vertex buffer
g_device->CreateVertexBuffer(sizeof(vertices), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_DEFAULT, &g_vertex_buffer, NULL);
void* ptr;
g_vertex_buffer->Lock(0, sizeof(vertices), (void**)&ptr, 0);
memcpy(ptr, vertices, sizeof(vertices));
g_vertex_buffer->Unlock();
}
bool init_d3d(HWND hwnd)
{
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(g_d3d == NULL)
return false;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
if(FAILED(g_d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, FALSE,
D3DMULTISAMPLE_4_SAMPLES, NULL)))
{
MessageBox(hwnd, "Hardware do not support antialiasing, use ref device!", "ERROR", MB_OK);
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_device)))
{
return false;
}
}
else
{
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_device)))
{
return false;
}
}
init_vertices();
return true;
}
void cleanup()
{
release_com(g_vertex_buffer);
release_com(g_device);
release_com(g_d3d);
}
void render()
{
g_device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, g_support_anti_aliasing);
g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(5, 5, 5), 1.0f, 0);
g_device->BeginScene();
g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
g_device->SetFVF(D3DFVF_CUSTOM_VERTEX);
g_device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
}
LRESULT WINAPI WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
g_support_anti_aliasing = !g_support_anti_aliasing;
break;
case WM_KEYDOWN:
switch(wParam)
{
case VK_ESCAPE:
DestroyWindow(hwnd);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR, INT)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_CLASSDC;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = inst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
wc.hIconSm = NULL;
if(! RegisterClassEx(&wc))
return -1;
HWND hwnd = CreateWindow(CLASS_NAME, "Direct3D App", WS_OVERLAPPEDWINDOW, 200, 100, 300, 300,
NULL, NULL, wc.hInstance, NULL);
if(hwnd == NULL)
return -1;
if(init_d3d(hwnd))
{
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
UpdateWindow(hwnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render();
}
}
cleanup();
UnregisterClass(CLASS_NAME, wc.hInstance);
return 0;
}