网页功能: 加入收藏 设为首页 网站搜索  
DirectX 图形接口指南
发表日期:2003-10-10作者:译:In355Hz[] 出处:  

译者申明:

这些指南是我在阅读 DirectX8.1 SDK 中逐步翻译出来的。对于初次接触 DirectX Graphics 的编程者而言,这应该是很好的上手资料。其实,本人就是从这些指南开始深入 Direct3D8.1 的;由于这是本人第一次翻译英文材料,言语不通,词不达意之处一定很多,一些术语也译得很勉强,请见谅。

此外,需要转载此文者,请保留以下部分:

-----------------------------------------------------------------------

DirectX图形接口指南 译者:In355Hz 电子邮箱: In355Hz@hotmail.com

-----------------------------------------------------------------------

DirectX 图形接口指南:(应用于 DirectX 8.1 版 C/C++ 编程)

本区域的指南将说明如何在 C/C++ 程序中使用 Microsoft Direct3D 和 Direct3DX 完成一些普通的工作。这些工作总是被分解成若干个必要的步骤。在某些情况下,为了使表达更清楚,一些步骤还被细分成几个子步骤。

本区域提供的指南有:

· 指南一:创建设备

· 指南二:演示顶点

· 指南三:使用矩阵

· 指南四:创建和使用光源

· 指南五:使用纹理映射

· 指南六:使用Mesh模型

提示:指南中出现的示例代码来自于每个指南具体提供的路径里的源文件。

这些指南中的源代码是用 C++ 写成的。如果使用C编译器,你必须适当的改变这些文件使它们能够编译通过。最少的,你需要加入 vtable 然后用它引用接口函数。

包含在示例代码中的一些注解可能与来自 Microsoft Platform Software Development Kit (SDK) 中的源代码不同。这些改变仅仅为了简化表述并且只限于注解中,这样能够防止示例程序的行为被改变。

指南一:创建设备

为了使用 Microsoft Direct3D,你首先需要创建一个应用程序窗口,并紧接着创建和初始化 Direct3D 对象。你应该使用这些对象提供的 COM 接口来操纵它们,以及创建描绘一个场景所必需的其它对象。本指南包含的 CreateDevice 示例将例示并说明以下几个工作:创建 Direct3D 设备并且绘制一个简单的蓝色屏幕。

这个指南使用以下步骤:初始化 Direct3D,绘制场景,以及最后清理与关闭。

·步骤一:创建一个窗口

·步骤二:初始化 Direct3D

·步骤三:处理系统消息

·步骤四:绘制与显示场景

·步骤五:关闭与清除

注意:CreateDevice 示例程序的路径在:

(SDK root)\Samples\Multimedia\Direct3D\Tutorials\Tut01_CreateDevice.

步骤一:创建一个窗口

任何 Microsoft Windows 程序执行中必须要作的第一件事就是创建一个应用程序窗口并将其显示给用户。为做到这点,CreateDevice 例程将首先实现它的 WinMain 函数。以下示例代码完成了窗口的初始化。

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )

{

// Register the window class.

WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,

GetModuleHandle(NULL), NULL, NULL, NULL, NULL,

"D3D Tutorial", NULL };

RegisterClassEx( &wc );

// Create the application's window.

HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 01: CreateDevice",

WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,

GetDesktopWindow(), NULL, wc.hInstance, NULL );

前述示例代码是标准的 Windows 编程。例子开始时定义和注册了一个窗口类名为 "D3D Tutorial"。类注册以后,示例代码使用已注册的类创建了一个基本的顶层(top-level)窗口,客户区域为 300 像素宽,300 像数高。这个窗口没有菜单或子窗口。示例使用了 WS_OVERLAPPEDWINDOW 属性创建一个包括最大化,最小化,以及关闭按钮的普通窗口。(如果该例程将运行在全屏模式下,首选的窗口属性应该是WS_EX_TOPMOST,它指定创建的窗口置于并且保持在所有非最高(non-topmost)窗口之前,甚至在窗口失活的情况下。)一旦窗口创建完成,例代码调用标准的 Microsoft Win32 函数显示和更新窗口。

在应用程序窗口准备好以后,你就能开始设置具体的 Microsoft Direct3D 对象了,

请见:步骤二:初始化 Direct3D

