c++图形学实验教程:Direct3D程序设计基础_第1页
c++图形学实验教程:Direct3D程序设计基础_第2页
c++图形学实验教程:Direct3D程序设计基础_第3页
c++图形学实验教程:Direct3D程序设计基础_第4页
c++图形学实验教程:Direct3D程序设计基础_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 MACROBUTTON MTEditEquationSection2 Equation Chapter 1 Section 1 SEQ MTEqn r h * MERGEFORMAT SEQ MTSec r 1 h * MERGEFORMAT SEQ MTChap r 1 h * MERGEFORMAT Direct3D程序设计基础本章将介绍使用Direct3D进行游戏动画绘制的基础知识,只要会简单的VC+编程以及一点立体几何的基础知识即可完成本章给出的实例。通过它,可以了解到Direct3D的基本概念,学会绘制简单的几何图形,并掌握光源、材质和纹理的基本用法。 3D绘图的实质就是在二维计算

2、机屏幕上绘制三维形体,为此要用到一些数学变换来建模和处理几何图形。第一节 DirectX 与Direct3D简介1.1 开发环境 DirectX是Microsoft公司开发的运行于计算机平台的多媒体控制处理引擎。对于通常所说的DirectX实际上有两种不同的含义:一是指DirectX SDK(即DirectX开发工具包)或称为DirectX API(应用程序编程接口),它是Microsoft公司提供的一套用于开发高性能多媒体程序的应用程序接口;二是指DirectX Runtime,它是一组动态链接库,是运行利用DirectX SDK开发的程序所必需的动态库。在安装游戏时,经常会询问用户是否安装

3、新版本的DirectX,这时所提到的DirectX就是指DirectX Runtime。对于程序员来说,DirectX主要是指DirectX SDK,本章中提到的DirectX如无特殊说明也是指DirectX SDK。基于DirectX API设计开发的多媒体软件运行于硬件抽象层(Hardware Abstraction Layer, HAL )上,即充分利用了系统硬件的加速功能,又隐藏了硬件相关的设备特性,通过编写与设备无关的高效代码,DirectX程序总能以最佳方式运行,因此具有效率高,并且易于开发的优点,一推出就深受多媒体开发人员的喜爱。除支持效率极高的硬件抽象层外DirectX还支持软

4、件运行于软件参考层(Reference Layer,REF)上,软件参考层能使不支持某些硬件加速功能的设备使用软件模拟相应的功能特性,在对运行速度要求不高的系统中使用高级的DirectX功能。DirectX在计算机游戏设计中应用最为广泛,当前流行的绝大多数游戏都支持DirectX,并拥有出色的性能。最新推出的DirectX 9.0,对早期的DirectX的功能进行了完善和补充,新增了更多最新的多媒体特性,能够充分发挥计算机硬件的性能,可以说是三维软件特别是游戏软件开发的有效工具。本章采用DirectX SDK 9.0版。为了创建Direct3D程序,首先需要从微软网站下载安装DirectX S

5、DK。由于微软已经在SDK中包含了DirectX9的安装文件,因此安装完SDK后,就搭建好了开发环境和编译环境。DirectX由几部分组成,每部分负责特定的功能。其中Direct3D是负责三维图形的组件,也是DirectX最重要、最复杂的组成部分。本章将介绍使用Direct3D开发三维图形程序的相关内容。本章将以MFC基于对话框的应用程序为框架,在其上添加Direct3D绘图功能。 1.2 COM对象 DirectX的功能都是以COM对象的形式提供的。COM是组件对象模型(Component Object Model)的简写,它是对一组特定功能的抽象集合,应用程序不能直接访问COM对象,而是必

6、须通过对COM对象的接口(Interface)的指针执行COM对象的功能(COM对象接口指针在使用上类似于C+类的指针)。所谓接口,其实就是一组特殊的C+对象,应用程序通过调用这些对象的成员函数,来访问COM对象,实现组件的功能。因此,COM对象可看作一种协议,用来实现软件模块间的二进制连接。当这种连接建立后,两个模块之间就可以通过接口的机制来通信。目前常用的ActiveX控件就是一种COM对象。COM的实现细节相当复杂,不过微软已经最大限度地简化了COM的使用。作为Direct3D开发人员,只要了解接口及其用法就行了。COM对象在被应用程序调用时,通常像个黑匣子,作为一个DLL动态库被调用。

7、同普通的DLL动态库一样,COM对象接口定义了一组函数,供应用程序调用并完成所有它所支持的任务。在COM术语中,这些成员函数被称作方法(Method)。虽然称呼变了,但应用程序和COM对象相互作用的方法与它和普通的C+对象之间的调用语法相类似。接口的特殊性在于它的生成和销毁都由系统完成,无须用户干预。COM对象进行了更为严格的封装。不仅能创建它并能调用所有的公有方法。一个COM对象的公有方法被集成到一个或多个接口。为了使用某个方法,必须创建这个对象并从它这里得到恰当的接口。一个接口一般包括一组相关的方法,由它们提供对该对象特定属性的访问。任何非接口提供的方法都不能使用。COM对象具有如下特点:

