《逐梦旅程 WINDOWS游戏编程之从零开始》笔记7——DirectInput&纹理映射

第15章 DirectInput接口

DirectInput作为DirectX的组件之一,依然是一些COM对象的集合。DirectInput由IDirectinput8、IDirectInputDevice8和IDirectInputEffect这3个接口组成。其中IDirectInput8作为DirectInput API中最主要的接口,用于初始化系统以及创建输入设备接口,DirectInput中其他所有接口都需要依赖于我们的IDirectInput8之上,都是通过这个接口进行查询的。而DirectInputDevice8接口用于表示各种输入设备,并提供了相同的访问和控制方法。对于某些输入设备(如鼠标),都能够通过查询各自的IDirectInputDevice8接口对象,得到另一个接口IDirectInputEffect8。而IDirectInput8接口则用于控制设备的力反馈效果。

DirectInput使用步骤:

首先是包含 DInput.h 头文件,并且项目属性页中已经链接了 DInput.lib 等库文件:

然后是创建DirectInput接口和设备:

通过调用DirectInputCreate函数创建并初始化IDirectInput接口:

HRESULT DirectInput8Create(
         HINSTANCE hinst,  //当前创建的DirectInput的Windows程序句柄
         DWORD dwVersion,  //DirectInput的版本号
         REFIID riidltf,  //接口的标志,通常取IID_IDirectInput8就可以了
         LPVOID * ppvOut,  //用于返回我们新创建的IDrectInput8指针
         LPUNKNOWN punkOuter  //设为NULL即可
)

下面是个调用的例子:

//创建DirectInput设备
LPDIRECTINPUT8 g_DirectInput = NULL;
if(FAILED(DirectInput8Create(hInstance, 0x800, IID_IDirectInput8, (void**)&g_pDirectInput, NULL)))
  return E_FAIL;

在IDirectInput8接口中包含了很多了很多用于初始化设备及获得设备接口的方法。其中,常用的方法为EnumDevices和CreateDevices。前者用于获得输入设备的类型,而后者用于为输入设备创建IDirectInputDevice8接口对象。需要注意的是,系统中每一个已安装的设备都有一个系统分配的全局唯一标识符(GUID)。要使用某个设备的话,首先我们就需要知道它的GUID。

鼠标和键盘作为我们电脑中最为重要的外设,DirectInput对它们做了特殊对待,定义了它们的GUID分别为GUID_Keyboard和GUID_SysMouse。而对于其他的输入设备,我们就用上面提到过的EnumDevices方法枚举出这些设备,已得到它们的GUID:

HRESULT EnumDevices(
         DWORD dwDevType,  //指定我们需要枚举的设备类型
         LPDIENUMDEVICESCALLBACK lpCallback,  //用于指定一个回调函数的地址,当系统中每找到一个匹配的设备时,就会自动调用这个回调函数
         LPVOID pvRef,  //返回我们当前匹配设备的GUID值
         DWORD dwFlags  //指定我们枚举设备的方式
)

取得我们需要使用的设备的GUID后,就可以根据这个GUID来调用IDrectInput9接口中的CreateDevice方法,进而来创建设备的IDirectInputDevice接口对象了。

HRESULT CreateDevice(
         REFGUID rguid,  //输出设备的GUID
         LPDIRECTINPUTDEVICE * lplpDirectInputDevice,   //创建的输入设备对象的指针地址,可以说调用这个CreateDevice参数就是在初始化这个参数
         LPUNKNOWN pUnkOuter    //取NULL即可
)

下面的代码中CreateDevice方法的第一个参数我们填的是GUID_SysMouse,为系统鼠标创建一个Direct设备接口对象:

