direct3D学习笔记

更新时间:2023-03-08 06:29:58 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

一.DirectX:

DirectX SDK(俗称 Direct X 开发工具包)或者DirectX API(应用程序接口),是一套用于开发高性能多媒体程序的应用程序接口;

DirectX Runtime(DirectX 运行时),是一组动态连接库,是运行利用DirectX SDK开发的程序所必需的动态库。

DirectX SDK包括以下几部分:Direct3D(direct3d,directdraw)、DirectInput、DirectSound、Direct3D简称D3D,集成了开发DirectX程序三维图形部分的所有API 函数,是DirectXDirectMusic、DirectPlay、DirectShow、DirectSetup和DirectX Media Object。

最主要的也是最复杂的一个组件。DirectDraw是用来开发二维图形的一个组件,目前两者合并一起成为Direct Graphics,也称Direct3D.

二.Direct3D体系结构

硬件抽象层(HAL):大多数的Direct3D API设计开发的三维图形程序都运行于硬件抽象层(HAL),即充分利用了硬件系统的加速功能,又隐藏了硬件相关的设备特性,即通过Direct3D实现了硬件无关性。它仅仅是与硬件设备相关的代码,对硬件部支持的功能,不提供软件模拟。提供硬件功能的检查,但不进行参数检查,所有工作要Direct3D在调用HAL之前进行。 硬件

硬件模拟层(HEL)可以在软件中模拟某些特性,现在已不使用。 Direct3D有两种运行模式:窗口模式和全屏模式

WIN32应用程序 -> Dirent3D API -> HAL -> 设备驱动程序接口(DDI) -> 图形

Dirent3D系统集成:

三.在创建Dirent3D设备对象时要先创建Dirent3D对象,Dirent3D的实现方式就是通过组件

对象模型和接口实现的,在使用c++和COM开发方式时可以直接访问这些接口和对象。在使用c++编程时,要先得到一个指向Dirent3D接口的指针,从而通过该指针调用Dirent3D对象的功能。

Dirent3D设备对象(渲染设备),在Dirent3D的渲染组件,在程序中为一个COM对象,它封装和存储了渲染状态。此外还执行坐标变换和光照操作。使用前也需要获取该对象的接口指针。

四.Dirent3D程序基本结构:五大部分包括:

1.创建windows窗口 2.初始化Dirent3D 3.消息循环

4.图形渲染

5.退出Dirent3D程序

1.创建windows窗口

WNDCLASSEX wndclass ; //一个窗口类 wndclass.cbSize = sizeof (wndclass);

//WNDCLASSEX 的大小

wndclass.style = CS_HREDRAW | CS_VREDRAW; //从这个窗口类派生的窗口具有的风格 wndclass.lpfnWndProc = CGameEngine_App::WndProc; //窗口处理函数的指针,回调函数

wndclass.cbClsExtra = 0 ; //指定紧跟在窗口类结构后的附加字节数

wndclass.cbWndExtra = 0 ; //指定紧跟在窗口事例后的附加字节数。如果一个应用程序在资源中用CLASS伪指令注册一个对话框类时,则必须把这个成员设成DLGWINDOWEXTRA wndclass.hInstance = hInstane;//本模块的事例句柄 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); MAKEINTRESOURCE(IDI_DGE) ) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);//光标的句柄

wndclass.hbrBackground =(HBRUSH)GetStockObject(BLACK_BRUSH) ; //背景画刷的句柄

wndclass.lpszMenuName = NULL;

//(wndclass.hInstance,

wndclass.lpszClassName = \

wndclass.hIconSm = LoadIcon(NULL,IDI_APPLICATION); //(wndclass.hInstance, MAKEINTRESOURCE(IDI_DGE) ) ;

// Register the class

RegisterClassEx(&wndclass);

// Create a window

HWND hWnd = CreateWindowEx(

0, // Extended style wndclass.lpszClassName, szTitle,

wndStyle, // Window style 0, // Horizontal origin 0, // Vertical origin

nWidth, nHeight,

//GetSystemMetrics(SM_CXSCREEN), // x size

//GetSystemMetrics(SM_CYSCREEN), // y size // Handle of parent // Handle to menu

NULL, NULL,

wndclass.hInstance,//hInstance,// Application instance NULL); // Additional data

2.初始化Dirent3D,包括Dirent3D对象,Dirent3D设备对象以及要渲染的图形对象

//创建Dirent3D对象 IDirect3D9* m_pDirect3D;

m_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); //该函数的参数必须是D3D_SDK_VERSION,只有如此方能保证应用程序使用正确的头文件,如果该函数调用失败,将返回一个NULL指针。

//检查渲染设备是否支持所需要的功能 D3DCAPS9 caps;

//用检测到的显示适配器的特性填充D3DCAPS9 结构 m_pDirect3D->GetDeviceCaps(

D3DADAPTER_DEFAULT, //指定物理显卡的序号

D3DDEVTYPE_HAL, //指定设备类型(例如硬件设备(D3DDEVTYPE_HAL)或软件设备&caps );

//返回已初始化的设备性能结构实例

(D3DDEV_TYPE_REF))

int vp = 0;

//检测硬件是否支持变换和灯光

if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; else

vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

//创建direct3D设备对象

D3DPRESENT_PARAMETERS* m_D3Dpp; //创建Dirent3D设备对象前先对m_D3Dpp进行初始化

ZeroMemory(&m_D3Dpp,sizeof(m_D3Dpp)); //全部置零 m_D3Dpp.BackBufferWidth = m_nWidth;

//后备缓冲的宽度

m_D3Dpp.BackBufferHeight = m_nHeight;//后备缓冲的高度

m_D3Dpp.BackBufferFormat = D3DFMT_A8R8G8B8; //后备缓冲的格式 m_D3Dpp.BackBufferCount = 1; m_D3Dpp.MultiSampleQuality = 0;

//后备缓冲数目

m_D3Dpp.MultiSampleType = D3DMULTISAMPLE_NONE;//全屏抗锯齿类型

//全屏抗锯齿质量等级

//设备窗口句柄

//全屏或窗口

m_D3Dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //m_D3Dpp.hDeviceWindow = m_hWindow; m_D3Dpp.Windowed = m_bWindowed; m_D3Dpp.EnableAutoDepthStencil = true; m_D3Dpp.Flags = 0; //显示器刷新率