8、COM对象的创建方法与C+对象不同。有几种不同的方法可以创建COM对象,但它们都包括具体的COM技术。必须使用具体的COM技术来控制对象的生命期。COM对象无需明确加载。COM对象通常位于一个DLL动态库中,但无需明确加载该动态库或连接到静态库来使用COM对象。每个COM对象都有一个惟一的注册标识符用来创建对象。COM会自动加载正确的DLL动态库。COM是个二进制文件。许多语言都可以使用COM对象,无须知道该对象的源代码。例如,Microsoft Visual Basic应用程序可以使用C+写成的COM对象。在Direct3D编程中,要做的工作基本上可以归纳为: 调用适当的函数获取接口指针;

9、调用接口的方法(成员函数)来完成所需功能; 用完接口后,调用Release方法进行“释放”,注意释放顺序应该和获取它们的顺序相反。 第二节 Direct3D程序基本结构 本节将给出一个简单的Direct3D程序,它在MFC对话框程序的基础上,生成一个蓝色背景的Direct3D窗口。通过该例程,帮助读者了解Direct3D的初始化过程。 2.1 创建程序框架 进入VC,新建一个工程d3d,工程类型选“MFC AppWizard (exe)”,即MFC应用程序,然后把程序类型设置为“Dialog Based”基于对话框的应用程序,如 REF _Ref201249595 h 图 1所示。按“Next

10、”进入应用程序向导第二步,去掉在该步骤中的所有选项,如 REF _Ref201249868 h 图 2所示。从第三步以后的其余选项使用缺省设置即可,所以此时可直接按“Finish”,结束应用程序向导。这里之所以选择基于对话框的应用程序,主要是为了借用MFC的界面和消息处理机制,同时也可避免文档视图结构中的复杂关系和一些无关的代码。 图 SEQ 图 * ARABIC 1 应用程序向导第一步图 SEQ 图 * ARABIC 2 应用程序向导第二步在成功创建完基于对话框的应用程序后,得到是如 REF _Ref201250266 h * MERGEFORMAT 图 3所示的对话框,该对话框是应用程序的

11、主画面。由于要在该对话框内进行3D图形的绘制,所以直接删除对话框中预留的所有控件(包括两个按钮和一个文本框),并将对话框尺寸调整为方形,最终得到的是一个干净的程序主画面。此时,对该工程进行编译和连接,并执行,得到如 REF _Ref201250833 h 图 4所示的画面,这是一个无任何功能的基于对话框的应用程序。由于绘制的三维图形会受到显示窗口长宽比例的影响而发生变形,因此,有必要确保显示窗口长宽比例为1时,即对话框尺寸调整为方形。图 SEQ 图 * ARABIC 3 基于对话框的应用程序框架图 SEQ 图 * ARABIC 4 无任何功能的基于对话框的应用程序接下来,就需要向这个工程中添加

12、添加Direct3D功能的代码。 为了简化代码,本章中的程序均忽略了出错情况下的处理。但在正式编程中,还是应该考虑进行适当的出错处理。2.2 初始化Direct3D 对于Direct3D程序来说,第一步要做的就是创建Direct3D对象,然后用该对象创建设备对象。设备对象可以说是Direct3D中最重要的部件,几乎所有的3D绘图功能都要通过它实现。 在类视图(ClassView)中可以看出,该工程中有两个类CD3DApp类和CD3DDlg类。本章的主要代码基本都是在CD3DDlg类的“D3DDlg.cpp”和“D3DDlg.h”两个文件中完成的。首先为类CD3DDlg添加下列成员: (D3DD

13、lg.h) . . #include #include class CD3DDlg : public CWnd protected: LPDIRECT3D9 m_pD3D; /Direct3D对象的接口指针 LPDIRECT3DDEVICE9 m_pDevice; /设备对象的接口指针 void InitD3D(); /该函数用于初始化Direct3D . . 输入初始化函数InitD3D的代码: (D3DDlg.cpp) void CD3DDlg:InitD3D() /创建Direct3D对象,并获取接口IDirect3D9的指针, /通过该指针操作Direct3D对象。 m_pD3D =