步骤二:初始化 Direct3D

CreateDevice 示例在 WinMain 中创建窗口之后,调用该程序定义的函数 InitD3D 完成 Microsoft Direct3D 初始化过程。在创建窗口之后,程序已经准备好初始化你将用来绘制场景的 Direct3D 对象了。这个过程包括创建一个 Direct3D 对象,设置Present Parameters,以及最后创建 Direct3D 设备。

创建完 Direct3D 对象之后,你可以立即使用 IDirect3D8::CreateDevice 方法创建 Direct3D 设备。你也能够使用 Direct3D 对象枚举设备,类型,模式以及其他东西。这些工作的代码段应位于使用 Direct3DCreate8 函数创建 Direct3D 对象之后。

if( NULL == ( g_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) )

return E_FAIL;

传递给 Direct3DCreate8 的唯一参数应该始终是 D3D_SDK_VERSION,它告诉 Direct3D 当前使用的头文件信息。无论如何,头文件或者其他的变化将导致这个值增加并强制使用该值的应用程序重新编译。如果此版本不匹配,调用 Direct3DCreate8 将失败。

下一个步骤是使用 IDirect3D8::GetAdapterDisplayMode 接口找到当前的显示模式,代码如下:

D3DDISPLAYMODE d3ddm;

if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )

return E_FAIL;

D3DDISPLAYMODE 结构中的 Format 变量将被用于创建 Direct3D 设备。如果是运行于窗口模式下的话,Format 参数通常用来创建一个与适配器当前模式相匹配的后背缓冲 (Back buffer)。

在给 D3DPRESENT_PARAMETERS 各参数赋值时,你必须指定你的应用程序在3D下工作的方式。本 CreateDevice 例程设置D3DPRESENT_PARAMETERS结构中 Windowed 为 TRUE,SwapEffect 为 D3DSWAPEFFECT_DISCARD,BackBufferFormat 为 d3ddm.Format。

D3DPRESENT_PARAMETERS d3dpp;

ZeroMemory( &d3dpp, sizeof(d3dpp) );

d3dpp.Windowed = TRUE;

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.BackBufferFormat = d3ddm.Format;

最后一步,是利用 IDirect3D8::CreateDevice 函数创建 Direct3D 设备,代码如下:

if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,

D3DCREATE_SOFTWARE_VERTEXPROCESSING,

&d3dpp, &g_pd3dDevice ) ) )

前述代码使用 D3DADAPTER_DEFAULT 标志创建了一个使用省缺适配器的设备。在非常多数的情况下,系统只有一个适配器,除非它安装了多个图形加速卡。通过把 DeviceType 参数设成 D3DDEVTYPE_HAL,表示你希望获得一个实际硬件设备 (hardware device) 而不是软件虚拟设备 (software device)。示例代码还使用 D3DCREATE_SOFTWARE_VERTEXPROCESSING 标志通知系统使用软件顶点处理 (software vertex processing)。注意,如果你指定 D3DCREATE_HARDWARE_VERTEXPROCESSING 标志通知系统使用硬件顶点处理 (hardware vertex processing),你可以在支持硬件顶点处理的图形加速卡上得到大幅度的性能提升。

现在 Direct3D 已经初始化完毕,下一步是确保你的程序具有一个机制用来来处理系统消息,

见下文:步骤三:处理系统消息

步骤三:处理系统消息

完成创建程序窗口以及初始化 Direct3D 以后,你已经准备好绘制场景 (Render scene)。大多数情况下,Microsoft Windows 程序在它们的消息循环里监视系统消息,并且在队列里没有消息时绘制画面帧。然而,CreateDevice 例程仅仅在等到一个WM_PAINT出现在队列里时,才通知应用程序重绘窗口的所有部分。

// The message loop.

MSG msg;

while( GetMessage( &msg, NULL, 0, 0 ) )

{

TranslateMessage( &msg );

DispatchMessage( &msg );

}

当每循环一次,DispatchMessage 调用 MsgProc,后者负责处理队列里的消息,当 WM_PAINT 消息进队时,调用该程序自身定义的函数 Render(),它将负责重绘窗口。然后 Microsoft Win32 函数 ValidateRect 执行并将整个客户区域设为有效。

消息处理函数的例代码如下:

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )

{

switch( msg )

{

case WM_DESTROY:

PostQuitMessage( 0 );

return 0;

case WM_PAINT:

Render();

ValidateRect( hWnd, NULL );

return 0;

}

return DefWindowProc( hWnd, msg, wParam, lParam );

}

现在,应用程序处理了系统消息,接着的一步是绘制显示,见:步骤四:绘制与显示场景

步骤四:绘制与显示场景

为了描绘和显示需要的场景,本例程在这一步把后背缓冲 (back buffer) 填充为蓝色,然后将此后背缓冲的内容传给前景缓冲 (front buffer), 并且将前景缓冲提交至屏幕。

清除表面,应调用 IDirect3DDevice8::Clear 函数:

// Clear the back buffer to a blue color

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

Clear() 接受的前两个参数通知 Microsoft Direct3D 被清除的矩形区域数组的基址和大小,该矩形区域数组描述了绘制目标表面 (render target surface) 里需要清除的区域。

在大多数情况下,只使用单个矩形覆盖整个绘制目标表面。这样你只需设置第一个参数为 0 及第二个参数为 NULL。第三个参数将决定方法的行为,你可以通过设置特定的标志用来清除绘制目标表面 (render target surface),关联的Z缓冲 (associated depth buffer),模版缓冲 (stencil buffer),以及任意这三者的混合。本指南不使用Z缓冲,所以仅仅使用了 D3DCLEAR_TARGET 标志。最后三个参数分别用于设置对应绘制目标表面、Z缓冲和模版缓冲的清除填充值 (reflect clearing values)。该 CreateDevice 例程将绘制目的表面的清除填充色设置为蓝色 (D3DCOLOR_XRGB(0,0,255)。由于相应的标志没有设置,最后两个参数被 Clear() 忽略。

在清除了视口 (viewport) 之后,CreateDevice 例程告知 Direct3D 绘图将要开始,然后立即通知这次绘制完成,见以下代码段:

// Begin the scene.

g_pd3dDevice->BeginScene();

// Rendering of scene objects happens here.

// End the scene.

g_pd3dDevice->EndScene();

当绘制开始或完成时,IDirect3DDevice8::BeginScene 和 IDirect3DDevice8::EndScene 函数将用信号通知系统。你只能在这两函数之间调用其它的绘图函数。即使调用绘图函数失败,你也应该在重新调用 BeginScene 之前调用 EndScene。

绘制完之后,调用 IDirect3DDevice8::Present显示该场景:

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

Present() 接受的前两个参数是原始矩形和目标矩形。在这一步,例程设置这两个参数为 NULL 并把整个后备缓冲提交到前景缓冲。第三个参数用于设置该次提交的目标窗口。因为这个参数被设为 NULL,实际使用的窗口是 D3DPRESENT_PARAMETERS 的 hWndDeviceWindow 成员。第四个是 DirtyRegion 参数,在绝大多数情况下应该设为 NULL。

本指南的最终步骤是关闭应用程序,见:步骤五:关闭与清除

步骤五:关闭与清除

在执行的若干时刻,你的应用程序必须立即关闭。关闭一个 Direct3D 应用程序中不只是意味着你必须销毁程序窗口,并且你还要释放程序中使用过的的任何 Direct3D 对象并且无效化它们的指针。当收到一个 WM_DESTROY 消息时,CreateDevice 例程通过调用一个本地定义的函数 Cleanup() 来处理这些工作。

VOID Cleanup()

{

if( g_pd3dDevice != NULL)

g_pd3dDevice->Release();

if( g_pD3D != NULL)

g_pD3D->Release();

}

上述函数对每个对象调用 IUnknown::Release 方法来释放它们自身。由于DirectX遵循 COM 规则,大多数对象当其引用计数降为0时,DirectX会自动的从内存中释放这个对象。

对于其他关闭程序情况,可能发生在程序的平常执行中——比如用户改变了桌面的参数或色深——此时你可能需要撤销和重建使用中的 Microsoft Direct3D 对象。因此一个好的主意就是将你的释放代码放到一起,以便能在需要时随时调用它。

本指南已经说明了如何创建一个设备,指南二:演示顶点(Render Vertex) ,将告诉你如何用顶点(Vertex)创建几何形体。

指南二:演示顶点(Render Vertex)

Microsoft Direct3D 写的应用程序使用顶点(Vertex)构造几何物体。每一个三维空间 (3D) 场景包括一个或几个这样的几何物体。Vertices 例程构造简单的物体,一个三角形,并且将它绘制到显示屏上。

本指南说明如何采用以下步骤从顶点构造一个三角形:

·第一步:定义一个自定义顶点类型

·第二步:设置顶点缓冲

·第三步:绘制至显示屏

注意:Vertices 示例程序的路径为:

(SDK root)\Samples\Multimedia\Direct3D\Tutorials\Tut02_Vertices.

Vertices 程序的示例代码与 CreateDevice 的代码大部分相同。本“演示顶点(Render Vertex)”指南仅仅关注于那些独特的,关于顶点的代码而不包括初始化 Direct3D,处理 Microsoft Windows 消息,绘图,与清理等工作。如要得到有关这些任务的信息,请参考 指南一:创建设备。

第一步:定义一个自定义顶点类型

Vertices 例程使用三个顶点构造一个 2D 的三角形。这里提及了顶点缓冲的概念,这是用于保存和演示大量顶点的 Microsoft Direct3D 对象。通过指定一个自定义的顶点结构和相应的可变向量格式 (FVF),顶点能够采用很多方法定义。本 Vertices 例程使用的顶点格式定义于以下代码片断中。

struct CUSTOMVERTEX

{

FLOAT x, y, z, rhw; // The transformed position for the vertex.

DWORD color; // The vertex color.

};

上面的结构体说明了自定义顶点类型的格式。下一步是定义 FVF 以描述顶点缓冲区中的顶点内容。以下代码片段定义了一个 FVF 并符合此上建立的自定义顶点类型。

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)

