灵活顶点格式
灵活顶点格式(Flexible Vertex Format, FVF)用来描述在顶点缓冲区中的顶点存储格式中包含了哪些属性。Direct3D应用程序可以用几种不同的方式定义灵活顶点格式。灵活顶点格式使应用程序只使用它需要的顶点数据,排除那些它不需要的组成成分。这样,应用程序可以节省内存空间,减少系统带宽。通过D3DFVF的组合,可以描述图元顶点的格式。灵活顶点格式指定的格式包括点的大小,用D3DFVF_PSIZE指定,该大小在投影机空间用来表示未经变换的顶点,在设备空间用来表示经过变换的顶点。
接口IDirect3DDevice9的渲染方法能够接受这些标志的组合,并用它们来决定如何渲染图元。这些标志告诉系统应用程序所使用的顶点的组成,包括顶点的位置、顶点混合权重、法向量、颜色和纹理坐标的格式和数量,以及向Direct3D申请何种渲染流水线。另外,提交或撤销一个具体的顶点格式标志会告诉系统哪些顶点组成单元还留在系统中,哪些已经被忽略了。
纹理坐标可用不同的格式声明,纹理可以由一个坐标寻址,也可以由多达4个纹理坐标来寻址。使用宏集合D3DFVF_TEXCOORDSIZEn可以创建位模式,定义要使用的顶点格式所需的纹理坐标格式。
为了使用索引顶点混合,标志D3DFVF_LASTBETA_UBYTE4应该追加到顶点灵活格式中去。这个标志的出现表明第5个混合权重将被当作一个DWORD值,而不是一个浮点值。
渲染状态
设备渲染状态控制Direct3D设备的光栅化组件的行为。通过改变渲染状态属性,可以控制使用何种着色模式,如何进行雾化及其他光栅化操作。Direct3D编程很大一部分工作就是设置合适的渲染状态。
Direct3D图形程序通过调用IDirect3DDevice9::SetRenderState()函数来设置渲染状态。枚举类型D3DRENDERSTATETYPE列举出所有可能的渲染状态。应用程序将D3DRENDERSTATETYPE类型的某一个枚举值作为第一个参数传递给函数SetRenderState(),然后用第二个参数指定相应的渲染状态。
着色模式
Direct3D中的物体表面是由许许多多的多边形构成的。当渲染一个物体的多边形时,不同的着色模式在其表面产生不同的效果。着色模式决定了多边形上每个点的颜色和光照的强度。Direct3D提供两种着色模式:平面着色模式(FLAT)和戈劳德着色模式(GOURAUD)。
(1)平面着色模式
在平面着色模式下,Direct3D渲染一个多边形时,把多边形第一个顶点的颜色作为整个多边形的颜色进行着色,也就是说,在平面着色模式下,一个多边形内的所有像素的颜色都等于该多边形第一个顶点的颜色。如果这些多边形不共面,用平面着色模式渲染的三维图形将出现明显的陡沿。平面着色模式是渲染速度最快的着色模式。
(2)戈劳德着色模式
当用戈劳德着色渲染一个多边形时,它会先用顶点法向量和灯光参数计算每个顶点的颜色。然后,在该多边形的表面上进行线性插值,进而得到每个像素的颜色。例如,顶点1颜色的红色值为0.8,顶点2颜色的红色至为0.4,使用戈劳德着色模式和RGB颜色模式,Direct3D灯光组件将使这两点连线上中点的颜色的红色值为0.6。
(3)着色模式比较
在平面着色模式中,相邻两个面之间会有明显的边缘,而采用戈劳德着色模式时,边缘处的着色值会由内插运算产生,因而最后会得到一个弯曲的表面。在戈劳德着色模式下,对平面光照的处理要比在平面着色模式下更真实。在平面着色模式下,一个面的颜色是唯一的,但戈劳德着色模式可以使光线更准确地照射在每一个面上。当一个表面距离一个点光源很近时,它们的区别将会更明显地表现出来。
戈劳德着色模式可以使在平面着色模式下多边形间的陡沿变得平滑。然而这样可能会导致马赫带效应(Mach
bands)的产生,也就是相邻的颜色或光线带之间不能很平滑的相互融合。对于程序开发人员来说,可以通过增加构成对象的多边形的数目来降低马赫带效应,当然也可以通过提高屏幕分辨率或者增加程序的颜色深度来达到目的。
(4)设置着色模式
Direct3D一次只能选择一种着色模式。默认情况下,选择戈劳德着色模式。在Direct3D图形程序中,调用IDirect3DDevice9::
SetRenderState()方法来改变着色模式。设置状态参数为D3DRS_SHADEMODE,该状态参数值必须是D3DSHADEMODE枚举成员的一个。
Defines constants that describe the supported shading
modes.
typedef enum D3DSHADEMODE
{
D3DSHADE_FLAT = 1,
D3DSHADE_GOURAUD = 2,
D3DSHADE_PHONG = 3,
D3DSHADE_FORCE_DWORD = 0x7fffffff,
} D3DSHADEMODE, *LPD3DSHADEMODE;
Constants
- D3DSHADE_FLAT
- Flat shading mode. The color and specular
component of the first vertex in the triangle are used to determine the
color and specular component of the face. These colors remain constant
across the triangle; that is, they are not interpolated. The specular alpha
is interpolated. See Remarks.
- D3DSHADE_GOURAUD
- Gouraud shading mode. The color and specular
components of the face are determined by a linear interpolation between all
three of the triangle's vertices.
- D3DSHADE_PHONG
- Not supported.
- D3DSHADE_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
The first vertex of a triangle for flat shading mode is
defined in the following manner.
- For a triangle list, the first vertex of the
triangle i is i * 3.
- For a triangle strip, the first vertex of the
triangle i is vertex i.
- For a triangle fan, the first vertex of the
triangle i is vertex i + 1.
The members of this enumerated type define the vales
for the D3DRS_SHADEMODE render state.
多边形填充模式
默认状态下,Direct3D会把渲染好的多边形面的图像绘制出来,这种方法适合于绝大多数情况。然而,有时为了调试程序或其他特殊目的,可能只需绘制出多边形的顶点或边。这可以通过设置渲染状态D3DRS_FILLMODE来实现,通过为D3DRS_FILLMODE渲染状态指定枚举类型D3DFILLMODE中的一个数值,来选择多边形填充模式。
Defines constants describing the fill mode.
typedef enum D3DFILLMODE
{
D3DFILL_POINT = 1,
D3DFILL_WIREFRAME = 2,
D3DFILL_SOLID = 3,
D3DFILL_FORCE_DWORD = 0x7fffffff,
} D3DFILLMODE, *LPD3DFILLMODE;
Constants
- D3DFILL_POINT
- Fill points.
- D3DFILL_WIREFRAME
- Fill wireframes.
- D3DFILL_SOLID
- Fill solids.
- D3DFILL_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
The values in this enumerated type are used by the
D3DRS_FILLMODE render state.
着色模式和填充模式示例程序
示例程序RenderState演示了着色模式和填充模式对图形显示结果的影响,在RenderState示例程序中用全局变量g_is_flat和g_fill_mode控制渲染图形使用的着色模式和填充模式,通过单击鼠标左键在两种着色模式之间进行切换,单击鼠标右键在三种填充模式之间进行切换。
Gouraud着色模式
、
FLAT着色模式
点模式
线模式
完整源代码:
#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_is_flat = false;
DWORD g_fill_mode = D3DFILL_SOLID;
struct sCustomVertex
{
float x, y, z, rhw;
DWORD color;
};
#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
void init_vertices()
{
sCustomVertex vertices[] =
{
{ 100.0f, 400.0f, 0.5f, 1.0f, 0xffff0000, },
{ 300.0f, 50.0f, 0.5f, 1.0f, 0xff00ff00, },
{ 500.0f, 400.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;
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_SHADEMODE, g_is_flat ? D3DSHADE_FLAT : D3DSHADE_GOURAUD);
g_device->SetRenderState(D3DRS_FILLMODE, g_fill_mode);
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_is_flat = !g_is_flat;
break;
case WM_RBUTTONDOWN:
if(g_fill_mode == D3DFILL_POINT)
g_fill_mode = D3DFILL_WIREFRAME;
else if(g_fill_mode == D3DFILL_WIREFRAME)
g_fill_mode = D3DFILL_SOLID;
else if(g_fill_mode == D3DFILL_SOLID)
g_fill_mode = D3DFILL_POINT;
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, 600, 500,
NULL, NULL, wc.hInstance, NULL);
if(hwnd == NULL)
return -1;
if(init_d3d(hwnd))
{
ShowWindow(hwnd, SW_SHOWDEFAULT);
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;
}