Visual C++ 高级编程

41
Visual C++ Visual C++ 高高高高 高高高高 第第第 第第 第第第 第第 3D 3D 第第 第第

description

Visual C++ 高级编程. 第七讲 进入 3D 世界. 什么是 DirectX SDK ?. 微软的 DirectX 软件开发工具包( SDK )提供了一套优秀的应用程序编程接口( APIs ),这个编程接口可以提供给你开发高质量、实时的应用程序所需要的各种资源。 DirectX 技术的出现将极大的有助于发展下一代多媒体应用程序和电脑游戏。. DirectX SDK 的主要组件. DirectDraw :通过直接访问显示硬件来提供高级的图象处理能力。 - PowerPoint PPT Presentation

Transcript of Visual C++ 高级编程

Page 1: Visual C++ 高级编程

Visual C++Visual C++ 高级编程高级编程第七讲 进入第七讲 进入 3D3D 世界世界

Page 2: Visual C++ 高级编程

什么是什么是 DirectX SDK DirectX SDK ? ? • 微软的 DirectX 软件开发工具包( SDK )提供了一套优秀的应用程序编程接口( API

s ),这个编程接口可以提供给你开发高质量、实时的应用程序所需要的各种资源。DirectX 技术的出现将极大的有助于发展下一代多媒体应用程序和电脑游戏。

Page 3: Visual C++ 高级编程

DirectX SDKDirectX SDK 的主要组件 的主要组件 • DirectDraw :通过直接访问显示硬件来提供高级的图象处理能力。 • DirectSound :它提供了软硬件的低延迟声音混频( lo

w_latency sound mixing )和回放( Playback ),硬件加速,以及直接访问音频设备的能力。 • DirectPlay :它明确的提供了通用环境连接能力( gene

ralized communication capabilities ),来简化你应用程序之间的通讯服务。 • Direct3D :它为主流的桌上型计算机和 Internet 用户提供实时的、交互的 3D 技术。 • DirectInput :它简化你的应用程序访问鼠标、键盘和操纵杆设备的能力。

Page 4: Visual C++ 高级编程

DirectXDirectX 的特色的特色• 直接读写内存 DDRAW 可以直接读写显存,并利用“切换页”的功能提高图形显示的性能。• 支持硬件加速 DirectX 对象建立时,程序自动查询可使用的硬件。提供 HAL 和 HEL 两种模式。• 网络联机功能 DirectPlay 可以程序员更容易地开发多人联机游戏。并支持各种通讯协议。

Page 5: Visual C++ 高级编程

COMCOM

• COM 就是 Component Object Model ( 组件对象模型)。• COM 接口和 C++ 的抽象类相似, COM 描述了一套符号和语法而非实现过程。• DX 就提供了一套完整的设计 3D 游戏的库。使用

DX 时,不必直接接触硬件,而由 DX 进行代理。• 使用 COM 时应该注意,必须在程序结束前释放所有的 COM 对象(或接口)。而且,释放它们的顺序应该和创建它们的顺序相反。

Page 6: Visual C++ 高级编程

设置设置 DirectXDirectX 开发环境开发环境• 步骤 1 :安装 DirectX SDK ;• 步骤 2 :设置应用程序中的头文件目录;• 步骤 3 :添加所需的头文件;• 步骤 4 :设置项目链接时所需的库文件,方法有两种:

– 1 、应用程序中使用 #pragma comment(lib,“xxxx.lib”) (推荐)– 2 、在项目设置中添加库文件

Page 7: Visual C++ 高级编程

第一种方法第一种方法

Page 8: Visual C++ 高级编程

第二种方法第二种方法

Page 9: Visual C++ 高级编程

Direct3DDirect3D 的特色的特色WIN32 Application WIN32 Application

Direct3D API

Hal Device

Device Driver Interface(DDI)

Graphics Hardware

GDI

Page 10: Visual C++ 高级编程

硬件抽象层硬件抽象层• Direct3D 通过硬件抽象层 (HAL) 提供设备无关性。 HAL 是一个设备相关的接口,由设备制造商提供, HAL 可以是显示驱动程序的一部分,或者是一个单独的动态链接库。• HAL 通过驱动程序开发人员定义的私有接口与显示驱动程序进行通信。应用程序则通过