可变顶点格式标记描述了使用中的自定义顶点类型。前述示例代码使用了 D3DFVF_XYZRHW 和 D3DFVF_DIFFUSE 标志,这将告诉顶点缓冲,自定义顶点类型包含一组转换过的点坐标并紧跟着一个颜色参数。

现在自定义向量格式和 FVF 已经被指定好了,下一步将使用顶点填充顶点缓冲区,请参看:第二步:设置顶点缓冲 。

注意:Vertices 例程中的顶点是转换过的。用另一句话说,它们已经在 2D 窗口坐标系下。这意味着座标点 (0,0) 位于左上角,且正的 x 半轴向右,正的 y 半轴向下。这些顶点同样也是光照过的,这说明它们的着色不通过 Direct3D 照明而由它们自己的颜色代替。

第二步:设置顶点缓冲

现在自定义顶点格式已经完成,初始化顶点的时候到了。 Vertices 例程创建了必需的 Microsoft Direct3D 对象之后调用本程序内部定义的函数 InitVB() 进行这个工作。以下代码段将初始化三个自定义顶点的值。

CUSTOMVERTEX g_Vertices[] =

{

{ 150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color

{ 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },

{ 50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },

};

前述代码片段采用三角形的三个顶点填充三个Vertex并指定了每个顶点的散射光的颜色。第一个顶点位于 (150,50) ,散射红色 (0xffff0000)。第二个顶点位于 (250,250) ,为绿色 (0xff00ff00)。第三点位于 (50,250) 并散射蓝绿色 (0xff00ffff)。每一点都具有相同的 0.5 Z值及 1.0 的 RHW 参数。关于这些矢量格式的其它信息见 SDK: Transformed and Lit Vertices。

下一步将调用 IDirect3DDevice8::CreateVertexBuffer 创建顶点缓冲区,如以下代码段所示:

if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX),

0 /* Usage */, D3DFVF_CUSTOMVERTEX,

D3DPOOL_DEFAULT, &g_pVB ) ) )

return E_FAIL;

CreateVertexBuffer 的头两个参数告诉 Direct3D 新顶点缓冲区预计的大小和用法。紧跟的两个参数指定新缓冲区的矢量格式及存储位置。这里的向量格式是 D3DFVF_CUSTOMVERTEX,就是例程先前定义的 FVF 值。D3DPOOL_DEFAULT 标记告诉 Direct3D 在最合适的位置创建此顶点缓冲区。最后一个参数返回创建完成的顶点缓冲区对象地址。

创建了顶点缓冲区之后,如以下代码段所示,开始采用自定义格式的顶点填充缓冲区中的数据。

