有时候从一张白纸开始的感觉还是不错的。微软的上一个版本(DirectX7.0)是一个新的开始,画图元

(DrawPrimitive)开始形成了一种风格。
DirectX8(DX8)真正体现了其成熟之处。许多操作得到了改进和变得简单,其高级功能更为易用。一个简单的例

子,一个500行程序行的OpenGL程序,如果用DirectX8.0写的话,大约在1000行左右。如今,DirectX8和OpenGL

看起来已经非常相似了。
DirectX8的变化实在是太大了,我不想花太多的时间去讲述都发生了什么改变。取而代之的是,我将讨论更多

的是现在的DirectX8.0 API更象什么,以及你如何立即取得更多的优势。
DX8由6组API组成:DirectX图形(包括Direct3D和D3DX函数库),DirectX Audio(包括Direct Sound和Direct

Music),DirectInput, DirectPlay, DirectSetup, 和 DirectShow。DX8是非常庞大的,因此,我不想在这里

讨论所有的DX8 API,本文会指导你使用DX8进行图形和视频编程。
我不知到是否有更新版本的DirectX Media会出现。DirectShow原来是DirectX Media的一部分,现在它已经是

DirectX8.0运行库的一个基本部分了。对于开发者来讲这是有利的,因为不用再分别安装两个运行库。Direct

3D保留模式是Direct Media的一个组成部分,但D3DX函数库更有取代它的可能。我想DirectX将会不断地得来改

进,而Direct Media不再有改变,但旧的DirectX Media6.1仍然是可用的。

DirectX图形
或许DirectX8.0中最令人耀眼改变就是DirectDraw了,DirectDraw完全地被Direct3D所取代了。
Direct3D作了重大的改动,引入了许多新的特性。你不再须要列举任何的东西(设备)。Direct3D仅由12个接口

组成,它的遗传图表是非常单的:
(图)
其中最COOL的一点特性就是加入了一种阴影语言(shader language)。和Renderman或Quake 3的阴影语言相比,

M$的的阴影语言更类似于汇编语言(assembly language)。然而它们的概念却是一样的。
D3DX是DirectX的一个高级函数库。D3DX函数库是非常灵活的,其包含的API可用于创建从精灵(sprites)、文字

到粘图等所用的东西。使用D3DX将使你的取得跳跃性的进展。

DX8的矩阵操作是非常清析的(由其是在D3DX当中),并且工作起来更象OpenGL了。以下是其它一些与OpenGL相似

的地方:
Direct3D  OpenGL
BeginScene glBegin 
EndScene glEnd
DrawPrimitive glDrawElements
SetRenderState glEnable
SetTexture glBindTexture
Clear  glClear
许多的类似之处已经在早其版本中的DirectX中出现了,但新的DX8中明显地体现到DX8与OpenGL有许多相似之处


2D编程并没有完全被取代,DX8的D3DX库中有一个精灵(scripte)接口。然而首选的2D编程方式应该是使用简单

的粘图。色彩键(chroma keying)被取消了,做透明效果的唯一方法是使用alpha混合(alpha blending)。
或许你会说我会很快成为这套API的狂热者。或许你只习惯于OpenGL。但DX8作了许多改进,使用DX8开发你的游

戏已经不再成为问题了,我们将写一些DX8的代码来说明这一点。
DirectX图形API是非常简单而且功能强大的。当你使用DX8一段时日子后你会希望其它的DX8 API也象DirectX8

图形API那样简单易用。

DirectShow
DirectShow是M$的视频API,你可以在这里找到录象机、数码摄象机和DVD播放机等。游戏开发者可以很容易的

把视频电影加进他门的游戏中。
有一些新的特性加入了DirectShow,但与游戏开发关系不大。例如欧洲的PAL制式,M$的ASF等。
播放Video是游戏开发者使用DirectShow的主要原因,一会儿我们将会写一些这样的代码。

我们的程序主体
我会讲解几个演示程序,为了简单起见,所有的演示程序都是基于同一程序主体的。
程序主体大约有90行,它是一个简单的Win32程序。它的作用是建立一个Windows窗口并调用我定义的DirectX函

数。这些函数是InitDirect3D,ShutdownDirect3D,和DrawScene。