Direct3D API 来实现显示。• Direct3D 选择 HAL 设备时,可以充分利用硬件的特性,如硬件加速等。

Page 11: Visual C++ 高级编程

建立建立 3D3D 环境环境• 一个标准的 3D 框架可以分为以下几个部分:

– 创建 Direct3D 接口和设备接口。– WinMain : Win32 程序的入口点,代码会从这里开始执行。这是我们注册、创建、显示窗口的地方。然后,我们要初始化 Direct3D 并进入游戏循环( Game Loo

p )。– WinProc :这是应用程序的消息处理过程。 Windows发给我们的程序的消息,都要有它处理。– InitD3D :这个函数是用来初始化 Direct3D 的。首先,创建 IDirect3D9 对象,通过这个对象我们得到了当前屏幕的显示模式。然后,根据刚刚我们获取的信息(显示模式),创建了兼容的设备。

Page 12: Visual C++ 高级编程

建立建立 3D3D 环境环境– Render :首先,我们清除了后缓冲区准备作画。然后,调用了 BeginScene 函数来告知 DX 我们要作画了。结束了绘制后我们调用 EndScene 来告知 DX 我们画完了。最后,我们调用了 Present 来完成关键的一步:翻动后缓冲区到前缓冲区(屏幕)。这时,用户就能看到我们画的东西了。– CleanUp :我们在此做清洁工作:释放所有的被创建的对象 。

Page 13: Visual C++ 高级编程

建立建立 3D3D 环境环境导入头文件声明接口指针

#include <d3d9.h>LPDIRECT3D9 g_pD3D=NULL;LPDIRECT3DDEVICE9 g_pd3dDevice=NULL;

注册窗口类

初始化 D3D 设备显示窗口

消息循环

释放所有对象程序结束

创建 DIRECT3D9 对象,获取显示卡的显示模式,然后根据这些信息创建DIRECT3D9 设备。

利用 DIRECT3D9 设备进行场景的绘制。

建立 3D 环境

Page 14: Visual C++ 高级编程

绘制绘制 3D3D 几何图形几何图形• 所有的 3D 图形都是由三角形构成的。 • 顶点:顶点就是 3D空间中的一个点。在 3D空间中,你可以用三个顶点来指定一个三角形。 • 灵活顶点格式:是用来描述顶点属性的一种格式,而这种格式是可以由我们自定义的 。顶点属性一般有: X , Y , Z值,以及颜色和亮度等。• 顶点缓冲:顶点缓冲就是一块用于保存顶点的内存缓冲区。• 颜色:在 DirectX 中,如果我们要指定一种颜色,我们可以用 D3DCOLOR_XRGB宏。

Page 15: Visual C++ 高级编程

绘制绘制 3D3D 几何图形几何图形• 坐标系: 3D 迪卡尔坐标系统

• 背面拣选:这所有的三角形面,面向我们的面将会被渲染出来(可见),否则将不被渲染(不可见,被拣选出来了)。

Page 16: Visual C++ 高级编程

绘制绘制 3D3D 几何图形几何图形• 3D 环境:三个矩阵——世界矩阵 、视图矩阵 、投影矩阵 。• 创建模型:即定义 3D 图形的所有顶点属性。• 设备数据源:当 3D 模型设置好后,我们就可以绑定该顶点缓存区到设备数据源。进

行 3D 图形的渲染。

Page 17: Visual C++ 高级编程

矩阵变换 矩阵变换 矩阵变换的基本公式

缩小或放大

Page 18: Visual C++ 高级编程

矩阵变换的实现矩阵变换的实现D3DXMatrixMultiply(&mat2, & mat1, &mat0); // 矩阵相乘 , mat1* mat0-> mat2D3DXMATRIX *D3DXMatrixTranslation( // 矩阵平移