m_D3Dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //图像最大刷新速度

//

//激活深度缓冲

m_D3Dpp.AutoDepthStencilFormat = D3DFMT_D24S8; //深度缓冲格式 m_D3Dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;

BackBufferWidth和BackBufferHeight:后备缓冲的宽度和高度。在全屏模式下,这两者

的值必需符合显卡所支持的分辨率。例如(800,600),(640,480)。

BackBufferFormat:后备缓冲的格式。这个参数是一个D3DFORMAT枚举类型,它的值有很多种,例如D3DFMT_R5G6B5、D3DFMT_X8R8G8B8为游戏后备缓冲常用格式,这说明后备缓冲的格式是每个像素16位,其实红色(R)占5位,绿色(G)占6位,蓝色(B)占5位,为什么绿色会多一位呢?据说是因为人的眼睛对绿色比较敏感。DX9只支持16位和32位的后备缓冲格式,24位并不支持。如果对这D3DFORMAT不熟悉的话,可以把它设为D3DFMT_UNKNOWN,这时候它将使用桌面的格式。

BackBufferCount:后备缓冲的数目,范围是从0到3,如果为0,那就当成1来处理。

大多数情况我们只使用一个后备缓冲。使用多个后备缓冲可以使画面很流畅,但是却会造成输入设备响应过慢,还会消耗很多内存。

MultiSampleType 和MultiSampleQuality:前者指的是全屏抗锯齿(多重采样)的类型,后者指的是全屏抗锯齿的质量等级。这两个参数可以使你的渲染场景变得更好看,但是却消耗你很多内存资源,而且,并不是所有的显卡都支持这两者的所设定的功能的。在这里我们分别把它们设为D3DMULTISAMPLE_NONE和0。

可以通过CheckDeviceMultiSampleType 来检测当前装置是否支持某个抗锯齿类型 typedef enum _D3DMULTISAMPLE_TYPE {

D3DMULTISAMPLE_NONE = 0, 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 = 0x7fffffff } D3DMULTISAMPLE_TYPE; // MultiSampleType为以上的枚举值 HRESULT CheckDeviceMultiSampleType(

[in] UINT Adapter,//要查询的显示适配器的序号,D3DADAPTER_DEFAULT始终是主显示适配器

[in] D3DDEVTYPE DeviceType,//顶点处理方式,硬件还是软件? [in] D3DFORMAT SurfaceFormat,// 为后备缓冲格式 [in] BOOL Windowed,// 是否为窗口模式

[in] D3DMULTISAMPLE_TYPE MultiSampleType,

[out]DWORD *pQualityLevels//返回的相对于type的(抗锯齿值)多重采样的最大质量等级 );

SwapEffect:交换缓冲支持的效果类型,指定表面在交换链中是如何被交换的。它是D3DSWAPEFFECT枚举类型,可以设定为以下三者之一:D3DSWAPEFFECT_DISCARD, D3DSWAPEFFECT_FLIP, D3DSWAPEFFECT_COPY。

(1)如果设定为D3DSWAPEFFECT_DISCARD,则后备缓冲区的东西被复制到屏幕上后,后备

缓冲区的东西就没有什么用了,可以丢弃(discard 是否丢弃由显卡决定,但不再等待)了。 (2)如果设定为D3DSWAPEFFECT_FLIP,后备缓冲拷贝到前台缓冲,保持后备缓冲内容不变。当后备缓冲大于1个时使用

(3)设定D3DSWAPEFFECT_COPY的话,后备缓冲拷贝到前台缓冲,保持后备缓冲内容不变。当后备缓冲等于1个时使用

一般我们是把这个参数设为D3DSWAPEFFECT_DISCARD。如果想使用GetBackBuffer 获得后备缓冲内容打印屏幕画面。则不能使用DISCARD.

很怀疑用DISCARD效率会好的说法。在我的8600GT 上_COPY 明显好于DISCARD. discard 做法是再次使用后备缓冲时 new 一个新的缓冲,旧的缓冲内容遗弃,如果还有使用旧的缓冲地方,不会影响新的内容,如使用抗锯齿必须是DISCARD。这样不用等待硬件同步。不过大部分是一次Present操作。用COPY在新机器上面反倒效率好些。毕竟new 一个 1440*900 的后台缓冲也是有消耗的。(对于DISCARD 做法仅仅是猜测。不同显卡可能不同。)

hDeviceWindow:显示设备输出窗口的句柄

Windowed:如果为FALSE,表示要渲染全屏。如果为TRUE,表示要渲染窗口。渲染全屏的时候,BackBufferWidth和BackBufferHeight的值就得符合显示模式中所设定的值。 EnableAutoDepthStencil:如果要使用深度缓冲,则把它设为TRUE。

AutoDepthStencilFormat:如果不使用深度缓冲,那么这个参数将没有用。如果启动了深度缓冲,那么这个参数将为深度缓冲设定缓冲格式。常用值D3DFMT_24S8 (24 深度缓冲,8模板缓冲),D3DFMT_24X8(24 深度缓冲),D3DFMT_16(16深度缓冲)等等。

//深度缓存和模板缓存的象素格式,如 D3DFMT_D24S8 , 24 位表示深度,8位为模板缓存。一般不会用到32位深度:D3DFMT_32

//注意如果设置模板缓冲在Clear() 函数中也要清楚模板缓冲:设置参数 D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL

Flags:通常为0 或D3DPRESENTFLAG_LOCKABLE_BACKBUFFER。不太清楚是用来做什么的,看字面好像是一个能否锁定后备缓冲区的标记。D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL 丢弃模板缓冲区

FullScreen_RefreshRateInHz:显示器的刷新率,单位是HZ,如果设定了一个显示器不支持的刷新率,将会不能创建设备或发出警告信息。为了方便,一般设为D3DPRESENT_RATE_DEFAULT就行了。

PresentationInterval:如果设置为D3DPRENSENT_INTERVAL_DEFAULT,则说明在显示一个渲染画面的时候必要等候显示器刷新完一次屏幕。例如你的显示器刷新率设为80HZ的话,则一秒内你最多可以显示80个渲染画面。另外你也可以设置在显示器刷新一次屏幕的时