所有的Demo都使用同样的ShutdownDirect3D函数和变量。
#define HELPER_RELEASE(x) { if(x) { (x)->Release(); (x) = NULL; }}

IDirect3D8 * pID3D                   = NULL;
IDirect3DDevice8 * pID3DDevice       = NULL;
IDirect3DVertexBuffer8 * pStreamData = NULL;
IDirect3DIndexBuffer8 * pIndexBuffer = NULL;
IDirect3DTexture8 * pTexture         = NULL;

void ShutdownDirect3D()
{
  HELPER_RELEASE(pTexture);
  HELPER_RELEASE(pIndexBuffer);
  HELPER_RELEASE(pStreamData);
  HELPER_RELEASE(pID3DDevice);
  HELPER_RELEASE(pID3D);
}
我首先定义我所用到的接口。注意:并不是所有的demo都会用到所有的接口的。只是为了程序主体的统一和简

单化而已。
ShutdownDirect3D释放所有的接口。将来你可能要加入额外的代码来关闭Direct3D接口,但现在已经够了。
现在让我们开始我们的初始化代码吧,请定位到InitDirect3D函数。IDirect3D是我们首先要用到的接口,你可

以这样写:
IDirect3D8 * pID3D = Direct3Dcreate8(D3D_SDK_VERSION);
在你使用pID3D以前,请检查pID3D是否为非空。
你下一步通常是创建D3D设备,但在创建D3D设备之前你要调用GetAdapterDisplayMode方法取得必须的信息:
D3DDISPLAYMODE d3ddm;
pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);
接下来是取得当前显示模式参数。下面的参数是Surface格式。你可以用这些参数来创建一个

D3DPRESENT_PARAMETERS结构:
D3DPRESENT_PARAMETERS present;
ZeroMemory(&present, sizeof(present));
present.SwapEffect              = D3DSWAPEFFECT_COPY;
present.Windowed                = TRUE;
present.BackBufferFormat        = d3ddm.Format;
D3DPRESENT_PARAMETERS描述了显示器Surface的信息,交换机制的类型,应用程序是窗口的还是全屏模式等信

息。
在本例中,Surface是以拷贝方法代替页面翻转的,因为它是一个窗口模式的应用程序。把后台表面设置成与当

前显示模式相匹配的格式,一个准备显示的Surface可以Draw在后台表面上。

现在你可以创建一个IDirect3DDevice8接口了:
pID3D->CreateDevice(D3DADAPTER_DEFAULT,
                    D3DDEVTYPE_HAL,
                    hwnd,
                    D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                    &present,
                    &pID3DDevice);
这个函数有六个参数,幸运的是没有一个是很复杂的。D3DADAPTER_DEFAULT告诉Direct3D使用主显示器,只有

当你使用多显示器时才是必须的。你可以使用一个数值来指定另外一个显示器。调用IDirect3D的

GetAdapterCount将返回系统的适配器数目。
第二个参数,D3DDEVTYPE_HAL,告诉Direct3D使用硬件加速。其它选项包括D3DDEVTYPE_REF 和 D3DDEVTYPE_SW

,通常你都会希望使用硬件加速的,但有时侯你可能会使用软件加速进行测试。
指定窗口取得焦点。如果是全屏应用程序,你需要一个最顶层窗口。
D3DCREATE_SOFTWARE_VERTEXPROCESSING指定顶点处理类型。你也可以使用硬件加速或是联合类型,我不使用硬

件加速为的是广泛的兼容性。如果你想支持T&L,则你必须使用硬件加速。
最后两个参数很简单,一个是你以前建立的,而pID3Ddevice是你现在要创建的IDirect3DDevice8接口。如果方

法返回D3DERR_NOTAVAILABLE,则你写的参数是正确的,但你的设备不支持你指定的参数。
最完美的是这个方法自动为你创建后台缓冲(back buffers)和深度缓冲(depth buffers)。剪裁(Clipping

)作为后台表面(backface culling)被自动激活。灯光也被自动激活了,直到你定义顶点颜色之前,你可以