LPDIRECTINPUTDEVICE8 g_pMouseDevice = NULL;
if(FAILED(g_pDirectInput->CreateDevice(GUID_SysKeyboard,&g_pKeyboardDevice,NULL))
  return E_FAIL;

设置数据格式:数据格式用于表示设备状态信息的存储方式,每种设备都有一种用于读取对应数据的特定数据格式,所以对每种设备都要区别对待。设置数据格式通常都是用IDrectInputDevice8接口的SetDataFormat方法来做到,这个方法可以把设备的数据格式填充到一个DIDATAFORMAT接口类型的对象。

HRESULT SetDataFormat(
         LPCDIDATAFORMAT lpdf
)

关于LPCDIDATAFORMAT类型的lpdf,下面是一些备选参数:

设置协作级别:因为每个应用程序通常会使用多个输入设备,并且同一输入设备也可能被多个应用程序同时使用。因此,需要一种方式来共享和协调应用程序对舍设备的访问。协作级别定义了进程与其他应用程序和操作系统共享设备的方式。设备一旦创建就需要设置它的协作级别。DirectInput的协作级别可以以两套方案来分类:前台,后台模式和共享,独占模式。

平常通过IDirectInputDevice8接口的SetCooperativeLevel方法来设置设备的协作级别:

HRESULT SetCooperativeLevel(
         HWND hwnd,  //与当前设备想关联的窗口句柄
         DWORD dwFlags  //描述了当前设备的协作级别类型
)

设置特殊属性:设备的特殊属性包含设备的数据模式,缓冲区大小以及设备的最小最大范围等等。DirectInput为我们提供了SetProperty方法来设置设备的特殊属性:

HRESULT SetProperty(
         REFGUID rguidProp,
         LPCDIPROPHEADER pdiph
)

获取和轮询设备:使用设备之前往往要重新获取一下设备的控制权。通过IDirectInput8接口的Acquire方法:

g_pMouseDevice->Acquire()

另外需要注意的是,在获得设备的控制权之前,必须先调用IDirectInputDevice8接口的SetDataFormat或者SetActionMap方法来设置一下数据格式,否则调用Acquire方法的话,将直接给我们返回DIERR_INVALIDPARAM错误。

轮询可以准备在合适的情况下读取设备数据。因为数据可能具有临界时间。用法如下:

g_pMouseDevice->Poll();

读取设备信息:拿到对输入设备的控制权之后,就可以调用IDirectInputDevice8接口的GetDeviceState方法来读取设备的数据。为了存储设备的数据信息,在调用该方法时,须传递一个数据缓冲区给GetDevice方法。

HRESULT GetDeviceState(
         DWORD cbData,  //指定缓冲区的大小
         LPVOID lpvData  //一个获取当前设备状态的结构体的地址
)

第二个参数的数据格式和之前调用的SetDataFormat方法有着前呼后应的密切联系:

比如,我们先调用了SetDataFormat设置了设备的数据格式为c_dfDIMouse:

g_pMouseDevice->SetDataFormat(&c_dfDIMouse);

那么在读取设备信息的时候调用GetDeviceState就需要把第二个参数填与dfDIMouse对应的DIMOUSESTATE结构体中的一个实例:

DIMOUSESTATE dimouse;
g_pMouseDevice->GetDeviceState(sizeof(dimouse), (LPVOID)&dimouse);

DirectInuput使用五步曲(以键盘为例):

  • 创建DirectInput接口和设备
  • 设置数据格式和协作级别
  • 获取设备控制权
  • 获取按键情况并做响应
  • 释放控制权和接口对象

示例代码如下:

//首先是全局变量的定义
LPDIRCTINPUTDEVICE8 g_pKeyboardDevice = NULL;
char g_pKeyStateBuffer[256]={0};

//【DirectInput使用五步曲之一】,创建DirectInput接口和设备
DirectInput8Create(hInstance, 0x800, IID_IDirectInput8, (void**)&g_pDirectInput, NULL);
g_pDirectInput->CreateDevice(GUID_Syskeyboard, &g_pKeyboardDevice, NULL);

//【DirectInput使用五步曲之二】,设置数据格式和协作级别
g_pKeyboardDevice->setDataFormat(&c_dfDIKeyboard);
g_pKeyboardDevice->setCooperativeLevel(hwnd,DISCL_FOreGROUND|DISCL_NONEXECLUSIVE);

//【DirectInput使用五步曲之三】,获取设备控制权
g_pKeyboardDevice->Acquire();

//【DirectInput使用五步曲之四】,获取按键情况并作出响应
//读取键盘输入
ZeroMemory(g_pKeyStateBuffer,sizeof(g_pKeyStateBuffer);
Device_Read(g_pKeyboardDevice,(LPVOID)g_pKeyStateBuffer,sizeof(g_pKeyStateBuffer));

//定义的全局函数
BOOL Device_Read(IDirectInputDevice8* pDIDevice, void* pBuffer, longlSize)
{
    HRESULT hr;
    while(true)
    {
        pDIDevice->Poll();    //轮询设备
        pDIDevice->Acquire();
        if(SUCCEEDED(hr=pDIDevice->GetDeviceState(lSize,pBuffer))) break;
        if(hr!=DIERR_INPUTLOST||hr!=DIERR_NOTACQUIRED) return false;
        if(FAILED(pDIDevice->Acquire())) return false;
    }

    return TRUE;
}

//然后就是用if判断并作响应了
if(g_pKeyStateBuffer[DIK_A]&0x800)fPosX-=0.005f;

//【DirectInput使用五步曲之五】,释放控制权和接口对象
g_pKeyboardDevice->Unacquire();
SAFE_RELEASE(g_pKeyboardDevice);

注:上面判断键码为什么要按位与0x800? 现在还不是很明白

DirectInput键盘按键值:简而言之就是DirectInput并非使用Windows中的消息机制来读取键盘的状态,而是直接读取硬件的状态获取按键的扫描码的,DirectInput中与键对应的宏是以DIK_开头。在程序中,需要定义一个大小为256字节的数组,其中每一个字节都存储一个按键的状态,这样就可以保存256个按键的状态信息了。关于DirectInput的键码可以查msdn文档

DirectInput鼠标按键值:在Direct3D中,可以直接同鼠标的驱动程序进行交互,而不用走消息队列这条慢悠悠的道。另外有绝对模式和相对模式来跟踪鼠标的移动。在DirectInput中,鼠标的移动信息通常是通过一个DIMOUSESTATE结构体来记录的:

typedef struct DIMOUSESTATE {
    LONG lX;  //x轴坐标
    LONG lY;  //y轴坐标
    LONG lZ;  //滚轮的相对移动量,没移动的话就是0
    BYTE rgbButtons[4];  //rgbButtons[0]代表鼠标左键,rgbButtons[1]代表鼠标右键
} DIMOUSESTATE, *LPDIMOUSESTATE


第16章 纹理映射

计算机图形学中比较重要的一块,首先是明白其概念。比如现在要绘制出如下效果的一个贴了瓷砖的立方体:

问题在于如何绘制出像砖块那样坑坑洼洼的效果呢?首先是线绘制一个立方体,接着注备一副描绘着砖块状的2D图片,然后把这幅图片像贴画一样贴到这个立方体的六个面:

上面的方法就是纹理映射的思想。即将2D图像映射到3D物体上的技术。

纹理映射使用四步曲

1. 纹理坐标的定义:一般把纹理映射所使用的2D图像称作为纹理贴图。Direct3D支持多种格式图片的纹理贴图,一般使用边长为2的N次幂正方形图片。纹理贴图往往都通过一个二维数组存储每个点的颜色值,称之为纹理元素,而每个纹理元素在纹理中都有唯一的地址。为了将纹理贴图映射到三维图形中,Direct3D使用了纹理坐标确定纹理贴图上的每个纹理元素。

纹理坐标由一个二维坐标系指定,这个坐标系由沿水平方向的u轴和沿垂直方向的v轴构成,(u,v)。其中u轴正方向为水平右,v轴正方向为垂直向下,它们的取值都在[0,1]之间。

纹理坐标位于纹理空间之中,是相对坐标,相对于纹理坐标系中的源点(0,0)。当把纹理映到三维模型表面上时,纹理元素首先被映射到物体模型的局部坐标系中,然后再变换到屏幕坐标系中对应的像素位置。

2. 顶点的访问:在FVF灵活顶点格式中定义好纹理坐标之后,要想把纹理坐标存到缓存顶点中,需要访问顶点缓存。比如在第一步中定义的顶点格式是这样的(看到这里要点迷迷糊糊的,顶点为什要定义纹理坐标,现在猜测是因为这个顶点要根据它里面的纹理坐标来去纹理坐标系中取相应的纹理元素来贴图):

struct CUSTOMVERTEX
{
    FLOAT _x, _y, _z;               // 顶点的位置
    FLOAT _u, _v;                   // 纹理坐标
    CUSTOMVERTEX(FLOAT x, FLOAT y, FLOAT z, FLOAT u, FLOAT v)
        : _x(x), _y(y), _z(z), _u(u), _v(v) {}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)

上面的程序看不懂了,哦哦,难道这里要gg?开玩笑,百度大法 ,找到了其中一部分的解答:

也就是说,CUSTOMVERTEX(FLOAT x, FLOAT y, FLOAT z, FLOAT u, FLOAT v) : _x(x), _y(y), _z(z), _u(u), _v(v) { } ,这句话的作用是利用CUSTOMVERTEX构造函数对成员_x, _y, _z, _u和_v进行初始化,_x(x) 的意思就是将构造函数的输入参数x赋给_x,其他的同理。

回到正题,如果第一步定义的顶点格式如上,接着下一步就要做如下的填空题:

//填充顶点缓存
CUSTOMVERTEX *pVertices;
if(FAILED(g_pVertextBuffer->Lock(0,sizeof(CUSTOMVERTEX),(void**)&pVertices,0)))
    return E_FAIL;

//正面顶点数据
pVertices[0]=CUSTOMVERTEX(-10.0f,10.0f,-10.0f,0.0f,0.0f);
pVertices[1]=CUSTOMVERTEX(10.0f,10.0f,-10.0f,1.0f,0.0f);
pVertices[2]=CUSTOMVERTEX(10.0f,-10.0f,-10.0f,1.0f,1.0f);
pVertices[3]=CUSTOMVERTEX(-10.0f,-10.0f,-10.0f,0.0f,1.0f);
g_pVertextBuffer->Unlock();

3. 纹理的创建:顶点这边的内同经过以上两步已经大功告成,接下里就是创建一个纹理对象,从文件中读取一副纹理并保存在这个对象中。在Direct3D中,纹理是以COM对象的形式存在的,也就是IDirect3DTexture9这个接口。要对物体表面进行纹理映射的话,首先要创建纹理对象,指定纹理的宽,高,格式等属性,然后还需要将图形文件加载到纹理对象中。可以用D3DX库中的D3DXCreateTexture函数创建一个纹理对象。

HRESULT D3DXCreateTexture(
  _In_  LPDIRECT3DDEVICE9  pDevice,  //Direct3D设备对象
  _In_  UINT               Width,  //纹理对象宽度
  _In_  UINT               Height,  //高度
  _In_  UINT               MipLevels,  //渐进级别
  _In_  DWORD              Usage,  //纹理的使用方式
  _In_  D3DFORMAT          Format,  //纹理中保存每个颜色成分所使用的位数
  _In_  D3DPOOL            Pool,  //纹理对象停驻的内存类别
  _Out_ LPDIRECT3DTEXTURE9 *ppTexture  //我们要的东西,指向IDirect3DTexture9接口的指针
);

更多的情况是从文件中读取纹理图形的,用的函数是D3DXCreateTextureFromFile函数:

HRESULT D3DXCreateTextureFromFile(
  _In_  LPDIRECT3DDEVICE9  pDevice,  //Direct设备对象
  _In_  LPCTSTR            pSrcFile,  //用于创建纹理的图标文件名字的字符串
  _Out_ LPDIRECT3DTEXTURE9 *ppTexture  
);

4. 纹理的启用:加载完纹理后,就可以调用IDirect3DDevice接口的SetTexture方法,设置当前需要启用的纹理:

HRESULT SetTexture(
  [in] DWORD                 Sampler,  //指定了应用的纹理是哪一层
  [in] IDirect3DBaseTexture9 *pTexture  //将要启用的纹理的IDirect3DBaseTexture9对象
);

另外,如果物体模型所使用的纹理不相同,那么在每个绘制物体模型之前都需要调用该方法设置对应的纹理:

四大纹理过滤方式

当Direxct3D渲染一个图元或者三维图形时,必须将它们通过坐标变换映射到二维屏幕之上。而但我们使用纹理来进行辅助渲染的时候,Direct3D就必须使用该纹理为二维图像上的每个像素进行着色。这里的每个像素都包含一个来自纹理的颜色值,而从纹理中为每个像素获取颜色的过程,就是所谓的纹理过滤了。大多数情况下,屏幕显示的图形与纹理贴图大小是不相同的。这个纹理会被映射到一个比他大或者小的图元图像上。纹理会被放大或者缩小,对纹理的放大会造成很多像素被映射到同一个纹理元素上,这样的图形渲染的结果就会有色块的感觉。缩小一个纹理意味着一个像素被映射到许多纹理上,图形看上去闪烁或者失真或者有锯齿。为了解决这些问题,就有了纹理过滤方式。

Direct3D,有四种过滤方式:

  • 最近点采样过滤
  • 线性纹理过滤
  • 各项异性过滤
  • 多级渐进过滤

设置纹理过滤方式通常采用的是IDirect3DDevice9::SetSamplerState函数:

HRESULT SetSamplerState(
  [in] DWORD               Sampler,  //指定为哪一层纹理设置采样状态
  [in] D3DSAMPLERSTATETYPE Type,    //指定对哪种纹理采用属性来进行操作
  [in] DWORD               Value  //对第二个参数指定的属性进行值的设置
);

1. 最近点采样过滤:速度最快,效果最差。Direct3D计算得到的纹理过滤元素通常是一个浮点值,使用最近点采样时,Direct3D会复制与这个浮点值地址最接近的整数地址的纹理元素的颜色。

下面是一个调用实例,把纹理层0的过滤方式设置为最近点采样:

//最近点采样过滤
g_pd3dDevice->setSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_POINT);
g_pd3dDevice->setSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_POINT);