间内显示1到4个画面。如果设置为 D3DPRENSENT_INTERVAL_IMMEDIATE,则表示可以以实时的方式来显示渲染画面,虽然这样可以提高帧速(FPS),如果速度过快却会产生图像撕裂的情况,但当游戏完成时,帧速度一般不会过快。 //创建D3D设备接口: HRESULT CreateDevice ( UINT Adapter,

//显卡序列号

//所属窗口句柄

//设备进行3D 运算方式

D3DDEVTYPE DeviceType, //D3D 设备类型 HWND hFocusWindow, DWORD BehaviorFlags, 的指针

IDirect3DDevice9 ** ppReturnedDeviceInterface //返回D3D 设备接口指针的地址 );

第二个参数DeviceType 取值:

D3DDEVTYPE_HAL //硬件抽象层,通过显示硬件来完成图形渲染工作 D3DDEVTYPE_REF //参考光栅器,一般用于测试显卡不支持的D3D 功能 D3DDEVTYPE_SW //用于支持第三方软件 第四个参数BehaviorFlags 取值:

D3DCREATE_SOFTWARE_VERTEXPROCESSING //由D3D 软件进行顶点运算(常用) D3DCREATE_FPU_PRESERVE //激活双精度浮点运算或浮点运算异常检测,设置该项会降低系统性能

D3DCREATE_MULTITHREADED //保证D3D是多线程安全的,设置该项会降低系统性能 D3DCREATE_MIXED_VERTEXPROCESSING //由混合方式进行顶点运算 D3DCREATE_HARDWARE_VERTEXPROCESSING //由D3D硬件进行顶点运算

D3DCREATE_PUREDEVICE //禁用D3D 的Get*()函数,禁止D3D使用虚拟设备模拟顶点运算

//创建顶点缓冲区

HRESULT CreateVertexBuffer( UINT Length,

//顶点缓冲区的大小,按字节数算 //顶点缓冲区属性 //灵活顶点格式

DWORD Usage, DWORD FVF, D3DPOOL Pool,

D3DPRESENT_PARAMETERS *pPresentationParameters, //用于存储D3D 设备相关信息

//顶点缓冲区的内存类型

IDirect3DVertexBuffer9** ppVertexBuffer, );

//顶点缓冲区指针地址

HANDLE* pSharedHandle //保留参数,置为0

*Usage:参数Usage 用于指定顶点缓冲区的属性,其取值可以设为0,或下面任意值的组合。

D3DUSAGE_WRITEONLY //只写属性,不能进行读操作,设置该属性可以提高系统性能 D3DUSAGE_DYNAMIC //指定顶点缓冲区要求使用动态内存 D3DUSAGE_NPATCHES //使用顶点缓冲区绘制N-patches 曲线 D3DUSAGE_POINTS

//指定顶点缓冲区存储原始点

//使用软件进行顶点运算,否则使用硬件计

D3DUSAGE_RTPATCHES //使用顶点缓冲区绘制高阶图元(high-orderprimitive) D3DUSAGE_SOFTWAREPROCESSING 算

*Pool:参数Pool 属于枚举类型D3DPOOL,指定顶点缓冲区资源的内存位置,如下: typedef enum _D3DPOOL {

D3DPOOL_DEFAULT = 0,//默认值,顶点缓冲区尽可能存在于显存中

D3DPOOL_MANAGED = 1, //由D3D的资源管理器自动调度顶点缓冲区内存位置 D3DPOOL_SYSTEMMEM = 2, //顶点缓冲区位于内存中

D3DPOOL_SCRATCH = 3, //定点缓冲区位于计算机临时内存中,只能进行内存加锁拷贝 D3DPOOL_FORCE_DWORD = 0x7fffffff //强制将此ENUM 编译为32 位,无其他意义 } D3DPOOL;

//创建索引缓冲

HRESULT CreateIndexBuffer(

UINT Length, //索引缓冲区大小,按字节数计算 DWORD Usage, //索引缓冲区属性,和顶点缓冲区相同

D3DFORMAT Format, //索引数组的元素格式,可以是16 位或者32 位 D3DPOOL Pool, //索引缓冲区内存位置

IDirect3DIndexBuffer9** ppIndexBuffer, //索引缓冲区指针地址 HANDLE* pSharedHandle //保留参数,设为0 ); //保存顶点 HRESULT Lock(

UINT OffsetToLock, //加锁内存起始地址

UINT SizeToLock, //加锁内存大小 VOID **ppbData, //返回内存指针地址 DWORD Flags );

DWORD Flags:指定了顶点缓冲区的加锁属性,它可以取值为0,或者如下中的任意组合:

D3DLOCK_DISCARD //仅在动态缓冲区下使用,硬件丢弃原缓冲区并创建一个 新的缓冲区

D3DLOCK_NO_DIRTY_UPDATE //在缺省状态下,对缓冲区加锁将会在该区域设置一个Dirty 标志,该属性将不对该区域设置Dirty 标志

D3DLOCK_NOSYSLOCK //在加锁的过程中系统可进行其他操作 D3DLOCK_READONL

//设置缓冲区位只读属性

D3DLOCK_NOOVERWRITE //尽在动态缓冲区下使用,保证不覆盖缓冲区数据,即向缓冲区中添加数据,允许在渲染时添加数据到缓冲区

//加锁属性

3.消息循环

由peekmessage(),translatemessage(),dispatchmessage()三个函数组成,他们是windows标准消息循环处理过程,当应用程序消息队列有一个消息时,peekmessage()返回true,执行translatemessage()进行消息转换,最后由dispatchmessage()传递给窗口过程函数 BOOL PeekMessage(

LPMSG IpMsg, //接收消息信息的MSG结构指针 HWND hWnd,

//其消息被检查的窗口的句柄

UINT wMSGfilterMin, //指定被检查的消息范围里的第一个消息 UINT wMsgFilterMax, //指定被检查的消息范围里的最后一个消息 UINT wRemoveMsg );

wRemoveMsg可取下列值之一:

PM_NOREMOVE:PeekMessage处理后,消息不从队列里除掉。 PM_REMOVE:PeekMessage处理后,消息从队列里除掉。

可将PM_NOYIELD随意组合到PM_NOREMOVE或PM_REMOVE。此标志使系统不释放等待调用程序空闲的线程。

缺省地,处理所有类型的消息。若只处理某些消息,指定一个或多个下列值: PM_QS_INPUT:Windows NT5.0和Windows 98:处理鼠标和键盘消息。

//确定消息如何被处理

PM_QS_PAINT:Windows NT 5.0和Windows 98:处理画图消息。

PM_QS_POSTMESSAGE:Windows NT 5.0和Windows 98:处理所有被寄送的消息,包括计时器和热键。

PM_QS_SENDMESSAGE:Windows NT 5.0和Windows 98:处理所有发送消息。 返回值:如果消息可得到,返回非零值;如果没有消息可得到,返回值是零

4.图形渲染

所有的渲染操作都必须在BeginScene()和EndScene()之间执行,最后Present()将后台缓冲区内容提交到前台缓冲区,大多数的三维程序都拥有两个或者两个以上的颜色缓冲区,用于当前屏幕刷新的为前台缓冲区,其他的用于图形绘制的颜色缓冲区成为后台缓冲区. HRESULT IDirect3DDevice9::Clear( DWORD Count, DWORD Flags, float z, );

Clear作用是:清空一个或者多个表面的内容,direct3d在绘制图形之前要调用它清除视口的颜色缓冲区、深度缓冲区、模版缓冲区中的一个或者多个。

//设置渲染状态

HRESULT SetRenderState(

D3DRENDERSTATETYPE State, //需要渲染的状态 DWORD Value );

改变D3D中的渲染状态(部分) 1). 设置着色模式:

SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT) //设置平面着色模式 SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD) //设置格劳德着色模式 2). 设置多边形填充模式:

SetRenderState(D3DRS_FILLMODE, D3DFILL_POINT) //点填充模式,D3D在多边形的每个顶点绘制一个像素

SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME) //线填充模式,D3D在多边形

//设置的渲染状态的值

//重置的矩形区域数量

//重置缓冲区标志,//指定重置的缓冲区 //颜色值 //模板

const D3DRECT* pRects, //重置的矩形区域//数组指针 D3DCOLOR Color, DWORD stencil

//深度值,最远为1.0f最近为0

的每个边绘制一条线

SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID) //面模式,D3D默认模式,对多边形的面进行填充