D3DXMATRIX* pOut, // 输出FLOAT x,FLOAT y, FLOAT z

);D3DXMATRIX *D3DXMatrixRotationX( // 矩阵旋转

D3DXMATRIX* pOut, // 输出FLOAT Angle // 角度 .

);D3DXMATRIX *D3DXMatrixScaling( // 矩阵缩放

D3DXMATRIX* pOut, // 输出FLOAT sx, FLOAT sy, FLOAT sz

);

Device->SetTransform(D3DTS_XXXX, &XXXXX);

Page 19: Visual C++ 高级编程

顶点格式顶点格式• Direct3D让我们可以灵活的构造自己的顶点格式。换句话说,我们可以自己定义顶点的成员。 • 为了创建一个自定义的顶点结构,我们首先要创建一个包含能存放我们选择的顶点数据的结构 .

struct ColorVertex{

float _x, _y, _z; DWORD _color;

};struct NormalTexVertex{

float _x, _y, _z; float _nx, _ny, _nz; float _u, _v;

};

包含了位置和颜色信息

包含了位置法线向量纹理坐标

Page 20: Visual C++ 高级编程

灵活顶点格式(灵活顶点格式( FVFFVF ) ) #define FVF_COLOR (D3DFVF_XYZ | D3DFVF_DIFFUSE)

顶点结构表明它包含位置和颜色属性

#define FVF_NORMAL_TEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)

顶点结构表明它包含了位置,法线向量,纹理坐标的属性

旋转的三角形

Page 21: Visual C++ 高级编程

图元图元• 图元就是设备所支持的原始的类型。它包括:点列、线列、线代、三角形列、三角形带 和 三角扇形。

Triangle Strips( 三角形带 )

Page 22: Visual C++ 高级编程

立方体的绘制立方体的绘制• 三角形带:

• 立方体的分割:

Page 23: Visual C++ 高级编程

3D3D物体的绘制物体的绘制

旋转的三角棱

g_pD3DDevice->BeginScene(); //Rendering our triangleg_pD3DDevice->SetStreamSource(0, g_pVertexBuffer, sizeof(CUSTOMVERTEX));g_pD3DDevice->SetVFV(D3DFVF_CUSTOMVERTEX);g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1); //End the scene

g_pD3DDevice->EndScene();

设置源缓冲区 设置顶点格式 绘制图元

Page 24: Visual C++ 高级编程

索引缓冲 索引缓冲 • 索引缓冲就是内存中的一块用于索引顶点的区域。 • 当渲染场景时, DX 会对每个顶点都进行许多计算,例如灯光、变幻等等,这样,运算量会很大。但是我们总是希望让 DX做最少的运算以增加程序的效率,因此,我们需要把顶点的数目减到最少。

Page 25: Visual C++ 高级编程

索引缓冲例子索引缓冲例子

在上面的例子中,我们只用了 4 个顶点就定义了一个正方形,实际节约了 2 个顶点。

Page 26: Visual C++ 高级编程

索引缓冲的实现索引缓冲的实现LPDIRECT3DINDEXBUFFER9 g_pIB; // 定义WORD indices[]={0,2,1,0,3,2,0,1,3,1,2,3}; // 定义数组g_pd3dDevice->CreateIndexBuffer(sizeof(indices), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &g_pIB, NULL); // 创建索引缓冲void *pIndices;g_pIB->Lock( 0,sizeof(indices),(void**)&pIndices,0);memcpy( pIndices,indices,sizeof(indices) ); // 拷贝索引值g_pIB->Unlock();

g_pd3dDevice->SetIndices(g_pIB); // 设置索引缓冲g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,0,4,0,4); // 输出

Page 27: Visual C++ 高级编程

灯光灯光• 可以模拟出真实世界中一样的光线反射效果,受计算机计算能力的限制,只能有限地进行模拟。

– 环境光( ambient) 的投射– 直射光的投射( DIRECT )– 阴影

• 在 3D 环境里,阴影分为:平面阴影和内插( GOURAUD )阴影• 平面阴影:

– 在每一个表而后第一个顶点上进行颜色与打光的计算。效果较差,但速度很快• 内插阴影:在每个表面上,利用三个顶点的颜色值进行内插计算,这种效果有点像渐变的模式。但计算量较大,速度慢