14、:Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS d3dpp; :ZeroMemory(&d3dpp, sizeof(d3dpp); d3dpp.Windowed = TRUE; /创建窗口模式的Direct3D程序 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; /调用方法IDirect3D9:CreateDevice创建设备对象,并获取 /接口IDirect3DDevice9的指针,通过该指针操作设备对象 m_

15、pD3D-CreateDevice( D3DADAPTER_DEFAULT, /使用缺省的显卡 D3DDEVTYPE_HAL, /指定设备类型为HAL m_hWnd, /Direct3D窗口的句柄 D3DCREATE_SOFTWARE_VERTEXPROCESSING,/软件顶点处理 &d3dpp, &m_pDevice); 作为Direct3D中的渲染部件,设备对象用于顶点变换、光照处理以及矢量图形的光栅化。Direct3D目前支持两种设备类型:HAL(硬件抽象层 Hardware Abstraction Layer)和Reference。前者启用硬件三维加速功能,需要显卡支持,如NVIDI

16、A的TNT、GeForce系列;后者则以软件模拟方式完成三维处理,虽然速度慢,但可以在任意显卡上运行,一般用于调试程序,其对应的参数为D3DDEVTYPE_REF。 上述代码使用了软件顶点处理方式,如果显卡支持硬件T/L,如GeForce系列,可以选用硬件方式以提高效率,调用参数为D3DCREATE_HARDWARE_VERTEXPROCESSING。 用类向导为CD3DDlg添加WM_CREATE的消息处理函数OnCreate,在其中调用InitD3D,以便在创建窗口的同时完成初始化工作: (D3DDlg.cpp) int CD3DDlg:OnCreate(LPCREATESTRUCT lp

17、CreateStruct) if (CWnd:OnCreate(lpCreateStruct) = -1) return -1; InitD3D(); /初始化Direct3D return 0; 2.3 渲染 初始化完成后,就可以开始执行渲染操作,即前面所说的绘图。 在Direct3D中,一个设备对象至少包含两个显示缓存区:当前缓存区(Front Buffer)和后备缓存区(Back Buffer),前者可以看成Direct3D窗口的映射。当使用双缓冲区技术时,应用程序不会直接去改变用于显示的显示内存中的内容。相反的,它要改变的是位于显示内存中的另一块区域,这块区域被称为后端缓冲区。可以在任

18、何需要的时候改变后端缓冲区的内容,然后在垂直空白间隔期间再把整个后端缓冲区的内容和前端缓冲区内容相交换(或称为切换),这样新的前端缓冲区将被扫描。如 REF _Ref201308872 h 图 5所示。快速重复此过程,就会在屏幕上形成连续的动画。 图 SEQ 图 * ARABIC 5 当前缓存区与后备缓存区示意图现在来编写渲染部分的代码,给CD3DDlg添加一个成员函数Render: (D3DDlg.h) . . void InitD3D(); void Render(); /该函数用于渲染 . . (D3DDlg.cpp) void CD3DDlg:Render() /用指定颜色清除后备缓存

19、区 m_pDevice-Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), /指定使用蓝色 1.0f, 0); /Direct3D规定在渲染前必须调用方法IDirect3DDevice9:BeginScene, /结束时要调用IDirect3DDevice9:EndScene。 m_pDevice-BeginScene(); /实际的渲染代码放在此处。因为本节只是为了演示如何初始化Direct3D, /所以这里为空,生成的Direct3D窗口将是一个蓝色背景的空白窗口 m_pDevice-EndScene(); /交换当前/后备缓存

20、区,刷新窗口 m_pDevice-Present(NULL, NULL, NULL, NULL); 打开类向导,为CD3DDlg添加WM_PAINT的消息处理函数OnPaint,在其中调用Render: (D3DDlg.cpp) void CD3DDlg:OnPaint() CPaintDC dc(this); Render(); /渲染 2.4 释放接口 为CD3DDlg添加成员函数Cleanup,输入“释放”代码: (D3DDlg.h) . . void Render(); void Cleanup(); /该函数用于释放接口 . . (D3DDlg.cpp) void CD3DDlg:C

21、leanup() m_pDevice-Release(); /释放设备对象 m_pD3D-Release(); /释放Direct3D对象 用类向导为CD3DDlg添加WM_DESTROY的消息处理函数OnDestroy,在其中调用Cleanup。这样当窗口关闭时,就会自动释放接口: (D3DDlg.cpp) void CD3DDlg:OnDestroy() CWnd:OnDestroy(); Cleanup(); /释放接口 现在代码已经全部输入完毕,不过在编译前,还需要为连接器指定Direct3D的导入库:选择VC的菜单项“Project/Settings.”,然后选中“Link”标签,在

22、“Object/library modules”栏输入“d3d9.lib d3dx9.lib”(本节中的例程只用到了d3d9.lib,另外一个库文件是为后面程序准备的)。 编译运行程序,会弹出一个蓝色的Direct3D窗口(见 REF _Ref201252455 h 图 6)。至此,就完成了Direct3D的初始化程序。 图 SEQ 图 * ARABIC 6 Direct3D的初始化程序第三节 五角星的绘制3.1 一些数学概念 在开始编程之前,读者有必要了解一些有关三维坐标系的基本概念。按坐标轴之间的相互关系划分,三维坐标系可分为左手坐标系和右手坐标系,如 REF _Ref203564232