3). 设置全景图形抗锯齿:

SetRenderState(D3DRS_MUTISAMPLEANTIALIAS, TRUE) //抗锯齿 SetRenderState(D3DRS_MUTISAMPLEANTIALIAS, FALSE) //不抗锯齿 4). 设置剔除模式:

SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE) //不剔除任何面,默认为剔除背面 5). 设置光照模式:

SetRenderState(D3DRS_AMBIENT, D3DCOLOR ambientColor); //为整个场景设置环境光,ambientColor默认值为0

SetRenderState(D3DRS_SPECULARENABLE, TRUE); //激活镜面反射计算(D3D默认情况下关闭)

6). 启动/关闭深度测试:

SetRenderState( D3DRS_ZENABLE, TRUE ); //启用深度测试 7) 设置纹理过滤器 8)

SetRenderState( D3DRS_POINTSCALEENABLE, TRUE ); //打开缩放功能 9)

SetRenderState( D3DRS_POINTSCALE_A , FtoDW( 1.00f ));//设置因子,下同 SetRenderState( D3DRS_POINTSCALE_B , FtoDW( 1.00F )); SetRenderState( D3DRS_POINTSCALE_C , FtoDW( 1.00f )); 10)

SetRenderState( D3DRS_POINTSIZE_MAX, FtoDW( 5.00f ));//设置点大小上限,下类似 SetRenderState( D3DRS_POINTSIZE_MAX, FtoDW( 5.00f ));

SetRenderState( D3DRS_POINTSPRITEENABLE , TRUE ) ; //打开点精灵效果 SetRenderState( D3DRS_AMBIENT, 0xffffffff ); //设置环境光颜色开启 ALPHA混合效果 11)

设置混合因子:

源:SetRenderState( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA ); 目的:SetRenderState( D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA); 第二个参数是 D3DBLEND的枚举结构。 typedef enum D3DBLEND

{

D3DBLEND_ZERO = 1, D3DBLEND_ONE = 2, D3DBLEND_SRCCOLOR = 3, D3DBLEND_INVSRCCOLOR = 4, D3DBLEND_SRCALPHA = 5, D3DBLEND_INVSRCALPHA = 6, D3DBLEND_DESTALPHA = 7, D3DBLEND_INVDESTALPHA = 8, D3DBLEND_DESTCOLOR = 9, D3DBLEND_INVDESTCOLOR = 10, D3DBLEND_SRCALPHASAT = 11, D3DBLEND_BOTHSRCALPHA = 12, D3DBLEND_BOTHINVSRCALPHA = 13, D3DBLEND_BLENDFACTOR = 14, D3DBLEND_INVBLENDFACTOR = 15, D3DBLEND_SRCCOLOR2 = 16, D3DBLEND_INVSRCCOLOR2 = 17, D3DBLEND_FORCE_DWORD = 0x7fffffff, } D3DBLEND, *LPD3DBLEND;

Source和Destination的默认方式分别为D3DBLEND_SRCALPHA和 D3DBLEND_INVSRCALPHA。

5.坐标变换

1)世界变换

我们在建立三维实体的数学模型时,通常以实体的某一点为坐标原点,比如一个球体,很自然就用球心做原点,这样构成的坐标系称为本地坐标系(Local Coordinates)。实体总是位于某个场景(World Space)中,而场景采用世界坐标系(World Coordinates),如图8所示,因此需要把实体的本地坐标变换成世界坐标,这个变换被称为世界变换(World Transformation)。

在Direct3D中,坐标变换通过一个4x4矩阵来实现,对于世界变换,只要给出实体在场景中的位置信息,就可以借助Direct3D函数得到变换矩阵,具体的计算步骤如下: ", 首先把实体放置在在世界坐标系原点,使两个坐标系重合;

", 在世界空间中,对实体进行平行移动,其对应的平移变换阵TT可由函数D3DXMatrixTranslation求得;

", 把平移后的实体沿自身的Z轴旋转一个角度(角度大于0,表示从Z轴的正向朝原点看去,旋转方向为顺时针;反之为逆时针,下同),对应的旋转变换阵TZ用D3DXMatrixRotationZ计算;

", 把实体沿自身的Y轴旋转一个角度,用D3DXMatrixRotationY求出变换阵TY; ", 把实体沿自身的X轴旋转一个角度,用D3DXMatrixRotationX求出变换阵TX;