VOID* pVertices;

if( FAILED( g_pVB->Lock( 0, sizeof(g_Vertices), (BYTE**)&pVertices, 0 ) ) )

return E_FAIL;

memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );

g_pVB->Unlock();

首先调用 IDirect3DVertexBuffer8::Lock 锁定顶点缓冲区。函数第一个参数是锁定顶点数据的偏移量,按字节计算。第二个参数是需锁定的顶点数据长度,同样按字节计算。第三个参数是一个 BYTE 类型指针的地址,用于返回指向顶点数据的地址。第四个参数告知顶点缓冲区如何锁定数据。

通过使用 memcpy,顶点被复制到顶点缓冲区里。将顶点放入缓冲区之后,调用一次 IDirect3DVertexBuffer8::Unlock 以解锁顶点缓冲区。这个锁定——解锁机制是必需的,因为正在使用的顶点缓冲区可能位于设备内存中。

现在顶点缓冲区已经填入顶点,绘制到显示的时候到了,见描述:第三步:绘制至显示屏 。

第三步:绘制至显示屏

现在缓冲区已经填入顶点,现在需要把它绘制到显示屏上。在绘制到屏幕之前,先将背景清除为蓝色并调用 BeginScene。

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0L );

g_pd3dDevice->BeginScene();

从顶点缓冲区绘制顶点数据需要一些步骤。首先,你需要设置流数据源;在当前情况下,使用第 0 个流 。流的数据源是通过调用 IDirect3DDevice8::SetStreamSource 设置的。

g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );

SetStreamSource 的第一个参数告诉 Microsoft Direct3D 设备设置数据流的索引。第二个参数是绑定在该数据流上的顶点缓冲区。第三个参数是数据单元的大小,用字节数表示。在上面的示例代码中,将使用CUSTOMVERTEX 的大小作为数据单元的大小。

下一步通过调用 IDirect3DDevice8::SetVertexShader 使 Direct3D 了解使用中的顶点处理器(Vertex Shader)。就整体而言,自定义顶点处理器是一种高级的话题,但是在绝大多数情况下顶点处理器仅仅等于 FVF 代码。这能够让 Direct3D 知道处理中的顶点类型。以下代码片段将FVF设置为当前顶点处理器:

g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );

SetVertexShader() 唯一的参数是当前设置的顶点处理器的句柄。这个参数的值可以是从IDirect3DDevice8::CreateVertexShader 返回的句柄,或者是 FVF 代码。在这儿,使用的参数是定义为 D3DFVF_CUSTOMVERTEX 的 FVF 代码。

关于顶点处理器的更多信息,请见 SDK: Vertex Shader 一章。

下一步使用 IDirect3DDevice8::DrawPrimitive 绘制顶点缓冲区中的顶点,见以下代码片段:

g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );

DrawPrimitive 接受的第一个参数是一个标记,它通知 Direct3D 绘制哪种类型的物件(Primitive)。本例程使用 D3DPT_TRIANGLELIST 标记指定为三角形序列。第二个参数是第一个顶点的索引。第三个参数通知绘制的物件的数目。本例子只画一个三角形,这个值为 1。

关于不同种类物件的更多信息,可见 SDK: 3-D Primitive

最后的一步是结束场景并立即将后背缓冲提交为前景缓冲。这些写在以下代码片段中:

g_pd3dDevice->EndScene();

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

当后背缓冲被提交为前景缓冲后,客户窗口将显示出一个三个点颜色各异的三角形。

本指南已经指导你如何使用顶点构造几何外形了。指南三:使用矩阵 将介绍矩阵的概念以及如何使用它们。

指南三:使用矩阵

本指南介绍矩阵的概念及演示如何使用它们。Vertices 例程通过呈递2D的顶点画出了一个三角形。然而,在这个指南中,你将通过顶点变换在 3-D 环境下工作。矩阵和变换也同样用于设置摄影头与视口(Viewport)。

在 Matrices 例程呈递几何物体之前,它调用程序自定义函数 SetupMatrices 创建并设置用于演示 3-D 三角形的矩阵变换。作为代表,三种类型的变换同时被设置到一个 3-D 场景。创建这些典型变换的步骤如下表:

·第一步:定义世界变换矩阵