禁止使用灯光:
pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
InitDirect3D函数已经完成,让我们来看一看完整的InitDirect3D函数吧:
HRESULT InitDirect3D(HWND hwnd)
{
  pID3D = Direct3DCreate8(D3D_SDK_VERSION);

HRESULT hr;
  do
  {
    // we need the display mode so we can get
    // the properties of our back buffer
    D3DDISPLAYMODE d3ddm;
    hr = pID3D->GetAdapterDisplayMode(
                       D3DADAPTER_DEFAULT,
                       &d3ddm);
    if(FAILED(hr))
      break;

D3DPRESENT_PARAMETERS present;
    ZeroMemory(&present, sizeof(present));
    present.SwapEffect       = D3DSWAPEFFECT_COPY;
    present.Windowed         = TRUE;
    present.BackBufferFormat = d3ddm.Format;

hr = pID3D->CreateDevice(D3DADAPTER_DEFAULT,
                             D3DDEVTYPE_HAL,
                             hwnd,
                             D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                             &present,
                             &pID3DDevice);

if(FAILED(hr))
      break;

hr = pID3DDevice->SetRenderState(D3DRS_LIGHTING,
                                     FALSE);

} while(0);

return hr;
}

现在让我们把注意力集中到DrawScene函数吧,在我们的第一个练习中我只想放一些简单的东西在场景中。当你

达到这一点后,在这上面加些东西是很简单的事。
下面是DrawScene函数:
HRESULT DrawScene()
{
  HRESULT hr;
  do
  {
    // clear back buffer
    hr = pID3DDevice->Clear(0,
                            NULL,
                            D3DCLEAR_TARGET,
                            D3DCOLOR_RGBA(0,63,0,0),
                            0,
                            0);
    if(FAILED(hr))
      break;

// start drawing
    hr = pID3DDevice->BeginScene();
    if(FAILED(hr))
      break;

// Put all drawing code here

hr = pID3DDevice->EndScene();
    if(FAILED(hr))
      break;

// flip back buffer to front
    hr = pID3DDevice->Present(NULL, NULL, NULL, NULL);
  } while(0);

return hr;
}
这段代码是很简洁的。Clear会填充你指定的缓冲区。你可以填充Z缓冲区、后台缓冲区或摸板缓冲区(stencil

buffer)。在这个例子中你将用绿色填充后台缓冲区。所以,我们设定D3DCLEAR_TARGET标志和绿色。
在本例中BeginScene和EndScene并没有做什么,但在以后的例子中我们会用到它的。这两个函数是画图元时的

例行公事代码,
这个函数不断的翻转后台表面。我们可以不断的在后台表面画一些东西,然后把后台表面翻转到前台表面。
如果你现在就运行程序,你将得到一个绿色背景的窗口。如果一切都正常,你就可以编写代码去画一个三角形

了,要知道画图元乃是游戏编程的核心。

画三角形(d3d2.cpp)
三角形有几个有趣的特性,是它们在三维编程中吸引人的地方。它们总是平面,三角形的组合可以成为任何的

几何体。在后面的例子中我们会用三角形去建立一个立方体。通常我会在我的第一个三维引擎中做一个立方体

旋转的例子。如果它适合于一个程序员,那么它也适合于另外一个程序员。
在它的最简单形式当中,是一个由三个顶点组成的三角形。程序员是怎样定义这些顶点的呢。一个二维的三角

形你可以用x和y轴坐标系来定义每一个点。一个完善的三维程序可能会定义顶点的坐标系,转换坐标系,颜色

,几个纹理坐标系和其它一些信息。
从严格的语义学来讲,如何运用这些信息在OpenGL和Direct3D之间只有些微的区别。画一些不连续的三角形时

,你可以分别的定义它们。当你画一个模型的时候许多的顶点在三角形之间是共享的,所以,为每一个三角形

保存三个顶点是低效率的。在OpenGL和Direct3D中你都可以在一个大的阵列中为一个模型指定所有的顶点。三

角形的个数被定义成三的整数倍。你可以把这个阵列传给一个函数,例如,DrawIndexedPrimitive,使用它你

可以立即画出一个三维模型。
定义你的顶点格式,Direct3D引入了一种可变形顶点格式(flexible vertex format)(FVF)的概念。在FVF

中,你定义一个结构其中包括所需要的顶点组成部分。这个结构会随着你的程序而改变,但在这里你将初步把