", 最后对实体进行缩放,假设三个轴的缩放系数分别为sx、sy、sz,该操作对应的变换阵TS可由函数D3DXMatrixScaling求得;

", 最终的世界变换矩阵TW = TS·TX·TY·TZ·TT ,在Direct3D中,矩阵乘法用函数D3DXMatrixMultiply实现,注意相乘顺序为操作的逆序。

从以上描述中,我们很容易得出:实体的运动可以通过不断改变世界变换矩阵来实现。

2)视角变换,(观察矩阵)

实体确定后,接下来要确定观察者在世界坐标系中的方位,换句话说,就是在世界坐标系中如何放置摄像机。观察者(摄像机)所看到的景象,就是Direct3D窗口显示的内容。 确定观察者需要三个量: ", 观察者的点坐标;

", 视线方向,为一个矢量,不过Direct3D用视线上的一个点来替代,此时视线方向就是从观察者指向该目标点,这样表示更直观一些;

", 上方向,通俗地说,就是观察者的头顶方向,用一个矢量表示。

确定后,以观察者为原点,视线为Z轴,上方向或它的一个分量为Y轴(X轴可由左手法则得

出,为右方向),构成了视角坐标系,如图9所示。我们需要把实体从世界空间转换到视角空间,这个坐标变换被称为视角变换(View Transformation)

与世界变换相比,视角变换矩阵的获取要容易得多,只需调用一个函数D3DXMatrixLookAtLH,其输入参数就是决定观察者的那三个量。 D3DXMATRIX *WINAPI D3DXMatrixLookAtLH( D3DXMATRIX *pOut,

CONST D3DXVECTOR3 *pEye, CONST D3DXVECTOR3 *pAt, CONST D3DXVECTOR3 *pUp );

这个函数用来控制摄影机,用来控制视图矩阵的。 pEye眼睛的位置,观察的方向。

pAt是摄影机的前进和后退,向左或向右。向上或向下。 pUp是向上的方向。 详细说明 参数: pOut

[in, out] 指向 D3DXMATRIX 结构的返回结果的矩阵。 pEye

[in] 指向D3DXVECTOR3 结构的眼睛所有在位置向量。这个值会用来作平移。 pAt

[in] 指向 D3DXVECTOR3 结构的摄像机观察目标位置向量。 pUp

[in] 指向D3DXVECTOR3 结构的当前世界坐标系向上方向向量。通常用[0, 1, 0]向量。

3)投影变换

实体转换到视角空间后,还要经过投影变换(Projection Transformation),三维的实体才能显示在二维的计算机屏幕上。打个比方,如果把屏幕看做照相机中的胶卷,那么投影变换就相当于照相机的镜头。

Direct3D使用透视投影变换(Perspective Transformation),此时在视角空间中,可视区域是一个以视线为轴心的棱台(Viewing Frustum),如图10所示。想象一下你处在一个伸手不见五指的房间里,面前有一扇窗户,你可以透过窗户看到各种景物。窗户就是棱台的前裁剪平面,天空、远山等背景是后裁剪平面,其间的可视范围是景深。投影变换把位于可视棱台内的景物投影到前裁剪平面,由于采用透视投影,距离观察者远的对象会变小,从而更具有真实感。在Direct3D中,前裁剪平面被映射到程序窗口,最终形成了我们在屏幕上看到的画面。

透视投影变换由四个量决定: ", 前裁剪平面的宽度w; ", 前裁剪平面的高度h; ", 前裁剪平面到原点的距离z1; ", 后裁剪平面到原点的距离z2。

由于w、h用起来不是很直观,因此实际应用中,常用fov和aspect代替w、h,其中fov是Y方向上的可视角度,通常取π/4;aspect是前裁剪平面的高度与宽度之比,通常取1(由三角函数定义,易知h=2·z1·tg(fov/2),w=h/aspect)。用这四个量来调用函数D3DXMatrixPerspectiveFovLH,即可获得投影变换矩阵。

得到三个变换矩阵后,还需要调用方法IDirect3DDevice9::SetTransform把它们设置到渲染环境中,具体用法参见后面的例程。

//得到左手坐标系透视投影变换矩阵 D3DXMatrixPerspectiveFovLH( &matrixProj,

//[in,out] 指向D3DXMATRIX 结构的操作结果矩阵 //[in]观察时y 轴方向的角度(弧度),就是观察范围夹角

D3DX_PI/2.0f,

float(m_nWidth)/float(m_nHeight),//in]纵横比,在视空间宽度除以高度 );

最后,可以用三句话来概括这些变换的作用:世界变换决定实体的位置;视角变换决定

1.0f,

//[in]近裁剪面位置Z值 //[in]远裁剪面位置Z值

10000.0f

观察者的位置;投影变换决定观察者的可视区域。

图形绘制

//*设置资源流