23、h 图 7所示。在左手坐标系中,坐标轴的定义符合左手法则:左手四个手指的旋转方向从X轴到Y轴,大拇指的指向就是Z轴。右手坐标系依次类推。Direct3D使用左手坐标系,其中X轴表示左右,Y轴表示上下,Z轴表示远近(深度)。 图 SEQ 图 * ARABIC 7 左手坐标系(左图),右手坐标系(右图)在Direct3D中,三角形是构成实体的基本单位,因为一个三角形正好是一个平面,以三角形面为单位进行渲染效率最高。大量的三角形组合在一起,构成复杂的多边形或者曲面。 一个三角形由三个点构成,习惯上把这些点称为顶点(Vertex)。三角形平面有正、反面之分,由顶点的排列顺序决定:顶点按顺时针排列的表面

24、是正面,如 REF _Ref203564301 h 图 8所示。其中与三角形平面垂直、且指向正面的矢量称为该平面的法线(Normal)。在Direct3D中,为了提高渲染效率,缺省条件下只有正面可见,不过可以通过IDirect3DDevice9:SetRenderState来改变设置,其对应的渲染状态常数为D3DRS_CULLMODE。图 SEQ 图 * ARABIC 8 顶点与平面法线顶点法线(Vertex Normal)是过顶点的一个矢量,用于在高洛德着色(Gouraud Shading)中计算光照和纹理效果。在生成曲面时,通常令顶点法线和相邻平面的法线保持等角,如 REF _Ref203

25、564375 h 图 9所示,这样进行渲染时,会在平面接缝处产生一种平滑过渡的效果。如果是多边形,则令顶点法线等于该点所属平面(三角形)的法线,如 REF _Ref203564521 h 图 10所示,以便在接缝处产生突出的边缘。 图 SEQ 图 * ARABIC 9 曲面的顶点法线图 SEQ 图 * ARABIC 10 多边形的顶点法线3.2 图元格式 在Direct3D中,三维实体都是由一些基本图元组合而成的,总共有6种图元格式。 REF _Ref203578458 h 表 1列出了6种图元格式和对应的含义,示例参见 REF _Ref203564872 h 图 11:表 SEQ 表 * A

26、RABIC 1 Direct3D图元格式图元格式Direct3D表示含义点列(Point Lists)D3DPT_POINTLIST = 1由顶点组成的集合线列(Line Lists)D3DPT_LINELIST = 2由直线段组成的集合线带(Line Strips)D3DPT_LINESTRIP = 3由互相连接的直线段组成的集合三角形列(Triangle Lists)D3DPT_TRIANGLELIST = 4由三角形组成的集合,每三个顶点构成一个三角形三角形带(Triangle Strips)D3DPT_TRIANGLESTRIP = 5由相接的三角形组成的集合。在例图中,v1、v2、v

27、3构成第一个三角形,v2、v3、v4构成第二个三角形. .(注意:三角形带的正面由第一个三角形决定,因此第二个三角形顶点的排列顺序实际上应该为v2、v4、v3)三角扇形(Triangle Fans)D3DPT_TRIANGLEFAN = 6由相接且共点的三角形组成,v1、v2、v3构成第一个三角形,v1、v3、v4构成第二个三角形. .(a) D3DPT_POINTLIST(b) D3DPT_LINELIST(c) D3DPT_LINESTRIP(d) D3DPT_TRIANGLELIST(e) D3DPT_TRIANGLESTRIP(f) D3DPT_TRIANGLEFAN图 SEQ 图 *

28、 ARABIC 11 6种图元格式上述图元中,后三种以三角形为单位的图元比较常用。其中三角形列适用范围较广,既能用于多边形,也可用于曲面;而三角形带和三角扇形由于存在公共顶点,如果用来创建多边形,其公共顶点的法线不好确定,因此通常只用于曲面,不过在三角形数目相同的情况下,它俩使用的顶点数目要比前者少得多。 3.3 坐标变换 要显示以三维坐标表示的三维景物模型,应用程序必须完成从三维坐标到二维坐标(世界坐标到屏幕坐标)的转换,称之为坐标变换。可以把坐标变换想象成摄影过程,三维世界的景物通过相机的拍摄在二维的相片上显示出来,所不同的是相片换成了屏幕。1)世界变换 世界变换把坐标从相对于模型的局部原

29、点定义顶点的模型空间,改变成相对于场景中所有对象的一个公共原点定义顶点的世界空间。世界变换的本质就是把一个模型放置在世界中。 REF _Ref203576407 h 图 12给出了世界坐标系和一个模型局部坐标系之可关系的图解表示。世界变换可以包含平移、旋转和缩放的组合。图形学中通过一个44的矩阵来表示三维物体的空间几何变换,把表示三维物体在世界空间中几何变换的矩阵称为世界变换矩阵,简称世界矩阵。通常情况下,作用于物体的不仅仅是一个几何变换,而往往是几个几何变换的组合。将这些几何变换所对应的变换矩阵连乘,便得到最终的世界变换矩阵。图 SEQ 图 * ARABIC 12 世界变换对实体进行平行移动