·第二步:定义观察变换矩阵

·第三步:定义映射变换矩阵

注意:Matrices 示例程序的路径为:

(SDK root)\Samples\Multimedia\Direct3D\Tutorials\Tut03_Matrices.

创建这三种变换的顺序并不影响场景元素的输出。无论如何,Direct3D 都使用以下顺序依次将矩阵作用于场景:(1) 世界,(2) 观察,(3) 映射。

Matrices 工程的示例代码几乎与 Vertices 工程的代码相同。该“使用矩阵”指南仅仅关注那些有关矩阵的独特代码,而不重复初始化 Direct3D,处理 Microsoft Windows 消息,演示,以及清除。关于这些工作的信息,请见 指南一:创建设备 。

本指南使用自定义顶点格式和单个顶点缓冲区呈递几何模型,关于更多的有关选择自定义顶点类型以及执行顶点缓冲区的信息,见 指南二:演示顶点 。

第一步:定义世界变换矩阵(World Transformation Matrix)

世界变换矩阵定义了怎样转换、缩放、以及旋转 3-D 模拟空间中的几何物体。

以下代码片段为 Microsoft Direct3D 设备设置当前的世界变换并且使三角形绕 y-轴 旋转。

D3DXMATRIX matWorld;

D3DXMatrixRotationY( &matWorld, timeGetTime()/150.0f );

g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

第一步是通过调用 D3DXMatrixRotationY 函数使三角形绕 y-轴 旋转。函数第一个参数是指向 D3DMATRIX 结构的指针用于返回操作结果。第二个参数是以弧度表示的旋转角度。

下一步是调用 IDirect3DDevice8::SetTransform 给 Direct3D 设备设置世界变换。SetTransform 接受的第一个参数通知 Direct3D 被设置的是哪个转换。这个例子用 D3DTS_WORLD 宏指定被设置的是世界变换。第二个参数是一个指向被设为当前变换之矩阵的指针。

关于世界变换的更多信息,见:SDK: World Transformation

定义完场景的世界变换后,你可以准备观察变换矩阵了。再一次请注意:定义任一变换的顺序不是关键。无论如何,Direct3D 采用以下顺序将这些矩阵作用于场景:(1) 世界,(2) 观察,(3) 映射。

定义观察变换矩阵请参看 第二步:定义观察变换矩阵

第二步:定义观察变换矩阵(View Transformation Matrix)

观察变换矩阵定义了观察的位置和旋转角度。此观察矩阵就相当于场景的摄影机。

以下代码片段创建了一个观察变换矩阵并将其设置为 Microsoft Direct3D 设备的当前观察矩阵。

D3DXMATRIX matView;

D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 3.0f,-5.0f ),

&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),

&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

第一步是通过调用 D3DXMatrixLookAtLH 定义观察矩阵。第一个参数是一个指向 D3DXMATRIX 结构的指针,用来接受操作结果。第二、三、四个参数定义了观察点、注视点、以及方向“上”。这儿设置观察点为沿 Z-轴 反方向 5 单位再往上 3 单位,注视点为原点,以及作为“上”的方向为 Y-轴。

下一步是调用 IDirect3DDevice8::SetTransform 给 Direct3D 设备设置观察矩阵。SetTransform 接受的第一个参数通知 Direct3D 哪一个变换将要被设置。该例程使用 D3DTS_VIEW 标记指定为观察矩阵。第二个参数是一个指向矩阵的指针,它被设为当前的变换。

关于观察矩阵的更多信息,见:SDK: View Transformation

定义了场景的世界变换后,你可以开始准备映射变换矩阵了。再一次提醒,定义每一变换的顺序不是关键性的。无论如何,Direct3D 总是采用以下顺序将矩阵应用于场景:(1) 世界,(2) 观察,(3) 映射。

定义映射变换矩阵的工作被描述在 第三步:定义映射变换矩阵

第三步:定义映射变换矩阵(Projection Transformation Matrix)

映射变换矩阵定义了将 3-D 观察空间转换为 2-D 视口空间的几何学方法。

以下代码片段创建映射变换矩阵并将其设为 Microsoft Direct3D 设备的当前映射变换。

D3DXMATRIX matProj;

D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );

g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