2. 线性纹理过滤:目前使用最广泛的纹理过滤方式。线性纹理过滤取得与计算得到的纹理元素的浮点地址最接近的上下左右4个纹理元素,对这四个纹理元素进行加权平均,从而得到最终显示的颜色值。依旧来个调用实例,将第0层纹理的放大和缩小过滤器设置为线性过滤器:

//最近点采样过滤
g_pd3dDevice->setSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR);
g_pd3dDevice->setSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_LINEAR);

3. 各向异性纹理过滤:在很多时候,三维物体的表面不可能是完全平面的,当三维物体的表面和投影平面不平行时,它在屏幕上的投影会有拉长和扭曲的现象,这种现象称为各向异性。当一个各项异性的图元映射到纹理元素上时,就会发生扭曲。而Direct3D会根据屏幕像素反向转换到纹理元素的延长度,来决定各项异性的程度。

关于使用方法,基本和之前类似,但是还需要专门设置一下最大各项异性的程度值:

//各项异性过滤
g_pd3dDevice->setSamplerState(1,D3DSAMP_MAXANISOTROPY,3)
g_pd3dDevice->setSamplerState(1,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
g_pd3dDevice->setSamplerState(1,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);

4. 多级渐进纹理过滤:这种过滤方式要和上面的过滤方式中的一种结合使用。多级渐进纹理就是由一组分辨率逐渐降低的纹理序列组成,每一级纹理的宽度和高度都是上一级纹理的宽度和高度的一半。这些图片不一定要是正方形。在Direct3D映射纹理时,会自动选择一副与物体大小最接近的纹理进行渲染。

对于多级渐进纹理的生成,使用的函数是D3DXCreateTextureFromFileEx:

HRESULT D3DXCreateTextureFromFileEx(
  _In_    LPDIRECT3DDEVICE9  pDevice,  //D3D设备接口对象
  _In_    LPCTSTR            pSrcFile,  //纹理贴图的文件地址
  _In_    UINT               Width,  //纹理宽度,0表示使用贴图的宽度
  _In_    UINT               Height,  //高度
  _In_    UINT               MipLevels,  //生成的渐进纹理的级数目
  _In_    DWORD              Usage,  //用法的标志,通常设为0
  _In_    D3DFORMAT          Format,  //纹理贴图的格式
  _In_    D3DPOOL            Pool,  //保存纹理的方式
  _In_    DWORD              Filter,  //纹理过滤方式
  _In_    DWORD              MipFilter,  //生成纹理序列的过滤方式
  _In_    D3DCOLOR           ColorKey,  //替换Alpha值的颜色值
  _Inout_ D3DXIMAGE_INFO     *pSrcInfo,  //设为NULL即可
  _Out_   PALETTEENTRY       *pPalette,  //同上
  _Out_   LPDIRECT3DTEXTURE9 *ppTexture  //纹理接口对象
);

下面是这个函数的一个调用实例:

对于多级渐进纹理的使用,要和之前的3种过滤方式的其中一种组合使用。用的还是SetSamplerState函数,第一个参数还是纹理层数的序号,第二个参数为设为D3DSAMP_MIPFILTER,第三个参数设置为在相邻纹理之间的过滤方式。比如下面这个代码就把相邻纹理级之间的过滤方式设置为线性过滤:

g_pd3dDevice->setSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR)