30、,其对应的平移变换阵可由函数D3DXMatrixTranslation求得; 把实体沿自身的Z轴旋转一个角度(角度大于0,表示从Z轴的正向朝原点看去,旋转方向为顺时针;反之为逆时针,下同),对应的旋转变换阵用D3DXMatrixRotationZ计算; 把实体沿自身的Y轴旋转一个角度,对应的旋转变换阵用D3DXMatrixRotationY计算; 把实体沿自身的X轴旋转一个角度,对应的旋转变换阵用D3DXMatrixRotationX计算; 对实体进行缩放,对应的变换阵可由函数D3DXMatrixScaling求得; 在Direct3D中,矩阵乘法用函数D3DXMatrixMultiply实现

31、。 2)视见变换 为了使三维景物在屏幕上成像,必须设置一个观察点,它相当于一个虚拟相机,三维物体从世界空间到观察空间的坐标变换过程称为视见变换,其变换对应的矩阵称为视见矩阵。在Direct3D中设置视见矩阵非常简单,首先调用Direct3D函数D3DXMatrixLookAtLH(),生成一个基于左手坐标系的虚拟相机的观察矩阵:D3DXMATRIX * D3DXMatrixLookAtLH ( D3DXMATRIX * pOut,/ 生成的观察矩阵存放地址 CONST D3DXVECTOR3 *pEye,/ 观察点位置坐标 CONST D3DXVECTOR3 *pAt,/ 被观察点的位置坐标,

32、此时视线方向就是从观察者指向被观察点 CONST D3DXVECTOR3 *pUp/虚拟相机的向上向量,通常取(0,1,0);然后调用函数HRESULT SetTransform( D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX * pMatrix);设置Direct3D观察矩阵,其中pMatrix为D3DXMatrixLookAtLH生成的观察矩阵。确定后,以观察者为原点,视线为Z轴,上方向或它的一个分量为Y轴(X轴可由左手法则得出,为右方向),构成了视见坐标系,如 REF _Ref203576610 h 图 13所示。图 SEQ 图 * ARABI

33、C 13 视见变换3)投影变换 将三维坐标投影到二维投影平面的过程也是一种坐标变换,称为投影变换,可以用投影矩阵来完成这个变换。典型的投影矩阵实现的是一种缩放和透视投影。透视投影的特点是远处的物体在投影平面上的投影缩小了。物体距相机越远,它的成像就越小。透视投影的取景范围是一个截头体。对于透视观察,观察截头体可以形象化为一个棱锥,摄像机位于它的顶尖。这个棱锥被前、后裁剪平面所分割,如 REF _Ref203576900 h 图 14所示。在前、后裁剪平面之间的棱锥内部的体积就是观察截头体。对象只有在这个三维几何体中才是可见的。设想观察者正站在一间黑屋子里,通过一个方窗户朝外看,这时他正在可视化