第一步是调用 D3DXMatrixPerspectiveFovLH 设置映射矩阵。函数第一个参数是一个指向 D3DXMATRIX 的结构,用于接受操作的结果。第二个参数定义视场,它说明物体如何随着距离而缩小。一个典型的视场是 1/4 π,就像这个例子使用的一样。第三个参数定义了屏幕纵横比。本示例采用典型的纵横比 1。第四和第五个参数定义最近和最远剪切平面。这是用于确定位于何种距离之外的几何物体无需再绘制。本 Matrices 示例设置它的最近剪切平面为 1,最远剪切平面为 100。

下一步是调用 IDirect3DDevice8::SetTransfrom 对 Direct3D 应用变换。SetTransfrom 接受的第一个参数通知 Direct3D 何种变换被设置。本例程使用 D3DTS_PROJECTION 标志指定映射变换将被设置。第二个参数是一个指向矩阵的指针,它将被设置为当前的变换。

关于映射变换的更多信息,参见:“映射变换”

本指南已经提示你如何使用矩阵。指南四:创建和使用光源 将揭示如何在你的场景中添加光源以增加真实性。

指南四:创建和使用光源

Microsoft Direc3D 光照系统给 3-D 物体提供更多的真实性。当使用它时,每个场景中的几何对象将被照亮,基于它们的位置和使用的光源类型。这个指南的例程将介绍关于光照和材质的主题。

本指南包含以下步骤用于创建材质与光照:

·第一步:创始化场景几何

·第二步:设置材置与光照

注意:Lights 示例程序的路径为:

(SDK root)\Samples\Multimedia\Direct3D\Tutorials\Tut04_Lights.

注意:Lights 例程中的代码和 Matrices 例程的代码几乎完全一样。“创建和使用光源”指南仅仅关注于有关创建和使用光照的独特代码,而并不重复有关设置 Direct3D,处理 Microsoft Windows 消息,绘制,或者清理的内容。关于这些任务的其他信息,见:指南一:创建设备。

本指南使用自定义顶点和顶点缓冲区呈递几何形体。关于选择一个自定义顶点格式并执行顶点缓冲的更多信息,见:指南二:演示顶点。

本指南采用矩阵变换几何对象。关于矩阵和变换的更多信息,参见:指南三:使用矩阵。

第一步:创始化场景几何

使用光照的一个前提是每个表面都应该有法向量。为此,Lights 例程使用一个稍微不同的自定义顶点格式,新的自定义顶点格式具有一个 3-D 位置坐标和一个表面法向量。这个表面法向量被用于 Microsoft Direct3D 光照计算的核心。

struct CUSTOMVERTEX

{

D3DXVECTOR3 position; // The 3-D position for the vertex.

D3DXVECTOR3 normal; // The surface normal for the vertex.

};

// Custom FVF.

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)

现在适当的矢量格式定义好了,Lights 例程调用 InitGeometry(),一个程序自定义的函数以创建一个圆柱体。最初的步骤是创建一个顶点缓冲区并用它保存这个圆柱体的各点,如以下例代码所示:

// Create the vertex buffer.

if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50*2*sizeof(CUSTOMVERTEX),

0 /* Usage */, D3DFVF_CUSTOMVERTEX,

D3DPOOL_DEFAULT, &g_pVB ) ) )

return E_FAIL;

下一步是使用圆柱体的顶点填充顶点缓冲区。注意下面的示例代码,每个点都被定义了一个位置和一个法向量。

for( DWORD i=0; i<50; i++ )

{

FLOAT theta = (2*D3DX_PI*i)/(50-1);

pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );

pVertices[2*i+0].normal = D3DXVECTOR3( sinf(theta), 0.0f, cosf(theta) );

pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );

pVertices[2*i+1].normal = D3DXVECTOR3( sinf(theta), 0.0f, cosf(theta) );

}

在前述例程使用圆柱体顶点填充了顶点缓冲区之后,这个顶点缓冲区已经准备好用于呈递了。但是首先,这个场景的材质与光照必须在绘制圆柱体之前被设置。这些描述在 第二步:设置材质与光照。

第二步:设置材质与光照

为了在 Microsoft Direct3D 中使用光照,你必须创建一个或多个光源。为了确定一个几何物体放射何种颜色的光线,材质必须被创建于绘制几何对象。在绘制这个场景之前,Lights 例程调用 SetupLights,一个程序自定义函数来设置材质和一个方向性光源。