四大纹理寻址方式

Direct3D应用程序可以为任何图元的任何顶点指定纹理坐标。通常使用的u、v纹理坐标的取值范围是[0.0, 1.0]。但如何控制[0.0, 1.0]坐标范围之外的纹理坐标值了,这时候需要用到纹理寻址模式。Direct3D中有四种纹理模式供我们选择,来处理超出[0.0, 1.0]坐标范围之外的纹理映射情况。分别是:重复纹理寻址模式,镜像纹理寻址模式,夹取纹理寻址模式和边框颜色纹理寻址。

1. 重复纹理寻址模式:默认的寻址模式,允许在每个整数连接点处重复上一个整数的纹理。

我们可以用那个SetSamplerState函数来手动启用这种重复寻址模式,如下两句连用,分别对U轴和V轴启用重复纹理寻址模式:

g_pd3dDevice->setSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_WRAP);
g_pd3dDevice->setSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_WRAP);

2. 镜像寻址模式:会在每个整数纹理坐标连接处自动复制并翻转纹理,且为两两成对翻转,这样的话上面那个正方形图元就会变成这样:

3. 夹取寻址模式:将纹理坐标夹取在[0.0,1.0]之间,就是说,在[0.0,1.0]之间把纹理复制一遍,然后对于这之外的内容,将边缘的u轴和v轴进行一下延伸。对于上面的那个图元,在4个顶点的纹理坐标相同的情况下,就会变成这样:

4. 边框颜色纹理寻址:在[0.0,1.0]之间绘制一下纹理,然后[0.0,1.0]之外的内容就用边框颜色填充:



参考博客:

【Visual C++】游戏开发笔记四十一 浅墨DirectX教程之九 为三维世界添彩:纹理映射技术(一)

【Visual C++】游戏开发笔记四十二 浅墨DirectX教程之十 游戏输入控制利器:DirectInput专场

【Visual C++】游戏开发笔记四十三 浅墨DirectX教程十一 为三维世界添彩:纹理映射技术(二)

时间: 2024-10-11 12:20:24

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记7——DirectInput&纹理映射的相关文章

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记6——Direct3D中的顶点缓存和索引缓存

第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物体模型的基本单元,而一个三角形有3个顶点,为了能够使用大量三角形组成三角形网格来描述物体,需要首先定义号三角形的顶点(Vertex),3个顶点确定一个三角形,顶点除了定义每个顶点的坐标位置外,还还含有颜色等其他属性. 在Direct3D中,顶点的具体表现形式是顶点缓存,顶点缓存保存了顶点数据的内存空

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D编程基础

第11章 Direct3D编程基础 2D游戏是贴图的艺术,3D游戏是渲染的艺术.这句话在我学过了之前的GDI编程之后,前一句算是有所体会,现在是来理解后一句的时候了. 安装DirectX SDK配置啥的就不说了,直接进入正题,先来个典型的Direct3D程序框架图: 主要分为5个部分: 创建一个Windows窗口 Direct3D的初始化 消息循环 渲染图形 结束应用程序,清除在初始化阶段锁创建的COM对象,退出程序 至于COM (Component Object Model, 组件对象模型)

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记10——三维天空的构建&三维粒子的实现&多游戏模型的载入