Page 28: Visual C++ 高级编程

– 2.光的属性:• 光的投射方式:

– 漫射( DIFFUSE )– 反射( SPECULAR )– 环境光( AMBIENT )

• 光的类型– 点光源,无方向– 聚光灯,方向性较强– 指定光,有方向,但没位置,如太阳光等

– 3.光的色彩属性• 扩散( Diffuse Color) :当物体被光照射时,所能反射的光• 环绕( Ambient Color)• 放射 (Emissiv Color)• 反射 (Specular Color)

灯光灯光

Page 29: Visual C++ 高级编程

灯光属性灯光属性• 想要不同的光可以指定不同的属性,不是所有类型的光都拥有下面的这些属性:

– Position (位置)这是在 3D空间中光源的位置,例如( 0, 10, 0 )。

– Direction (方向)这是一个向量(例如( 0, 1, 0 )),表示从光源发射出来的光的方向。– Range (范围)这是光从光源发出后所能到达的最大距离,范围以外的物体将不会接受到此光源的光。 – Attenuation (衰减)在光源到它的范围之间,光会逐渐衰减,这是很正常的。如果想要,你也可以指定让光不衰减,或反而越来越亮。– Diffuse Light (漫反射)光的漫反射颜色。漫射光是分散的,但仍然具有方向,不像环境光没有方向。– Ambient Light (环境光)这是环境光的颜色,它是通用的背景光,它是分散的且没有方向和光源,它充满整个场景。

Page 30: Visual C++ 高级编程

灯光类型灯光类型• Ambient Light (环境光)可以为场景指定通用的环境光,与其它灯光互不影响,用红、绿、蓝三个分量来设置颜色。• Point Light (点光源)它没有方向(因为向全部方向发出),但是有颜色、范围和衰减。例如电灯 . • Directional Light (直射光)直射光具有颜色,没有位置。场景里的所有对象都会从同样的方向接收到同样的光。直射光也没有范围和衰减。例如太阳光 .• Spotlight (聚光灯)它具有位置、方向、范围、发光内径和发光外径属性,光照强度还会随距离而衰减。例如 :手电筒 .

Page 31: Visual C++ 高级编程

设置灯光设置灯光• 打开光照处理: SetRenderState( D3DRS_LIGHTING, TRUE );• 创建灯光:

D3DLIGHT9 light;::ZeroMemory( &light, sizeof(D3DLIGHT9) );light.Type = D3DLIGHT_DIRECTIONAL;//灯光类型light.Diffuse.r = 1.0f;light.Diffuse.g = 1.0f;light.Diffuse.b = 1.0f;light.Direction = D3DXVECTOR3( -1.0f, -1.0f, 0.0f );light.Range = 1000.0f;

Page 32: Visual C++ 高级编程

材质材质• 材质 : 用于描述对象(三角形)的反光性能,使它看起来有没有光泽和带有什么颜色。• 下面是描述材质的一些设置:

– Diffuse Reflection (漫反射)物体的漫反射颜色,能使物体看起来是什么颜色。– Ambient Reflection (环境反射)这也是一个颜色值,用于描述对象反射环境光的数量。你甚至可以指定它根本不反射环境光,这意味着它将不可见,除非接收到其它类型的光。– Specular Reflection and Power (镜面反射与高光强度)镜面反射的值,可以用镜面反射和高光强度设置对象,使它看起来发亮。– Emission (放射)使物体自发光,但不会影响到场景内的其它物体。

Page 33: Visual C++ 高级编程

设置材质设置材质D3DMATERIAL9 mtrl;::ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;

mtrl.Specular.r =mtrl.Emissive.r= 0.0f; mtrl.Specular.g =mtrl.Emissive.g= 0.0f; mtrl.Specular.b =mtrl.Emissive.b= 0.0f; mtrl.Specular.a =mtrl.Emissive.a= 0.0f; 灯光与材质

Page 34: Visual C++ 高级编程