它定义成这个样子:
struct MYVERTEX
{
  FLOAT x, y, z; // The transformed position
  FLOAT rhw;     // 1.0 (reciprocal of homogeneous w)
  DWORD color;   // The vertex color
};
示例的开始定义了一个顶点结构,顶点的名称,和每一个三角形的顶点。在你的InitDirect3D函数中,你必须

创建一个顶点缓冲区:
int num_elems = sizeof(vertices) / sizeof(vertices[0]);
pID3DDevice->CreateVertexBuffer(sizeof(MYVERTEX) *
                                num_elems,
                                D3DUSAGE_WRITEONLY,
                                D3DFVF_XYZRHW|D3DFVF_DIFFUSE,
                                D3DPOOL_DEFAULT,
                                &pStreamData);
函数的第一个参数是顶点结构的字节大小。在应用程序还不能读取顶点之前,传一个D3DUSAGE_WRITEONLY标记

给它。这里可以有不同的标记来指定如何处理你的顶点,但现在你可以确信Direct3D已经能正确的工作了。
下一步,指定我们用的是什么FVF格式。当你还没有使用坐标系预转换之前,指定为D3DFVF_XYZRHW标记。以后

你使用自己的矩阵坐标系转换时,把它改成D3DFVF_XYZ。D3DFVF_DIFFUSE告诉Direct3D,我们将为每一个顶点

指定颜色。D3DPOOL_DEFAULT指定内存的管理模式。
最后一个参数是顶点缓冲区的指针,在例子1中你已经定义了它,但并没有用上。
如果你不向顶点缓冲区填入有用数据的话,顶点缓冲区是没有用的:
MYVERTEX *v;
pStreamData->Lock(0, 0, (BYTE**)&v, 0);
for(int ii = 0; ii < num_elems; ii++)
{
  v[ii].x     = vertices[ii].x;
  v[ii].y     = vertices[ii].y;
  v[ii].z     = vertices[ii].z;
  v[ii].rhw   = vertices[ii].rhw;
  v[ii].color = vertices[ii].color;
}
pStreamData->Unlock();
这是不难理解的,Lock返回一个你想写入顶点数据的指针。下一步你从你的顶点阵列中拷贝数据。然后,反还

这个指针。
这一对的调用可以告诉Direct3D你的FVF格式,并设定顶点阵列为当前的活动顶点阵列。(你可以有多个顶点阵

列)。
pID3DDevice->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);

pID3DDevice->SetStreamSource(0, pStreamData, sizeof(MYVERTEX));
SetVertexShader告诉Direct3D使用与CreateVertexBuffer同样的格式。
SetStreamSource告诉Direct3D使用pStreamData作为当前顶点阵列,并取得所有元素的大小。
你现在可以加入画三角形的代码了。在BeginScene和EndScene之间加入如下代码:
int num_elems = sizeof(vertices) / sizeof(vertices[0]);
pID3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
                           0,
                           num_elems / 3);
D3DPT_TRIANGLELIST标记将命令Direct3D画不连续的三角形。你指定从索引的第0个顶点开始,指定所要画的三

角形数目。
如果正确的话,你会看到一个三角形画在先前的绿色背景窗口上。

声明:
本文的英文原作者是:Toby "Ace" Jones 作者电子邮件:tjones@hot-shot.com
我首先看到英文原作的网站是:http://gamedev.net
本文的SourceCode和英文原作都可以从http://gamedev.net得到
欢迎您光临我的主页:http://gamedev.363.net
陈伟凡
E-mail: laical@21cn.com
2000/12/19