34、一个观察截锥。与此类似,前面的裁剪平面就是窗户,后面的裁剪平面就是最后遮住观察者视线的物体、街道上的大楼或远处的山等。被截断的棱锥内部的每一件东西观察者都能看见,这以外的东西一概看不见。图 SEQ 图 * ARABIC 14 透视投影变换同样的,可以利用Direct3D函数D3DXMatrixPerspectiveFovLH(),创建一个透视投影矩阵。D3DXMATRIX * D3DXMatrixPerspectiveFovLH( D3DXMATRIX * pOut,/生成的透视投影矩阵存放的地址 FLOAT fovy,/ 视野在y轴上的成像角度(弧度表示),通常取/4 FLOAT Aspec

35、t,/ 截头体前裁剪平面的纵横比,通常取1 FLOAT zn,/ 截头体前裁剪平面距相机的距离 FLOAT zf/截头体后裁剪平面距相机的距离);用这四个量来调用函数D3DXMatrixPerspectiveFovLH,即可获得投影变换矩阵。 得到三个变换矩阵后,还需要调用方法IDirect3DDevice9:SetTransform把它们设置到渲染环境中,具体用法参见后面的例程。 最后,可以用三句话来概括这些变换的作用:世界变换决定实体的位置;视角变换决定观察者的位置;投影变换决定观察者的可视区域。 3.4 顶点格式Direct3D采用了一种被称之为弹性顶点格式(Flexible Verte

36、x Format(FVF)的技术。弹性顶点格式(FVF)码描述了交叉存储在单个数据流中顶点的内容。它通常说明了要被固定功能顶点处理流水线处理的数据。除顶点坐标外,还可以包括顶点的法线、颜色、纹理等数据。Direct3D应用程序能以几种不同的方式定义建模的顶点。对弹性顶点定义(也叫弹性顶点格式或弹性顶点格式码)的支持使用应用程序只使用必需的顶点成员成为可能,这样就消除了无用的成员。通过只使用必需的顶点成员,应用程序可以节省内存并最小化渲染建模需要的处理带宽。应用程序通过使用D3DFVF的组合来定义顶点格式。FVF规范包含了点的大小的格式,由D3DFVF_PSIZE指定。对非TL顶点而言,这个大小

37、表示的是摄像机空间中的单位,对TL顶点而言,则是设备空间中的单位。IDirect3DDevice9接口给C+应用程序提供了一些方法,可以接收这些标志的组合,并使用它们决定如何渲染图元。基本上,这些标志告诉系统应用程序使用哪些顶点成员位置,顶点混合加权值,法向,颜色,纹理坐标的数量和格式并且间接地说明要使用渲染流水线中的哪些部分。另外,某个特定顶点格式标志的存在与否会通知系统哪些顶点成员域存在于内存中,而哪些被省略了。要测定设备的限制,可以查询设备是否具有D3DFVFCAPS_DONOTSTRIPLELEMENTS和D3DVFVCAPS_TEXCOORDCOUNTMASK弹性顶点格式标志。系统对

38、如何安排顶点有一个重要规定,那就是数据出现的顺序。 REF _Ref203407617 h 表 2描绘了所有可能的顶点成员在内存中规定的顺序,以及它们相应的数据类型。表 SEQ 表 * ARABIC 2 灵活顶点格式标识符说明D3DFVF_DIFFUSE顶点数据中包含漫反射颜色D3DFVF_NORMAL顶点数据中包含法线向量,不能和D3DFVF_XYZRHW同时使用D3DFVF_PSIZE顶点信息指明绘制点的大小D3DFVF_SPECULAR顶点数据中包含镜面反射颜色值D3DFVF_XYZ顶点数据中包含未经坐标变换的顶点坐标,不能和D3DFVF_XYZRHW同时使用D3DFVF_XYZRHW顶

39、点数据中包含经过坐标变换的顶点坐标,不能和D3DFVF_NORMAL同时使用D3DFVF_XYZB1D3DFVF_XYZB5顶点数据中包含用于骨骼动画的顶点和顶点对骨骼的权重信息D3DFVF_XYZW顶点数据中包含经过坐标变换和裁剪的顶点坐标,只可用于可编程顶点流水线D3DFVF_TEX0D3DFVF_TEX8顶点数据中包含0-8个纹理坐标,用于纹理绘制纹理坐标可以被声明为不同的格式,这使纹理可以用最少一个坐标或最多四个坐标(二维投影纹理坐标)进行寻址。应该用D3DFVF_TEXCOORDSIZEn系列宏创建应用程序使用的顶点格式中的纹理坐标格式。没有哪个应用程序会使用每个成员齐次坐标W的倒数

40、(RHW)和顶点法向这两个域是互斥的。大多数应用程序也不会使用所有八组纹理坐标,但Direct3D具有这种能力。对于应用程序如何使用标志有一些限制。例如,不能同时使用D3DFVF_XYZ和D3DFVF_XYZRHW标志,同时使用意味着应用程序描述的是一个既未经变换又经过变换的顶点位置。3.5 绘制五角星 3.5.1现在来绘制一个五角星。该五角星在本地坐标系的数学模型如 REF _Ref201504064 h 图 15所示,五个外角顶点和五个内角顶点构成了一个10边形。设五角星中心到外角顶点的距离OA为R=1,则可相应算出五角星中心到内角顶点的距离)OF。选取三角扇形作为实体的图元格式,三角扇形

41、共享的顶点为五角星中心O,其它顶点为A-J,顶点处在z=1的平面内,排列顺序如图所示。 图 SEQ 图 * ARABIC 15 五角星的绘制3.5.2首先要定义顶点格式。在本节中,用到了坐标和颜色。通常情况下,实体的外观由材质、光照和纹理决定,不需要再另外为顶点定义颜色,但目前还没有讲到这些内容,因此要给出顶点的颜色。Direct3D在渲染时,将使用顶点颜色,通过插值算法来填充三角形。 打开上一节生成的例程d3d001,在D3DDlg.cpp的开始部分中加入FVF的定义: (D3DDlg.cpp) . . #include D3DDlg.h /定义FVF的顶点结构 struct CUSTOMV

42、ERTEX float x, y, z; /顶点坐标 DWORD color; /顶点颜色 ; /定义FVF用到的数据项:坐标 颜色 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE) . . 在Direct3D中,FVF顶点数据按图元的格式,顺序存放在顶点缓存区(Vertex Buffer),它是一个COM对象,通过接口IDirect3DVertexBuffer9访问。以下是创建顶点缓存区的代码: (D3DDlg.h) . . void Cleanup(); LPDIRECT3DVERTEXBUFFER9 m_pVB; /顶点缓