第23章 三维天空的构建 目前描述三维天空的技术主要包括三种类型,直接来介绍使用最广泛的模拟技术,详细的描述可以见作者的博文. 天空盒(Sky Box),即放到场景的是一个立方体.它是目前使用最广泛的三维天空模拟技术,网络上素材丰富,所以这次就用教大家用天空盒来模拟三维天空.天空盒经常是由24个顶点.六个面组成的立方体(或者直接从做好的X模型文件载入天空盒),并经常会随着视点的移动而移动,来刻画极远处玩家无法达到位置的天空 天空盒的设计 1.准备天空盒纹理素材 天空盒的纹理自然就是我们这个天空盒

《逐梦旅程 WINDOWS游戏编程之从零开始》读书笔记1——创建窗口

步骤: 窗口类的设计 窗口类的注册 窗口的正式创建 窗口的显示与更新 1. 设计:使用WNDCLASSEX结构体,这里注意的是C++中的结构体中的成员默认是共有的,所以可以直接通过 . 来调用. typedef struct tagWNDCLASSEX { UINT cbSize; //UINT类型的cbSize,表示该结构体的字节数大小 UINT style; //指定窗口的风格样式 WNDPROC lpfnWndProc; //指向窗口过程函数的函数指针 int cbClsExtra; //

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记7——四大变换

第13章 世界变换,取景变换,投影变换,视口变换 在Direct3D中,如果为进行任何空间坐标变换而直接绘图的话,图形将始终处于应用程序窗口的中心位置,默认这个位置就成为世界坐标系的原点(0,0,0).而且我们也不能改变观察图形的视角方向.默认情况下的观察方向是世界坐标系的z轴正向方向. 世界变换运算是为了能在世界空间中的指定位置来绘制图形 取景变换运算是为了以不同的视角观察图形 投影变换为了将相对较远的图形投影到同一个平面上并体现出"近大远小"的真实视觉效果 视口变换是为了控制显示图

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记8——载入三维模型&Alpha混合技术&深度测试与Z缓存

第17章 三维游戏模型的载入 主要是如何从3ds max中导出.X文件,以及如何从X文件加载三维模型到DirextX游戏程序里.因为复杂的3D物体,要用代码去实现,那太反人类了,所以我们需要一些建模软件. 对于3ds max,要到出.X文件,要装个Panda插件.然后就是作者推荐的一个3D模型资源网站:http://www.cgmodel.com/. 网格模型接口ID3DXMesh 这个接口表示网格,继承自ID3DXBaseMesh.ID3DXMesh接口中的D3DXCreateMesh()可用

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记8——光照与材质

第14章 绘制出质感的世界--光照与材质 1. 光照与光源 在Direct3D中的光源类型和光照类型是不同的两个概念,光照模型描述的是光线的反射特征,而光源类型主要强调的是能够产生这些光照模型的方式以及光线的位置,方向,强度等特征. 四大光照类型 环境光:基于整个自然界环境的整体亮度,称为环境光或者背景光,没有位置或者方向上的特征,只有一个颜色亮度值,不会衰减,在所有方向和所有物体表面上投射的环境光的数量是恒定不变的(有点像我们白天的自然光).在Direc3D中设置环境光可以直接使用setRen

《逐梦旅程 WINDOWS游戏编程之从零开始》源码分析2——GDI

GDI: 图形设备接口 1. 取得设备环境的句柄(如屏幕) 使用BeginPaint和EndPaint这两个函数,或者使用GetDC和ReleaseDC这两个函数.关于函数的具体说明可以参考mdsn文档. 一个GDI程序通用框架: 1 #include <windows.h> 2 3 #define WINDOW_WIDTH 800 //为窗口宽度定义的宏,以方便在此处修改窗口宽度 4 #define WINDOW_HEIGHT 600 //为窗口高度定义的宏,以方便在此处修改窗口高度 5 #

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记9——游戏摄像机&amp;三维地形的构建

第21章 游戏摄像机的构建 之前的程序示例,都是通过封装的DirectInput类来处理键盘和鼠标的输入,对应地改变我们人物模型的世界矩阵来达到移动物体,改变观察点的效果.其实我们的观察方向乃至观察点都是没有变的,变的只是我们3D人物的位置.说白了就是用D3DXMatrixLookAtLH在资源初始化时固定住视角,在程序运行过程中接收到消息并改变三维人物模型的世界矩阵而已.这章的主要内容就是创建出一个可以在三维空间中自由移动的摄像机类,我们准备给这个摄像机类取名为CameraClass. 设计摄