对3D编程期待已久,却一直叶公好龙浅尝辄止。近期在公司实习却无具体的工作安排,琢磨着学习个新的手艺,就又想起了3D Programming。这次从大名鼎鼎的龙书(Introduction to 3D Game Progamming with Directx 9.0)开始学起,坚持...

作为入门的第一篇笔记,本文对D3D初始化过程做了总结。DirectX3D的初始化需要做两部分工作:创建一个窗口、创建IDirect3DDevice9对象,窗口用于展示D3D渲染出来的场景;IDirect3DDevice9则是一个C++对象,表示用来displaying3D图形的物理设备。本文也主要包含两个部分:

  1. D3D的初始化
  2. 龙书中使用简单框架的代码分析

1.D3D的初始化

龙书中将一个D3D的初始化过程分为4个步骤:

  1. 获取IDirect3D9接口的指针,该接口通常用于取得物理设备信息和创建IDirect3DDevice9对象。
  2. 检测设备的处理能力(D3DCAPS9),检测显示适配器(display adapter)是否支持顶点的硬件处理。
  3. 初始化结构体D3DPRESENT_PARAMETERS,该结构指定了一些参数用来创建IDirect3DDevice9。
  4. 创建IDeirect3DDevice9对象。

1.1取得IDirect3D9指针

D3D中有专门的函数来获取IDirect3D9指针

	IDirect3D9* d3d9 = NULL;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);

D3D_SDK_VERSION是创建IDirect3D9唯一需要的参数,该参数能够保证程序是基于当前版本的DirectX生成的。

1.2 检测硬件的处理能力

在创建IDirect3DDevice9时需要指定其顶点处理类型(硬件或者软件),硬件顶点处理速度较快,但是不是所有的显示适配器都具有该能力。可以调用函数GetDeviceCaps,该函数的原型如下

HRESULT IDirect3D9::GetDeviceCaps(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DCAPS9 *pCaps
);
  1. Adpater 指定要检测的显示适配器
  2. DeviceType 硬件类型,D3DDEVTYPE_HAL(硬件设备)、D3DDEVTYPE_REF(软件设备)。
  3. pCaps 返回D3DCAPS9结构,包含了硬件的所支持的各种特性。
//  检查硬件的顶点处理能力
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps); int vp = 0 ; //顶点处理类型
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

1.3 初始化 D3DPRESENT_PARAMETERS

D3DPRESENT_PARAMETERS用于指定IDirect3Device9的一些特性,其声明如下:

typedef struct _D3DPRESENT_PARAMETERS_
{
UINT BackBufferWidth;
UINT BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount; D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality; D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags; /* FullScreen_RefreshRateInHz must be zero for Windowed mode */
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS;
  • BackBufferWidth,BackBufferHeight bakck buffer的宽和高
  • BackBufferFormat back buffer的像素格式,例如:D3DFMT_A8R8G8B8
  • BackBufferCount back buffer的数量,通常为1
  • MultiSampleType,MultiSampleQuality 抗锯齿的类型和质量
  • SwapEffect 指定buffer在交换链(flipping chain)是如何被交换的,改值是D3DSWAPEFFECT类型的枚举,其中D3DSWAPEFFECT_DISCARD是效率 最高的。
  • hDeviceWindow 用于绘制的窗口句柄
  • Windowed 是窗口模式还是全屏,true为全屏。
  • EnableAutoDepthStencil 设置为true,D3D将自动的创建深度/模板buffer
  • AutoDepthStencilFormat 深度/模板buffer的格式
  • Flags 附加的一些特性,可以指定为0或者D3DPRESENTFLAG中某个值。比较推荐下面两个值
    • D3DPRESENTFLAG_LOCKABLE_BACKBUFFER back buffer能给被锁定,这会降低程序的性能。
    • D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL 在present下一个buffer时,当前的深度/模板buffer会被“丢弃(discard)",这有利于提升程序的性能。”discard“的意思是深度/模板buffer所占用的存储空间会被丢弃或者不可用。
  • FullScreen_RefreshRateInHz 刷新频率,使用D3DPRESENT_RATE_DEFAULT指定为默认的刷新频率。
  • PresentationInterval D3DPRESENT成员,两个常用的标志
    • D3DPRESENT_INTERVAL_IMMEDIATE 立即呈现
    • D3DPRESENT_INTERVAL_DEFAULT D3D选中呈现的速度,通常等于刷新率。

      D3DPRESENT_PARAMETERS的填充如下
	D3DPRESENT_PARAMETERS d3dpp;

	d3dpp.BackBufferWidth            = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = windowed;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

1.4 创建IDirect3Device9

填充D3DPRESENT_PARAMETERS后,IDirect3Device9就很简单了

d3d9->CreateDevice(D3DADAPTER_DEFAULT,deviceType,hwnd,vp,&d3dpp,device);

2. 简单框架 d3dUtility.h/cpp

在龙书的第二章提供了一个简单框架,用于D3D的初始化工作。

d3dUtility.h如下:

namespace d3d
{
bool InitD3D(HINSTANCE hInstance, //应用程序实例
int width,int height, //Back buffer的size
bool windowed, //是否全屏
D3DDEVTYPE deviceType, //设备类型 HAL或者REF
IDirect3DDevice9** device); // 创建的设备 [out] int EnterMsgLoop(bool (*ptr_display)(float timeDelta)); LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam); template<class T> void Release(T t)
{
if(t)
{
t->Release();
t = NULL;
}
} template<class T> void Delete(T t)
{
if(t)
{
delete t;
t = NULL;
}
}
}

函数Init3D创建程序的主窗口,并进行D3D的初始化工作,初始化完成返回IDirect3Device9的指针。

EnterMsgLoop 进入窗口的消息循环,它的参数是一个显示函数,该函数是用于图形的绘制。

Release 用于释放一个COM接口

Delete 用于删除一个对象

WndProc 是窗口的消息处理函数。

2.1 乱码处理

VS中的项目编码默认的是Unicode,这样在进行一些字符串处理(例如设置窗口标题)非常容易出现乱码。这就需要加入头文件tchar.h

#include <tchar.h>

在使用字符串的时候使用宏_T转换就可以避免乱码,例如:

wc.lpszClassName = _T("Direct3D9App");

2.2 PeekMessage 和 GetMessage的区别

在该框架中,进入窗口循环的代码如下:

int d3d::EnterMsgLoop(bool (*ptr_display)(float timeDelta))
{
MSG msg;
::ZeroMemory(&msg,sizeof(MSG)); static float lastTime = (float)timeGetTime(); while(msg.message != WM_QUIT)
{
if(::PeekMessage(&msg,0,0,0,PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
else
{
float currTime = static_cast<float>(timeGetTime());
float timeDelta = (currTime - lastTime) * 0.001f; ptr_display(timeDelta); lastTime = currTime;
}
}
return msg.wParam;
}

在上述代码中取得消息使用的是PeekMessage而不是常用的GetMessagePeekMessageGetMessage都是从消息队列中抓取消息,如果消息队列为空,程序的主线程会被操作系统挂起。过一段时间,当操作系统再次执行该线程时,如果消息队列仍然为空,这时这两个函数的行为则就不一样了:

  • GetMessage 会直接返回,阻塞当前线程,操作系统去执行其他的线程。
  • PeekMessage 则不同,它会取回控制权,使得当前线程再执行一段时间。上面的代码中,消息队列如果为空就执行display函数绘制图形。

3 总结

本文是龙书第二章的学习笔记,总结了D3D初始化的4个步骤,并对龙书中提供的代码框架作为简单分析。

DX9入门笔记1-D3D初始化的更多相关文章

  1. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  2. MySQL入门笔记

    MySQL入门笔记 版本选择: 5.x.20 以上版本比较稳定 一.MySQL的三种安装方式: 安装MySQL的方式常见的有三种: ·          rpm包形式 ·          通用二进制 ...

  3. ORMLite学习入门笔记

    ORMLite学习入门笔记 使用原始的SQLiteHelper来操作维护数据库有点过于繁琐,重复工作量较大.所以会想到使用一个比较方便的ORM来维护我们本地的数据库,各位业界前辈都给我推荐了ORMLi ...

  4. 1 TensorFlow入门笔记之基础架构

    ------------------------------------ 写在开头:此文参照莫烦python教程(墙裂推荐!!!) ---------------------------------- ...

  5. awk 新手入门笔记

    转自:http://www.habadog.com/2011/05/22/awk-freshman-handbook/ awk新手入门笔记 @作者 : habadog@邮箱 : habadog1203 ...

  6. golang微服务框架go-micro 入门笔记2.4 go-micro service解读

    本章节阐述go-micro 服务发现原理 go-micro架构 下图来自go-micro官方 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go- ...

  7. golang微服务框架go-micro 入门笔记2.3 micro工具之消息接收和发布

    本章节阐述micro消息订阅和发布相关内容 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架go-mi ...

  8. golang微服务框架go-micro 入门笔记2.1 micro工具之micro api

    micro api micro 功能非常强大,本文将详细阐述micro api 命令行的功能 重要的事情说3次 本文全部代码https://idea.techidea8.com/open/idea.s ...

  9. JavaScript基础——JavaScript入门(笔记)

    JavaScript入门(笔记) JavaScript是一种轻量级.解释型的Web开发语言,该语言系统不是很庞杂,简单易学.由于所有现代浏览器都已嵌入JavaScript引擎,JavaScript源代 ...

随机推荐

  1. poj1002-487-3279(字符串处理)

    一,题意: 中文题,不解释!二,思路: 1,处理输入的电话号码 2,排序num[]数组 3,输出三,步骤: 1,消除 -.Q.Z 三种字符,将一个电话号码转化为一个整数存如num[]数组 如:num[ ...

  2. SQL Server CheckPoint的几个误区

        有关CheckPoint的概念对大多数SQL Server开发或DBA人员都不陌生.但是包括我自己在内,大家对于CheckPoint都或多或少存在某些误区,最近和高文佳同学(感谢高同学的探讨) ...

  3. 深圳电信光纤用户必备:简单破解中兴ZXA10 F460光电猫,实现WIFI和自动拨号功能

    最近搬家,ADSL转成光纤宽带,下载速度非常给力.原来的ADSL路由器派不上用场,电信的安装人员也给开通了wifi功能,只是wifi无法上网,而且拨号一定需要用电脑连网线进行拨号.以前是直接把拨号账户 ...

  4. MVC学习一:EF

    目录 一.EF修改和删除的多种方法 二.标准查询where 三.include 四.skip take 五.反射获取实例属性 六.EF DLL数据访问帮助类 一.EF修改和删除的多种方法 方法1:官方 ...

  5. iOS开发系列--IOS程序开发概览

    概览 终于到了真正接触IOS应用程序的时刻了,之前我们花了很多时间去讨论C语言.ObjC等知识,对于很多朋友而言开发IOS第一天就想直接看到成果,看到可以运行的IOS程序.但是这里我想强调一下,前面的 ...

  6. (源码下载)高灵活度,高适用性,高性能,轻量级的 ORM 实现

    我在上一篇博客中简单说明了一个面向内存数据集的“ORM”的实现方法,也提到我的设计实现或许不能称之为“ORM”,姑且称之为 S-ORM吧. 可能有些小伙伴没有理解我的思路和目的,与传统ORM框架做了简 ...

  7. 常用网络工具 ipconfig arp traceroute

    如今的计算机是离不开网络的计算机了,因而我们对网络要有一基础的认识.连不上网,程序运行不正常之类的,多少都与网络有关.本文将介绍常用的工具. 网络出问题 ipconfig ping 网络连不上,首先要 ...

  8. Objective-C 原型模式 -- 简单介绍和使用

    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建 ...

  9. iOS---iOS9搜索功能

    前言 在iOS9之前我们只能使用Spotlight来搜索应用名称来打开指定App,而其他的内容都是提供给系统使用(信息,联系人,邮件等).在iOS9以后Apple允许开发者设置应用中任意内容可以被Sp ...

  10. Nginx重写

    一.location匹配 1.分类:(1)正则location:~,~*(2)普通location:=,^~,@,无2.匹配规则:(1) =    精确匹配.如果找到,停止搜索(2) ^~    普通 ...