43、存区的的接口指针 void InitGeometry(); /该函数用于建模 . . (D3DDlg.cpp) void CD3DDlg:InitGeometry() int i;double theta;const int n = 5;const double R = 1.0;const double r = R / (sin(51 * D3DX_PI/180) + tan(72 * D3DX_PI/180) * cos(51 * D3DX_PI/180);srand( (unsigned)time(NULL) );/以系统时间为参数设定随机种子。/建立五角星的数学模型 CUSTOMVERT

44、EX vertices2*n+2; vertices0.position = D3DXVECTOR3( 0.0f, 0.0f, 1.0f ); /中心点的坐标 vertices0.color = D3DCOLOR_XRGB(255,255,0); /中心点的颜色 for ( i = 1,theta = D3DX_PI/2; i CreateVertexBuffer( sizeof(vertices), /缓存区尺寸 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &m_pVB, NULL ); /把顶点数据填入顶点缓存区void* pVertices; m_p

45、VB-Lock( 0, sizeof(vertices), (void*)&pVertices, 0 ); memcpy( pVertices, vertices, sizeof(vertices) ); m_pVB-Unlock(); 修改CD3DDlg:OnCreate,加入对InitGeometry的调用: (D3DDlg.cpp) . . InitD3D(); InitGeometry(); /进行建模 . . 由于顶点缓存区是COM对象,还要在CD3DDlg:Cleanup中添加它的释放代码: (D3DDlg.cpp) . . m_pVB-Release(); /释放顶点缓存区 m_

46、pDevice-Release(); . . 3.5.3本例把实体放到世界坐标系的原点,让它绕Y轴做顺时针旋转,为此要用到一个定时器,在WM_TIMER的处理函数中不断改变旋转角度。 对于视角变换,观察点定在(0,0,-5),视线目标点取原点,上方向取Y轴的正向,对应矢量为0,1,0。 投影变换的可视角取/4,高宽比取1,两个裁剪平面的距离分别取1和100。 下面是生成变换矩阵的代码: (D3DDlg.h) . . void InitGeometry(); int m_nRotateY; /实体的旋转角度(单位:度) void SetupMatrices(); /该函数用于设置三个变换矩阵 .

47、 . (D3DDlg.cpp) void CD3DDlg:SetupMatrices() float angle = m_nRotateY * D3DX_PI / 180; /把旋转角换算成弧度 D3DXMATRIX matWorld; /计算世界变换矩阵 :D3DXMatrixRotationY( &matWorld, angle ); /把世界变换矩阵设置到渲染环境 m_pDevice-SetTransform( D3DTS_WORLD, &matWorld ); D3DXVECTOR3 eye( 0.0f, 0.0f,-5.0f ); /观察点D3DXVECTOR3 lookat( 0.

48、0f, 0.0f, 0.0f ); /视线目标点 D3DXVECTOR3 up( 0.0f, 1.0f, 0.0f ); /上方向 D3DXMATRIX matView; /计算视角变换矩阵 :D3DXMatrixLookAtLH( &matView, &eye, &lookat, &up ); /把视角变换矩阵设置到渲染环境 m_pDevice-SetTransform( D3DTS_VIEW, &matView ); D3DXMATRIXA16 matProj; /计算透视投影变换矩阵 :D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.

49、0f, 1.0f, 100.0f ); /把投影变换矩阵设置到渲染环境 m_pDevice-SetTransform( D3DTS_PROJECTION, &matProj ); 在CD3DDlg:OnCreate中添加定时器的初始化语句: (D3DDlg.cpp) . . InitD3D(); InitGeometry(); m_nRotateY = 0; SetTimer( 1, 40 ,NULL ); /定时间隔设为40毫秒 . . 用类向导为CD3DDlg添加WM_TIMER的消息处理函数OnTimer,在其中累加旋转角度: (D3DDlg.cpp) void CD3DDlg:OnTi

50、mer(UINT nIDEvent) m_nRotateY += 2; /每次旋转2度 CWnd:OnTimer(nIDEvent); 3.5.4修改CD3DDlg:Render,在其中加入五角星的绘制语句: (D3DDlg.cpp) . . m_pDevice-BeginScene(); SetupMatrices(); /设置变换矩阵 /设置自定义的FVF m_pDevice-SetFVF( D3DFVF_CUSTOMVERTEX ); /绑定顶点缓存区至设备数据源 m_pDevice-SetStreamSource( 0, m_pVB, 0, sizeof(CUSTOMVERTEX) )

51、; /绘制图元,其中参数1为图元格式,参数3为三角形数目 m_pDevice-DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 10 ); m_pDevice-EndScene(); . . 因为要让五角星旋转,所以Render的调用改放在时钟消息处理函数OnTimer中,原来的OnPaint函数用类向导予以删除: (D3DDlg.cpp) . . Render(); /渲染 m_nRotateY += 2; . . 最后,要禁用光照处理(缺省是打开的)。因为本例程使用顶点颜色进行渲染,如果不禁用的话,将会看到一个黑糊糊的五角星。另外,缺省情况下Direct3D只挑选五