HRESULT SetStreamSource( UINT StreamNumber, //渲染数据流序号

IDirect3DVertexBuffer9 *pStreamData, //进行绑定的顶点缓冲区指针 UINT OffsetInBytes, //进行绑定连接的渲染数据流的起始位置 的起始位置

UINT Stride //渲染数据流中一个顶点所占的内存的大小 );

//*设置顶点格式 HRESULT SetFVF( DWORD FVF //灵活顶点格式 );

D3D 定义的FVF 格式:

D3DFVF_XYZ //包含未经变换的顶点坐标 D3DFVF_XYZRHW //包含经过变换的顶点坐标 D3DFVF_XYZW //包含经过变换和裁剪的顶点坐标 D3DFVF_NORMAL //包含法线信息 D3DFVF_PSIZE //点精灵的大小

D3DFVF_DIFFUSE //包含漫反射的颜色信息 D3DFVF_SPECULAR //包含镜面反射的颜色信息

D3DFVF_TEX0……D3DFVF_TEX8 //包含0-8 个纹理坐标信息

D3DFVF_XYZB1……D3DFVF_XYZB5 //包含顶点位置信息和影响顶点变换的权重信息,用于骨骼动画模型中 //*绘制基本图元

HRESULT DrawPrimitive(

D3DPRIMITIVETYPE PrimitiveType, //绘制的图元类型 UINT StartVertex, //绘制的起始顶点 UINT PrimitiveCount //绘制的图元数量 );

//第一个参数PrimitiveType 取值:

D3DPT_POINTLIST //点列集合(一组点的集合) D3DPT_LINELIST //线列集合(一组线段的集合) D3DPT_LINESTRIP //线带集合(首尾相连的线段的集合) D3DPT_TRIANGLELIST //三角形列(一组三角形的集合)

D3DPT_TRIANGLESTRIP //三角形带(首尾相连的三角形,有两个顶点重合) D3DPT_TRIANGLEFAN //三角形扇(组成扇形的一组三角形) //图形绘制

HRESULT SetIndices(

IDirect3DIndexBuffer9 *pIndexData //使用的索引缓冲区指针 );

HRESULT DrawIndexedPrimitive(

D3DPRIMITIVETYPE Type, //基本图元类型

INT BaseVertexIndex, //顶点缓冲区的起始位置 UINT MinIndex, //相对于BaseVertexIndex 的最小索引 UINT NumVertices, //绘制的顶点数目,第一个顶点的位置 UINT StartIndex, //索引缓冲区的起始位置 UINT PrimitiveCount //绘制的基本图元数量 );

HRESULT IDirect3DDevice::Present ( CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST* pDirtyRegion

//复制源的矩形区域指针 //复制目标的矩形区域指针 //Direct3D设备所属窗口句柄 //最小更新区域指针

);

纹理

//从磁盘文件获取纹理 //该函数支持的图形文件类型: bmp、dds、dib、jpg、png 以及tga 等

HRESULT WINAPI D3DXCreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, //Direct3D 设备指针 LPCTSTR SrcFile, );

//设置当前要渲染的纹理

//纹理图形文件

LPDIRECT3DTEXTURE9 *ppTexture //存储Direct3D 纹理的指针地址

HRESULT SetTexture(

DWORD Stage, //多级纹理的索引,从0-7,单层纹理取0 IDirect3DBaseTexture9 *pTexture //Direct3D 的纹理接口指针 );

//设置纹理的渲染状态

HRESULT SetTextureStageState(

DWORD Stage, //当前设置的多级纹理的索引

D3DTEXTURESTAGESTATETYPE Type, //纹理渲染状态的类型 DWORD Value //纹理渲染状态的值,与类型相对应 );

//第二个参数D3DTEXTURESTAGESTATETYPE Type 取值: typedef enum _D3DTEXTURESTAGESTATETYPE {

D3DTSS_COLOROP = 1, //纹理层的颜色混合方式,即运算方式 D3DTSS_COLORARG1 = 2, //颜色混合的第一个参数 D3DTSS_COLORARG2 = 3, //颜色混合的第二个参数 D3DTSS_ALPHAOP = 4, //指定纹理层的Alpha 透明 D3DTSS_ALPHAARG1 = 5, //Alpha 混合的第一个参数 D3DTSS_ALPHAARG2 = 6, //Alpha 混合的第二个参数 D3DTSS_BUMPENVMAT00 = 7, //绘制凹凸纹理时 D3DTSS_BUMPENVMAT01 = 8, //绘制凹凸纹理时 D3DTSS_BUMPENVMAT10 = 9, //绘制凹凸纹理时

D3DTSS_BUMPENVMAT11 = 10, //绘制凹凸纹理时

D3DTSS_TEXCOORDINDEX = 11, //该纹理层使用的纹理坐标的索引 D3DTSS_BUMPENVLSCALE = 22, //绘制凹凸纹理的缩放参数 D3DTSS_BUMPENVLOFFSET = 23, //绘制凹凸纹理的平移参数

D3DTSS_TEXTURETRANSFORMFLAGS = 24, //控制纹理坐标的转换标志 D3DTSS_COLORARG0 = 26, //指定混合过程的第三个颜色 D3DTSS_ALPHAARG0 = 27, //Alpha 混合的第三个参数 D3DTSS_RESULTARG = 28, //颜色混合的结果输出寄存器 D3DTSS_CONSTANT = 32, //颜色混合的常量寄存器

D3DTSS_FORCE_DWORD = 0x7fffffff //强制转换为32 位,用于占位 } D3DTEXTURESTAGESTATETYPE; //设置纹理采样属性

HRESULT SetSamplerState(

DWORD Sampler, //指定纹理采样属性的纹理层ID(0~7) D3DSAMPLERSTATETYPE Type, //纹理过滤类型 DWORD Value //设置纹理采样属性值 );

第二个参数D3DSAMPLERSTATETYPE Type 取值: D3DSAMP_MAGFILTER //处理放大过滤 D3DSAMP_MINFILTER //处理缩小过滤 D3DSAMP_MIPFILTER //多纹理过滤

D3DSAMP_MIPMAPLODBIAS //多级纹理级数偏移值,初始值为0 D3DSAMP_MAXMIPLEVEL //最大多纹理级别,初始值为0 D3DSAMP_MAXANISOTROPY //各向异性,初始为1 第三个参数Value 取值:

D3DTEXF_NONE //不使用特殊的采样方式 D3DTEXF_POINT //最近点采样 D3DTEXF_LINEAR //线性纹理采样

D3DTEXF_ANISOTROPIC //各向异性纹理采样

最近点采样

最近点采样是4种过滤方式中速度最快但效果最差的过滤方式。Direct3D计算得到的纹理元素地址通常是一个浮点数值,而非整数的纹理下标值,当使用最近点采样时,Direct3D会复制与这个浮点值地址最接近的整数地址的纹理元素的颜色。

设置最近点采样的具体方法如下:调用IDirect3DDevice9::SetSamplerState(),可分别

设置纹理过滤的放大过滤器和缩小过滤器。将第一个参数设置为纹理过滤器关联的纹理层序号(0~7)。如果要设置放大过滤器,第二个参数设为D3DSAMP_MAGFILTER,如果要设置缩小过滤器,第二个参数设为D3DSAMP_MINFILTER。第三个参数可设为表示最近点采样的枚举常量D3DTEXF_POINT。下列代码将纹理层0的纹理过滤方式设置为最近点采样。 g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);

如果纹理的大小和屏幕图元的实际大小将近,那么采用最近点采样方法对图像质量的影响不大。但是,如果大小相差太多,就会降低图像精度,从而影响图像质量,出现色块或闪烁的失真现象。

线性纹理过滤

线性纹理过滤是目前使用最广泛的纹理过滤方法。它与最近点采样相比,能有效地提高图像的显示质量,并且对系统性能影响不大。线性纹理过滤取得与计算得到的纹理元素的浮点地址最接近的上、下、左、右4个纹理元素,对这4个纹理元素进行加权平均,得到最终显示的颜色值。

与设置最近点采样的方法相似,调用函数IDirect3DDevice9::SetSamplerState()设置线性纹理过滤,所不同的是第三个参数设置为D3DTEXF_LINEAR。

下面的代码将纹理层0的放大和缩小过滤器设置为线性纹理过滤。 g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

因为是在单一纹理层上的线性过滤,而且是x、y方向上的线性过滤,所以称为双线性纹理过滤。目前大多数显卡都为线性纹理过滤进行了优化,所以使用线性纹理过滤一方面可以获得较好的图形质量,另一方面对程序性能影响不大。

各项异性纹理过滤

当三维物体表面与投影平面不平行时,它在屏幕上的投影会有拉长或扭曲,这种现象称为各项异性(anisotropy)。当一个各向异性图元的像素映射到纹理元素时,它的形状发生扭曲。Direct3D根据屏幕像素反向转换到纹理元素的延长度,决定各项异性程度。

要使用各项异性纹理过滤,还应当设置最大各项异性程度值。通过将函数IDirect3DDevive9::SetSamplerState()的第一个参数设为纹理层索引,第二个参数设为D3DSAMP_MAXANISOTOPY,第三个参数设为大于1的任何值,可以完成最大各项异性程

度值的设置。

下面的示例代码指定了最大各项异性值为4。

g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); g_device->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 4);

最大各项异性程度值D3DSAMP_MAXANISOTROPY为1时,表示禁用各项异性过滤。一般说来,其值越大,图像效果越好,计算量越大,速度越慢。需要注意的是,在设置最大各项异性之前,应调用IDirect3D9::GetDeviceCaps()函数,查询当前设备支持的Direct3D特性,获取当前设备支持的最大各项异性度的取值范围 //线性纹理

SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); //最近点采样

SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ POINT); SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); //各向异性纹理过滤

SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC );

SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ ANISOTROPIC);

5.退出Dirent3D程序,清除所有初始化时创建的COM对象

调用Release()使引用计数器减一;最后计数器为零时才调用delete();

五.三种顶点数据处理

D3DCREATE_HARDWARE_VERTEXPROCESSING D3DCREATE_SOFTWARE_VERTEXPROCESSING D3DCREATE_MIXED_VERTEXPROCESSING

一次只能给设备指定一种处理方式,软件顶点处理提供一种确保支持的顶点处理能力,包括无限制的光源数量和可编程的顶点渲染器的完全支持。在使用HAL设备时,在任一时刻都可以在软件和硬件顶点处理之间进行切换,HAL是一种同时支持软件、硬件顶点处理的设备类型,对软件顶点处理的唯一要求就是顶点缓冲区必须位于系统内存

//只指定给硬件设备 //处理能力固定 //软硬件切换使用

六.Direct3d表面

表面代表显示内存中的一块线性区域,尽管可以位于系统内存,但通常是位于显卡的显存

中。

前台缓冲区:是由显卡传送到显示器用于显示器显示的一块内存,程序不能对其进行任何

操作。

后台缓冲区:在程序中可以直接操作的一块内存区域,不能用于图形显示。 表面反转:将后台缓冲区的内容提交到前台缓冲区进行显示的过程。

交换链:一个或者多个后台缓冲区的集合,可以按照顺序逐个提交到前台缓冲区。

七.Direct3D坐标系和基本图元

1.三维笛卡尔坐标系根据z轴相对于x、y的方向又分为左手坐标系跟右手坐标系。在空间几何中常用右手坐标系,而在Direct3D中用的是左手坐标系。 2.使用顶点缓冲区绘制图形

顶点缓冲区是用来保存顶点数据的内存缓冲区,可以保存任意类型的顶点数据,并可以进行坐标变换,光照处理以及裁剪等操作。根据图形显示的需要,顶点缓冲区的顶点可以包含顶点坐标、颜色、法线向量、纹理坐标等属性,这些属性可以用灵活顶点格式FVF来描述。使用SetFVF()来声明当前实用的灵活顶点格式。灵活顶点格式使应用程序只使用它需要的顶点数据,这样可以节省系统内存空间,较小系统带宽。

3.使用索引缓冲区进行绘制

将所有的顶点数据存放在顶点缓冲区,在索引缓冲区建立索引,避免了重复,最后通过索引缓冲区跟顶点缓冲区共同绘制图形。

创建完顶点缓冲区跟索引缓冲区后,要将索引数据复制到索引缓冲区,这时需要Lock()和Unlock(),即在操作前锁定索引缓冲区,复制完后解锁。

4.渲染状态

设备渲染状态控制direct3d设备的光栅化组件的行为,通过改变渲染状态属性可以控制使用

何种着色模式,如何进行雾化及其他光栅化操作。Direct3d调用SetRenderState()来设置渲染状态。

着色模式:1. 平面着色模式;2. 戈劳德着色模式。一次只能使用一种着色模式,默认为戈劳德着色模式。

矩阵操作

//向量规格化