创建一种材质

材质被定义为当一束光照到几何物体表面后,反射出的颜色。以下代码片段使用 D3DMATERIAL8 结构来创建一个黄色的材质。

D3DMATERIAL8 mtrl;

ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );

mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;

mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;

mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;

mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;

g_pd3dDevice->SetMaterial( &mtrl );

这个材质的漫射光颜色与环境光颜色都被设为黄色。对 IDirect3DDevice8::SetMaterial 函数的调用将应用此材质到用于绘制场景的 Microsoft Direct3D 设备。SetMaterial() 接受的唯一参数是设置材质的指针。在这个调用完成以后,每个物件都将使用这个材质绘制直到另一次对 SetMaterial 的调用指定了一个不同的材质为止。

现在材质已经被应用到场景,下一个步骤是创建光源。

创建一个光源

Microsoft Direct3D 里有三种可用的光源:点光源,方向形光源,与聚光灯光源。本示例代码创建一个方向形光源,它向一个方向发光,并且不停的变换发光的方向。

下列代码片段使用 D3DLIGHT8 结构创建一个方向性光源。

D3DXVECTOR3 vecDir;

D3DLIGHT8 light;

ZeroMemory( &light, sizeof(D3DLIGHT8) );

light.Type = D3DLIGHT_DIRECTIONAL;

下列代码片设置光源的漫射光为白色。

light.Diffuse.r = 1.0f;

light.Diffuse.g = 1.0f;

light.Diffuse.b = 1.0f;

以下代码片在一个环内旋转光源的方向。

vecDir = D3DXVECTOR3(cosf(timeGetTime()/360.0f),

0.0f,

sinf(timeGetTime()/360.0f) );

D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );

对 D3DXVec3Normalize 函数的调用将归一化方向矢量并初始化光源的方向。

可以设置一个范围告诉 Direct3D 此光源能影响多远的距离。这个成员参数对方向性光源无效。以下代码片指定此光源的范围为 1000 单位。

light.Range = 1000.0f;

下面的代码片将这个光源分配到当前的 Direct3D 设备,通过调用 IDirect3DDevice8::SetLight。

g_pd3dDevice->SetLight( 0, &light );

SetLight 接受的第一个参数是此光源被分配的索引号。注意如果在此索引已存在一个光源,它将被新光源覆盖。第二个参数是一个指向新定义光源数据结构的指针。本 Lights 例程设置这个光源位于 0 号索引。

下列代码片激活这个光源,通过调用 IDirect3DDevice8::LightEnable。

g_pd3dDevice->LightEnable( 0, TRUE);

LightEnable 接受的第一个参数是激活光源的索引。第二个参数是一个布尔量通知此光源是开 (TRUE) 还是闭 (FALSE)。在上面的例程中,索引 0 上的光源被打开。

以下代码片通知 Direct3D 呈递此光源,通过调用 IDirect3DDevice8::SetRenderState。

g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );

SetRenderState 接受的头两个参数是哪一个设备状态变量被改写以及写入何种值。本例程设置 D3DRS_LIGHTING 设备变量为 TRUE,这将使设备能够演示光照效果。

本例程的最后一步是通过再一次调用 SetRenderState 打开环境照明光。

g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 );

当前代码段设置 D3DRS_AMBIENT 设备变量为一种浅灰色 (0x00202020)。环境照明将使用所给的颜色照亮所有的物体。

关于照明及材质的更多信息,参见 SDK: Lights and Materials。

本例程向你说明了如何使用照明与材质。指南五:使用纹理映射 将向你说明如何将纹理添加到物体表面上。

指南五:使用纹理映射

我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 DirectX 图形接口指南
本类热点文章
  WIN32音频数据采集 WaveIn-Out实现
  Windows环境下Unicode编程总结
  Windows SDK入门浅谈 — 写给初学者
  Windows SDK入门浅谈 — 写给初学者
  SendMessage进程间简单通信问题
  以程序的方式操纵NTFS的文件权限
  以程序的方式操纵NTFS的文件权限
  SDK编程笔记 - DLL篇
  SDK编程笔记 - DLL篇
  API 层实现语音录制
  API 层实现语音录制
  盗QQ的密码软件模拟实现
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2024 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00465