52、角星的正面进行渲染,当旋转到一定角度,背面朝向观察者时,图像会消失,因此要关闭该项特性。相关代码加在函数CD3DDlg:InitD3D中: (D3DDlg.cpp) . . m_pD3D-CreateDevice( . . /因为使用顶点颜色渲染,所以要禁用光照处理 m_pDevice-SetRenderState( D3DRS_LIGHTING, FALSE ); /关闭“挑选”功能,允许渲染背面 m_pDevice-SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); . . 编译运行程序,将会出现一个旋转的五角星,如 REF _Ref201331

53、965 h 图 16所示。图 SEQ 图 * ARABIC 16 五角星绘制程序的运行结果第四节 索引缓存和Z缓存 本节将通过绘制一个空间正二十面体,介绍索引缓存(Index Buffer)和Z缓存(Z-Buffer)的用法。 4.1 索引缓存 在Direct3D中,实体模型中的一个点可能被多个三角形面所共用。对于空间正二十面体,每个顶点是五条边的端点,每条边出现在两个相邻的三角形中,每个面是封闭的三角形面,如 REF _Ref201506295 h 图 17所示。 图 SEQ 图 * ARABIC 17 空间正二十面体的图示上节所使用的三角扇形图元格式只能用来绘制有限的三维形状,即这些形状必

54、须有公用的三角形顶点。但对于本例中的复杂形状,三角扇形的图元格式则不再适用。为此Direct3D引入了索引缓存的概念,把顶点的具体数据和代表图元格式的顶点顺序分开存储:顶点数据仍然放到顶点缓存区中,索引缓存区则按照图元格式,顺序存放顶点的索引。 以上面的空间正二十面体的为例: REF _Ref201507251 h 表 3和 REF _Ref201678959 h 表 4分别给出了正二十面体的顶点缓冲区和顶点索引缓冲区,其中=。表 SEQ 表 * ARABIC 3 正二十面体的顶点缓冲区编号xyz0011-0120-13-0-141051-06-107-1-0801901-100-1110-1

55、-表 SEQ 表 * ARABIC 4 正二十面体的顶点索引缓冲区编号三角形顶点索引编号三角形顶点索引00, 4, 8109, 2, 1110, 5, 101111,3, 922, 4, 9122, 4, 0311,2, 5130, 5, 241, 6, 8141, 6, 3510,1, 7153, 7, 169, 3, 6166, 8, 473, 7, 11174, 9, 6810,0, 8185, 10,798, 1, 10197, 11,54.2 创建索引缓存 打开上一节的例程,为CD3DDlg添加一个数据成员,用来保存索引缓存区的接口指针: (D3DDlg.h) . . void Se

56、tupMatrices(); LPDIRECT3DINDEXBUFFER9 m_pIB; /索引缓存区的接口指针 . . 修改函数CD3DDlg:InitGeometry中的建模部分,并添加索引缓存区的创建代码: (D3DDlg.cpp) void CD3DDlg:InitGeometry() /正二十面体的数学模型 CUSTOMVERTEX vertices = /FVF顶点数据 phi, 0.0f, 1.0f, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 11-0 -phi, 0.0f, 1.0f phi, 0.0f, -1.0f

57、, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 13-2 -phi, 0.0f, -1.0f, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 14-3 1.0f, phi, 0.0f, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 21-4 1.0f, -phi, 0.0f, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 22-5 -1.0f, phi, 0.0f

58、, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 23-6 -1.0f, -phi, 0.0f, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 24-7 0.0f, 1.0f, phi, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 31-8 0.0f, 1.0f, -phi, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 32-9 0.0f, -1.0f, phi

59、, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 33-10 0.0f, -1.0f, -phi, D3DCOLOR_XRGB(rand()%255,rand()%255,rand()%255) , / 34-11;WORD indices = 0, 4, 8,/00, 5, 10,2, 4, 9,/211,2, 5,1, 6, 8,/410,1, 7,9, 3, 6,/63, 7, 11,10,0, 8,/88, 1, 10,9, 2, 11,/1011,3, 9,2, 4, 0,/120, 5, 2,1, 6, 3,/143, 7,

60、 1,6, 8, 4,/164, 9, 6,5, 10,7,/187, 11,5; /索引序列/创建顶点缓存区,并获取接口IDirect3DVertexBuffer9的指针 m_pDevice-CreateVertexBuffer( sizeof(vertices), /缓存区尺寸 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &m_pVB, NULL ); /把顶点数据填入顶点缓存区 void* pVertices; m_pVB-Lock( 0, sizeof(vertices), (void*)&pVertices, 0 ); memcpy( pVert

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论