D3DXVECTOR3 *WINAPI D3DXVec3Normalize( D3DXVECTOR3 *pOut, //输出单位向量

CONST D3DXVECTOR3 *pV //输入的向量 ); //单位矩阵

D3DXMATRIX *D3DXMatrixIdentity(

D3DXMATRIX *pOut ); //矩阵转置

D3DXMATRIX *WINAPI D3DXMatrixTranspose(

D3DXMATRIX *pOut, CONST D3DXMATRIX *pM ); //逆矩阵

D3DXMATRIX *WINAPI D3DXMatrixInverse(

D3DXMATRIX *pOut,

FLOAT *pDeterminant, //通常忽略第二个参数都设置为0 CONST D3DXMATRIX *pM );

//设置变换矩阵

HRESULT SetTransform(

D3DTRANSFORMSTATETYPE State, //变换类型 CONST D3DMATRIX* pMatrix //变换矩阵 );

参数State 可以是一下任意类型: D3DTS_WORLD //世界变换 D3DTS_VIEW //视图变换 D3DTS_PROJECTION //投影变换 //*平移变换

D3DXMATRIX *WINAPI D3DXMatrixTranslation(

D3DXMATRIX *pOut, //输出矩阵 FLOAT x, //X 轴上的平移量 FLOAT y, //Y 轴上的平移量 FLOAT z //Z 轴上的平移量 ); //旋转变换

D3DXMATRIX *WINAPI D3DXMatrixRotationX( //绕X 轴旋转

D3DXMATRIX *pOut, //输出矩阵 FLOAT Angle //旋转角度 );

D3DXMATRIX *WINAPI D3DXMatrixRotationY( //绕Y 轴旋转

D3DXMATRIX *pOut, //输出矩阵 FLOAT Angle //旋转角度 );

D3DXMATRIX *WINAPI D3DXMatrixRotationZ( //绕Z 轴旋转 D3DXMATRIX *pOut, //输出矩阵

FLOAT Angle //旋转角度 );

D3DXMATRIX *WINAPI D3DXMatrixRotationAxis( //绕任意轴旋转

D3DXMATRIX *pOut, //输出矩阵

CONST D3DXVECTOR3 *Pv //旋转中心轴向量 FLOAT Angle //旋转角度 );

//*缩放变换

D3DXMATRIX *WINAPI D3DXMatrixScaling(

D3DXMATRIX *pOut, //输出矩阵 FLOAT sx, //X 轴上的缩放量 FLOAT sy, //Y 轴上的缩放量 FLOAT sz //Z 轴上的缩放量 );

//*组合变换,两个矩阵相乘

D3DXMATRIX *WINAPI D3DXMatrixMultiply(

D3DXMATRIX *pOut,

//输出变换矩阵

//输入矩阵

CONST D3DXMATRIX *pM1, //输入矩阵 CONST D3DXMATRIX *pM2 );

//计算两个3-D向量叉乘。向量的外积或者向量积,用右手法则判断,拇指指向结果向量 //通过前进向量和斜坡的法线向量做差乘,计算出右方向的向量,再由右方向和斜坡//法线做差成得出需要的平行斜面向上的向量

D3DXVECTOR3 *D3DXVec3Cross(

D3DXVECTOR3 *pOut, CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ); 参数: pOut

[in, out] 指向 D3DXVECTOR3 结构的操作结果。 pV1

[in] 指向 D3DXVECTOR3 结构的源向量。 pV2

[in] 指向 D3DXVECTOR3 结构的源向量。 返回值:

指向D3DXVECTOR3 结构的两个向量叉乘结果。

这个函数返回两个向量叉乘结果。 例子说明如下: D3DXVECTOR3 v;

v.x = pV1->y * pV2->z - pV1->z * pV2->y; v.y = pV1->z * pV2->x - pV1->x * pV2->z; v.z = pV1->x * pV2->y - pV1->y * pV2->x; *pOut = v;

//向量的点乘,求得向量的夹角余弦值,又称内积

FLOAT D3DXVec3Dot( CONST D3DXVECTOR3 *pV1, CONST D3DXVECTOR3 *pV2 ); 参数: pV1

[in] 指向 D3DXVECTOR3 结构的源向量。 pV2

[in] 指向 D3DXVECTOR3 结构的源向量。 返回值:

两个3D向量的点乘。

D3DXVec3TransformNormal(

&m_look, &m_look, &matrix);

//pOUT //pV //pM

//用矩阵pM变换向量pV标准形式(x, y, z, 0),不是齐次坐标形式

//如果一个非仿射矩阵变换,那么这个矩阵要作逆运算后再转置才传给本函数 //函数返回值跟pOut 参数返回值是一样的。

D3DXVec3TransformNormal() 与 3DXVec3TransformCoord() 的区别?????

DirectX中有两个很相似的函数,输入与输出的参数格式完全一样,都是输入一个三维向量(D3DXVECTOR3)和一个矩阵(D3DXMATRIX),输出变换之后的向量(D3DXVECTOR3)。

两者的区别在于开始把三维向量转换成四维向量时,第四维分量的取值。

0。

D3DXVec3TransformNormal( ) 用于矢量的变换,第四维分量为D3DXVec3TransformCoord( ) 用于坐标的变换,第四维分量为1。

函数内部的工作机制也很类似,都是把三维向量扩充成四维向量,然后和矩阵相乘,得到变换之后的四维向量,再把四维向量转换成三维向量输出。

为什么要有这样的区别呢?

在三维坐标系中,虽然矢量和坐标都用(x,y,z)表示,但是坐标仅表示点在坐标系中的位置,没有方向和长度。三维变换中,坐标点可以平移。由于我们使用向量与矩阵的乘法来计算三维变换,而变换矩阵是4x4的矩阵,只能和四维行向量相乘,因此需要扩充第四维分量来实现三维变换的乘法计算,把第四维分量设置成1,可以保证平移变换的实现。

矢量表示的是一段有方向和长度的有向线段,两个坐标点之间的矢量可以用终点坐标减起点坐标来计算。在三维的表示方法中,两个三维向量相减,结果还是三维向量,即(Ax,Ay,Az)-(Bx,By,Bz)=(X,Y,Z)。如果扩充到四维表示,把坐标点的第四维分量设置成1,那么用减法计算矢量时,得到的四维向量的前三维分量和三维计算一致,但第四维等于0,即(Ax,Ay,Az,1)-(Bx,By,Bz,1)=(X,Y,Z,0)。矢量(x,y,z)一般表示成从原点(0,0,0)到坐标点(x,y,z)的有向线段,但是它可以任意的坐标点作为起点或终点,只要方向和长度保持一致。因此矢量没有特定的位置。四维表示时,由于第四维等于0,因此,矢量也就不可以实现平移变换。当然,没有位置本来也就不需要平移了。

但是矢量变换与坐标变换还是有关系的。可以验证一下,在对矢量进行三维变换时,可以先假设一个矢量的起点为原点(0,0,0),终点是(x,y,z),变换时先使用D3DXVec3TransformCoord( ) 变换起点,再使用D3DXVec3TransformCoord( ) 变换终点,然后再把变换后的终点与起点相减得到转换后的矢量值,这个减法一方面是计算矢量的值,另一方面也相当于忽略了平移变换,因为原点只会发生平移变换。因此,矢量变换的结果与原矢量终点坐标(x,y,z)变换之后的值是完全不一样的。

所以,通过第四维的0,忽略平移变换,是矢量变换与坐标变换的根本区别。

本文来源:https://www.bwwdw.com/article/6he.html

Top