转:DirectX8.0初体验, 有点老,但写的挺好相关推荐

  1. php的swoole教程,PHP + Swoole2.0 初体验(swoole入门教程)

    PHP + Swoole2.0 初体验(swoole入门教程) 环境:centos7 + PHP7.1 + swoole2.0 准备工作: 一. swoole 扩展安装 1 .下载swoole cd/ ...

  2. 来一起学习一下vue3.0 初体验---comeon

    vue3.0 初体验 第一步创建项目 第二步对vue项目进行升级 接下来你就可以尽情的开发啊 第一步创建项目 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使用Ma ...

  3. vue3.0响应式源码实践,vue3.0初体验

    vue3.0响应式源码实践,vue3.0初体验 镇楼图--杀生丸.jpg vue-next(vue3.0预体验) 1. 使用: 2.vue-next的目录结构 3. reactive内部实现 作者上篇 ...

  4. 魅族 android6.0,大屏又好用的 MEIZU 魅蓝MAX及Flyme6.0初体验

    大屏又好用的 MEIZU 魅蓝MAX及Flyme6.0初体验 2017-01-03 15:49:10 9点赞 11收藏 28评论 其实这个手机已经买了快2个月了,奈何拖延症犯了.....一直不想写,拖 ...

  5. 鸿蒙OS2.0初体验

    重要的放前面 鸿蒙官方开发文档 鸿蒙IDE下载地址 鸿蒙OS入门2.0教程 鸿蒙初体验视频 鸿蒙2.0开源地址 一.HarmonyOS优点 (1)多终端开发调试便捷 鸿蒙目前支持可以开发TV,wear ...

  6. mysql8.0怎么样_MySQL8.0初体验

    MySQL8.0的官方社区开源版出来有段时间了,而percona的8.0版本还没有正式对外发布(已发布测试版),一直以来也没安装体验下这个号称质的飞跃的版本,今天正好有些时间就下了安装体验体验. 一. ...

  7. MySQL 8.0初体验

    从决定安装MySQL 8.0到开始行动,也就不到一个小时的时间,一个小时的时间能干些啥呢,来简单体验下8.0,官网上能看到这个丰富的表情包. 我们知道表情的信息在数据库中存储,使用 UTF8是无能为力 ...

  8. OWT (Open WebRTC Toolkit) 5.0 初体验与开发环境搭建

    介绍 OWT是Intel前些年开源的基于互联网的视频会议解决方案,可以支持WebRTC和SIP终端.这几年WebRTC应用的特别广泛,使用OWT可以快速搭建一个WebRTC视频会议系统.OWT最初仅支 ...

  9. android9.0ai技术,Funtouch OS 9.0初体验:AI技术加持,黑科技满满

    [PConline 专业评测]在3月19日晚上,vivo在海南三亚举办X27新品发布会.除了新款手机产品之外,全新的Funtouch OS 9.0也正式亮相. Funtouch OS 9.0基于And ...

最新文章

  1. oracle增加数据时报没安装java_在linux上安装Oracle Developer Tools for VS Code
  2. 锁的升级与synchronized锁的关系
  3. Anaconda 默认环境
  4. 2018南京网络赛 G. Lpl and Energy-saving Lamps (线段树非递归实现)
  5. 与金山云的樊博士聊了聊AV1算法优化以及如何提升沉浸式视频的沉浸感
  6. ABC182——F - Valid payments Editorial
  7. 克隆安装oracle,Oracle 之 Cloning $oracle_home (克隆安装oracle软件)
  8. 基于python的图像分割并计数
  9. 一起谈.NET技术,抛砖引玉:我看微软.NET各子技术领域之应用前景
  10. html div转行,转行web前端开发的人有没有未来
  11. linux、window中源码安装maven
  12. 28. Avoid returning handles to object internals
  13. 多View统一Camera v1.2
  14. 最小的单片机:ATtiny85
  15. 爬虫--雪球网爬取(requests 和 request 的两种方法)
  16. 网络爬虫技术是什么,网络爬虫的基本工作流程是什么?
  17. bubbles html5游戏源码,html5 canvas弹性气泡爆破 | 撒花动画
  18. 常用Windows系统进程列表
  19. 解锁工具Unlocker试用
  20. oracle转trs,TRS数据库数据的导入导出2.doc

热门文章

  1. Java及JavaScript常见框架汇总
  2. 【集合论】序关系 ( 链 | 反链 | 链与反链示例 | 链与反链定理 | 链与反链推论 | 良序关系 )
  3. (转)CMMI证书背后的6大怪现象
  4. CMMI证书背后的6大怪相
  5. ERP 软件项目验收流程
  6. WeMall:一元超值购,购惊喜,够时尚!
  7. 智慧油库人员定位管理系统“位”何而来?
  8. CES归来---话说AR眼镜
  9. 代码:用路由器模拟 神经元,以实现人工智能(一)
  10. 扫盲:什么是加德纳技术成熟度曲线?