顶点法线 顶点法线 • Direct3D 需要知道顶点法线以便它能够确定灯光照射到物体表面的角度,并且一旦计算了每个顶点的灯光, Direct3D 需要知道每个顶点的表面方向。注意顶点法线不一定和面法线相同。 • 为了描述顶点的顶点法线,我们必须更新原来的顶点结构 .( 如前叙 )

阴影的实现

Page 35: Visual C++ 高级编程

纹理 纹理 • 纹理 :赋于某物体一定的纹理属性

– 多种贴图方式 (参见 :3DMAX 里的材质与贴图演示 )• 纹理的基本概念

– 纹理坐标 : 纹理坐标的作用是在纹理上指定一个点,因为纹理是 2D 的,所以我们仅需要两个值 • U V值 :取值范围 :0-1.0f

– 纹理映射 :把纹理应用到对象上,这个过程就叫做“纹理映射”。在此过程中,纹理坐标会被映射到顶点上,所以,顶点将额外增加两个值: U 和 V 。

Page 36: Visual C++ 高级编程

纹理映射举例纹理映射举例0 = (0, 1) 9 = (0, 0)1 = (0, 0) 10 = (1, 1)2 = (1, 1) 11 = (1, 0)3 = (1, 0) 12 = (0, 1)4 = (0, 1) 13 = (0, 0)5 = (0, 0) 14 = (0, 1)6 = (1, 1) 15 = (0, 0)7 = (1, 0) 16 = (1, 1)8 = (0, 1) 17 = (1, 0)

Page 37: Visual C++ 高级编程

– 最近点取样 :• 过滤的效果不是很真实 ,但它的运算速度最快• 在匹配大小时 , 对材质进行同比放大 ,因此较为粗糙 .但因为速度快 ,因此常准备一些较大型的材质图做为贴图用 .

– 线性过滤• 将与像素点相邻的最近四个像素点之间做加权平均的运算 .• 也有失真 ,但比最近点取样要好

– Mipmap 过滤 :• 采用智能贴图技术 ,离观者近的 , 给高的细节 ,远的 , 则给出较粗的细节 , 这样 , 符合人们的观察习惯 ,又保证了精度• 缺点 : 计算时占用较多的系统资源

– 非线性过滤• 效果最好 ,但也最浪费系统资源

纹理过滤纹理过滤

Page 38: Visual C++ 高级编程

设置纹理设置纹理Struct CUSTOMVERTEX{ FLOAT x, y, z; DWORD colour; FLOAT tu, tv; // 纹理坐标};

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)// 顶点格式

LPDIRECT3DTEXTURE9 m_pTexture;// 定义纹理

D3DXCreateTextureFromFile(g_pd3dDevice, szTextureFilePath, &m_pTexture))

// 加载纹理 , szTextureFilePath 为纹理图片为每个顶点设置纹理坐标

Page 39: Visual C++ 高级编程

模型模型• 1.构成三角形的方法

–基础:任何 3D 模型(含平面模型)都是由三角形这个基本的几何图形来构成。–三角形清单:

• 在使用三角形之前,要先进行顶点的定义。• 特点:一个三角形由三个点决定, N 个三角形则需要 3*N 个顶点。

Page 40: Visual C++ 高级编程

–三角形带:• 对于连成一片的三角形,进行重复使用• 使用一个三角形的后两个顶点与新的顶点构成新的三角形。

–三角形扇:– 以一个顶点为基准,以基他顶点来构成多个三角形。

两个三角形构成一个四边形,但只有 4 个顶点。

Page 41: Visual C++ 高级编程

• 2 加载 .X 文件– 方法:

• 调用 D3D 的 D3DXLoadMeshFromX 函数将 .X 文件中的顶点数据读入到顶点缓冲区。• 加载必要的材质。• D3DXLoadMeshFromX 函数原型

HRESULT WINAPI D3DXLoadMeshFromX(      LPCTSTR pFilename,     DWORD Options,     LPDIRECT3DDEVICE9 pD3DDevice,     LPD3DXBUFFER *ppAdjacency,     LPD3DXBUFFER *ppMaterials,     LPD3DXBUFFER *ppEffectInstances,     DWORD *pNumMaterials,     LPD3DXMESH *ppMesh );

绘制模型文件