用DirectX绘制使用纹理的立方体

下面将学习DirectX的3D渲染基础部分,但不会对3D数学或图形理论有太详细的介绍。 首先要了解DirectX中的坐标系,要记住的是DirectX采用左手坐标系。

在Direct3D中渲染一个场景,涉及到的三维变换有:世界变换、视图变换、投影变换。

世界变换:三维变换的第一步就是将模型的顶点的局部坐标变换到所有对象都共享的一个坐标系中,也就是从模型空间向世界空间转换。变换到的新的坐标系称为世界坐标系。世界坐标系中的每一个顶点的坐标都以世界坐标系来表示。根据需要,应该将物体进行缩放、旋转、平移后放置到我们想要的位置。

视图变换:又称为观察变换,即如照相机一般,表示用户在屏幕上看到的内容。我们在世界坐标系中选择一个观察点,世界坐标系将被重新定位到这个观察点的视野中,也就是从世界坐标空间向观察空间的转换。需要注意的是,观察变换实际上是坐标系的变换。但是,Direct3D在处理时是对物体顶点进行矩阵变换,所以观察矩阵需要执行与视点变换相反的变换。例如,我们希望视点沿着z轴负方向移动5个单位,那么相对的就是顶点向z轴正方向移动5个单位。

投影变换:这是最后一步,在这里将视图变换的结果投影到屏幕上形成2D图像。视景体(field of view, FOV)用于定义在某个特定的位置能够看到的物体的范围,又称为视锥体或观察体。视景体在三维空间由6个面组成,以你的眼睛为视点向前看,依次是投影平面、近平面、远平面。典型的投影变换包括缩放和透视投影。投影变换将视景体变换为一个立方体。因为视景体的近端比远端小,所以会在投影平面上产生了离摄像机近的物体就被放大的效果。

除此之外,还要理解一些常见的术语,比如顶点缓存、索引缓存、深度缓存、模板缓存、交换链、多重采样、着色器、HLSL,下面将会简要介绍。

DirectX是一种基于COM(Component Object Model,组件对象模型)的系统,它既不属于驱动程序层,也不属于应用层。DirectX的主要设计目标是提供某种设备的独立性的同时获取很高的速度。COM使Direct3D独立于编程语言和具有向下兼容性,通常把COM对象作为一个接口,可以把它当做达到某种目的的C++类来使用,COM接口都具有前缀大写字母I表示,比如接口ID3DTexture2D。在DirectX的体系结构中,处于DirectX下层的是HAL(Hardware Abstract Layer,硬件抽象层)与HEL(Hardware Emulation Layer,硬件模拟层)。HAL负责检测本机的硬件功能,并以一种独立于设备的方式提供这些功能。HEL负责提供DirectX功能中本机硬件不支持部分的软件模拟实现。从DirectX 8.0起,DirectX就不再提供硬件模拟层HEL模块了,最新的DirectX 11要求硬件必须实现全部DirectX 11的特性,因此现在的DirectX是严重依赖于硬件的。Direct3D是一种低层的图形API,它能让我们利用三维硬件加速来渲染三维世界,可以被看成应用程序和图形设备之间的中介。

这里必须提到的是,DirectX 9中采用固定图像渲染管线,而DirectX 10与DirectX 11都放弃了固定的渲染管线,可以通过着色器代码改变渲染管线的过程。 在DirectX 9中,提供了两个独立的着色器:顶点着色器与像素着色器,在硬件中有各自的实现,不能通用。而从DirectX 10起,Shader Model 4.0提出了通用着色器的概念,即硬件上仅仅实现一种着色器,每一个着色阶段都利用通用着色器实现核心功能,每个特定的着色阶段都提供各自的额外功能。在通用着色器中,无论是常数、纹理或是缓存都被视为同样的资源直接或者通过采样器传递给着色器代码进行处理,HLSL便是DirectX使用的着色语言,类似C语言。

顶点着色器:顶点着色阶段将顶点作为输入集,负责处理“逐顶点”的操作,如坐标变换、蒙皮、动画以及顶点光照。顶点着色器的工作是处理一个独立的输入顶点并产生一个独立的输出顶点。顶点着色阶段在渲染管线中必须激活,即便没有对顶点做任何修改,也必须提供一个“不做任何修改”的顶点着色器才能保证渲染管线的正常工作。

几何着色器:这时由Direct3D 10引入的新的着色阶段,用来在已知的输入顶点的基础上生成新的输入顶点。和顶点着色器不同的是,顶点着色器仅仅处理独立的顶点,而几何着色器的输入则是一个图元(两个顶点的线段、三个顶点的三角形、一个顶点的独立点等),也可以将顶点的邻接点作为输入。

像素着色器:可以实现丰富的着色技术如逐像素光照和后期处理等。像素着色器可以通过常量、贴图、插值以及其他数据来产生逐像素的输出值。光栅处理器对每一个图元中的每一个像素都会执行一次像素着色器,但是也可以通过程序设置跳过像素着色器的执行。

计算着色器:是Direct3D 11引入的新着色器,独立于渲染管线之外,和其他着色器一样使用着色器语言实现。计算着色器提供了利用GPU中大量并行处理器进行高速通用计算的能力。

Direct3D管线中用到的所有资源可分为缓存(buffer)资源和纹理(texture)资源。缓存资源是指一组指定类型的数据的集合,分为顶点缓存、索引缓存、常量缓存。顶点缓存用于存储顶点数据,包括顶点的位置、法线、纹理坐标。纹理资源是一种结构,用于存储纹理。Direct3D有三种纹理类型:一维、二维和三维纹理。一维纹理指只在某一方向上变化,相当于高度为1的二维纹理;二维纹理是指纹理在相互垂直的两个方向上变化,用u表示横向纹理,v表示纵向纹理;三维纹理,其纹理单元为三维纹理体,每个纹理单元用u、v、w向量表示。多重纹理是指事先制定一系列分辨率逐渐减小的纹理图像,纹理采用mipmap方式自动生成,即每个层次的纹理细节(LOD)为小于上一级纹理平方根大小,Direct3D会根据所映射的物体尺寸自动选择使用哪个分辨率的纹理图。

Direct3D维护着两个纹理缓存,前台缓存(Front Buffer)和后台缓存(Back Buffer)。前台缓存存储着当前显示在屏幕上的图像数据,下一帧的动画则被绘制在后台缓存上。为了避免动画的闪动,当帧的整个场景在后台缓存中绘制好后,后台缓存和前台缓存就互相交换,这样后台缓存中的内容才被完整地呈现在屏幕上。前台缓存与后台缓存组成了交换链

深度缓存是一个只包含特定像素深度信息而不包含图像数据的纹理。深度值的范围为[0,1],0表示能被观察者看到的最近的位置,1表示能被观察者看到的最远的位置。为了理解这个概念,设想这样一个场景,一个圆圈环绕着一个立方体,显然圆圈会遮挡一部分的立方体,该如何绘制场景了?如果采用传统的画家算法,先画什么,再画什么就不行了。Direct3D在像素级别上提供了一个很好的解决方案,它使用一种叫深度缓存,又叫z-buffer的技术。深度缓存保存着每个像素的深度值,也叫z值,在绘制场景时按深度值绘制就可以了。

用像素矩阵表示的图像通常会出现“阶梯效应”,比如一条线段的边缘产生了锯齿,发生走样。这里要采用反走样技术,通过采集并使用线段中的点周围的一些像素,减少图像的阶梯效应。Direct3D支持一种称为多重采样的反走样技术,它使用目标像素周围的一些点来生成该像素点的最终颜色。由于这个过程使用了多个像素采样,所以叫多重采样。

实际的模型可以分为很多个三角形,这些三角形有大量的重复顶点和重复边。如果在顶点缓存中重复保存这些顶点信息,那么显卡将耗费比实际模型体积大得多的空间来保存模型信息。这里必须引入索引缓存的概念,它不能脱离顶点缓存而独立存在。我们需要建立一个顶点缓存,比如一个立方体,顶点缓存中只需要保存8个顶点的信息。除此之外,还需要建立一个缓存来确定每一个顶点对应顶点缓存中的哪一个顶点,这就是索引缓存

模板是一块特殊的缓存区,称为模板缓存(Stencil Buffer)。模板缓存的作用是限定哪些像素将被绘制到屏幕上而哪些不会。因为模板缓存的容量很小,因此在实际的硬件实现中,并没有一个独立的模板缓存,而是将深度缓存和模板缓存合并成一个深度模板缓存(Depth Stencil Buffer),其中每一个像素的前24位用作深度缓存,而后8位用于模板缓存。

Direct3D使用由用户自定义的顶点格式,下面是我们将要使用的结构VERTEX。前三个成员变量是顶点的位置,而tu和tv用于表达使用的纹理的坐标,可以使用tu=0.0、tv=0.0指定纹理左上角,tu=1.0、tv=1.0指定纹理右下角。

struct VERTEX
{
    float x, y, z;
    float tu, tv;
};

 

我们要创建一个四边形,所以需要这样一个结构QUAD,显然vertices保存四个顶点,buffer为顶点缓存,texture为用于着色的纹理贴图。

struct QUAD
{
    VERTEX vertices[4];
    LPDIRECT3DVERTEXBUFFER9 buffer;
    LPDIRECT3DTEXTURE9 texture;
};

 

基础部分暂时讲到这里,下面看一个例子,还是基于前面的例子,只有game.cpp文件改变了,也是唯一重要的文件。

DirectSound.h

复制代码
  1 //-----------------------------------------------------------------------------
  2 // File: DSUtil.h
  3 //
  4 // Desc: 
  5 //
  6 // Copyright (c) Microsoft Corp. All rights reserved.
  7 //-----------------------------------------------------------------------------
  8 //
  9 // Note: This file has been edited for use in Beginning Game Programming, Third Edition,
 10 // originally distributed with a 2004 release of DirectX 9.0c SDK.
 11 //
 12 
 13 #ifndef DSUTIL_H
 14 #define DSUTIL_H
 15 
 16 #include <windows.h>
 17 #include <mmsystem.h>
 18 #include <mmreg.h>
 19 #include <dsound.h>
 20 #include <dxerr.h>
 21 
 22 #pragma comment(lib, "dxerr.lib")
 23 #pragma comment(lib, "dsound.lib")
 24 
 25 
 26 //-----------------------------------------------------------------------------
 27 // Classes used by this header
 28 //-----------------------------------------------------------------------------
 29 class CSoundManager;
 30 class CSound;
 31 class CStreamingSound;
 32 class CWaveFile;
 33 
 34 
 35 
 36 
 37 //-----------------------------------------------------------------------------
 38 // Typing macros 
 39 //-----------------------------------------------------------------------------
 40 #define WAVEFILE_READ   1
 41 #define WAVEFILE_WRITE  2
 42 
 43 #define DSUtil_StopSound(s)         { if(s) s->Stop(); }
 44 #define DSUtil_PlaySound(s)         { if(s) s->Play( 0, 0 ); }
 45 #define DSUtil_PlaySoundLooping(s)  { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
 46 
 47 
 48 
 49 
 50 //-----------------------------------------------------------------------------
 51 // Name: class CSoundManager
 52 // Desc: 
 53 //-----------------------------------------------------------------------------
 54 class CSoundManager
 55 {
 56 protected:
 57     LPDIRECTSOUND8 m_pDS;
 58 
 59 public:
 60     CSoundManager();
 61     ~CSoundManager();
 62 
 63     HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel );
 64 
 65     inline  LPDIRECTSOUND8 GetDirectSound() { return m_pDS; }
 66 
 67     HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, 
 68         DWORD dwPrimaryBitRate );
 69 
 70     HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0,
 71         GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
 72 };
 73 
 74 
 75 
 76 
 77 //-----------------------------------------------------------------------------
 78 // Name: class CSound
 79 // Desc: Encapsulates functionality of a DirectSound buffer.
 80 //-----------------------------------------------------------------------------
 81 class CSound
 82 {
 83 protected:
 84     LPDIRECTSOUNDBUFFER* m_apDSBuffer;
 85     DWORD                m_dwDSBufferSize;
 86     CWaveFile*           m_pWaveFile;
 87     DWORD                m_dwNumBuffers;
 88     DWORD                m_dwCreationFlags;
 89 
 90     HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
 91 
 92 public:
 93     CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers,
 94         CWaveFile* pWaveFile, DWORD dwCreationFlags );
 95     virtual ~CSound();
 96 
 97     HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
 98     LPDIRECTSOUNDBUFFER GetFreeBuffer();
 99 
100     HRESULT Play( DWORD dwPriority = 0, DWORD dwFlags = 0, LONG lVolume = 0, 
101         LONG lFrequency = -1, LONG lPan = 0 );
102     HRESULT Stop();
103     HRESULT Reset();
104     BOOL    IsSoundPlaying();
105 };
106 
107 
108 //-----------------------------------------------------------------------------
109 // Name: class CWaveFile
110 // Desc: Encapsulates reading or writing sound data to or from a wave file
111 //-----------------------------------------------------------------------------
112 class CWaveFile
113 {
114 public:
115     WAVEFORMATEX* m_pwfx;        // Pointer to WAVEFORMATEX structure
116     HMMIO         m_hmmio;       // MM I/O handle for the WAVE
117     MMCKINFO      m_ck;          // Multimedia RIFF chunk
118     MMCKINFO      m_ckRiff;      // Use in opening a WAVE file
119     DWORD         m_dwSize;      // The size of the wave file
120     MMIOINFO      m_mmioinfoOut;
121     DWORD         m_dwFlags;
122     BOOL          m_bIsReadingFromMemory;
123     BYTE*         m_pbData;
124     BYTE*         m_pbDataCur;
125     ULONG         m_ulDataSize;
126     CHAR*         m_pResourceBuffer;
127 
128 protected:
129     HRESULT ReadMMIO();
130     HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
131 
132 public:
133     CWaveFile();
134     ~CWaveFile();
135 
136     HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
137     HRESULT Close();
138 
139     HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
140     HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
141 
142     DWORD   GetSize();
143     HRESULT ResetFile();
144     WAVEFORMATEX* GetFormat() { return m_pwfx; };
145 };
146 
147 
148 
149 
150 #endif // DSUTIL_H
复制代码

 

DirectSound.cpp

View Code

 

DirectX.h

复制代码
  1 #pragma once
  2 
  3 //header files
  4 #define WIN32_EXTRA_LEAN
  5 #define DIRECTINPUT_VERSION 0x0800
  6 #include <windows.h>
  7 #include <d3d9.h>
  8 #include <d3dx9.h>
  9 #include <dxerr.h>
 10 #include <dinput.h>
 11 #include <xinput.h>
 12 #include <ctime>
 13 #include <iostream>
 14 #include <iomanip>
 15 #include "DirectSound.h"
 16 using namespace std;
 17 
 18 //libraries
 19 #pragma comment(lib,"winmm.lib")
 20 #pragma comment(lib,"user32.lib")
 21 #pragma comment(lib,"gdi32.lib")
 22 #pragma comment(lib,"dxguid.lib")
 23 #pragma comment(lib,"d3d9.lib")
 24 #pragma comment(lib,"d3dx9.lib")
 25 #pragma comment(lib, "dxerr.lib")
 26 #pragma comment(lib,"dinput8.lib")
 27 #pragma comment(lib,"xinput.lib")
 28 
 29 //program values
 30 extern const string APPTITLE;
 31 extern const int SCREENW;
 32 extern const int SCREENH;
 33 extern bool gameover;
 34 
 35 //macro to detect key presses
 36 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
 37 
 38 //Direct3D objects
 39 extern LPDIRECT3D9 d3d; 
 40 extern LPDIRECT3DDEVICE9 d3ddev; 
 41 extern LPDIRECT3DSURFACE9 backbuffer;
 42 extern LPD3DXSPRITE spriteobj;
 43 
 44 //DirectSound object
 45 extern CSoundManager *dsound;
 46 
 47 //sprite structure
 48 struct SPRITE
 49 {
 50     float x,y;
 51     int frame, columns;
 52     int width, height;
 53     float scaling, rotation;
 54     int startframe, endframe;
 55     int starttime, delay;
 56     int direction;
 57     float velx, vely;
 58     D3DCOLOR color;
 59 
 60     SPRITE() 
 61     {
 62         frame = 0;
 63         columns = 1;
 64         width = height = 0;
 65         scaling = 1.0f;
 66         rotation = 0.0f;
 67         startframe = endframe = 0;
 68         direction = 1;
 69         starttime = delay = 0;
 70         velx = vely = 0.0f;
 71         color = D3DCOLOR_XRGB(255,255,255);
 72     }
 73 };
 74 
 75 //Direct3D functions
 76 bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen);
 77 void Direct3D_Shutdown();
 78 LPDIRECT3DSURFACE9 LoadSurface(string filename);
 79 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);
 80 LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));
 81 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, 
 82     int framenum, int framew, int frameh, int columns);
 83 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay);
 84 
 85 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, 
 86     int frame = 0, int columns = 1, float rotation = 0.0f, float scaling = 1.0f, 
 87     D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));
 88 
 89 //bounding box collision detection
 90 int Collision(SPRITE sprite1, SPRITE sprite2);
 91 
 92 //distance based collision detection
 93 bool CollisionD(SPRITE sprite1, SPRITE sprite2);
 94 
 95 //DirectInput objects, devices, and states
 96 extern LPDIRECTINPUT8 dinput;
 97 extern LPDIRECTINPUTDEVICE8 dimouse;
 98 extern LPDIRECTINPUTDEVICE8 dikeyboard;
 99 extern DIMOUSESTATE mouse_state;
100 extern XINPUT_GAMEPAD controllers[4];
101 
102 //DirectInput functions
103 bool DirectInput_Init(HWND);
104 void DirectInput_Update();
105 void DirectInput_Shutdown();
106 bool Key_Down(int);
107 int Mouse_Button(int);
108 int Mouse_X();
109 int Mouse_Y();
110 void XInput_Vibrate(int contNum = 0, int amount = 65535);
111 bool XInput_Controller_Found();
112 
113 //game functions
114 bool Game_Init(HWND window);
115 void Game_Run(HWND window);
116 void Game_End();
117 
118 
119 //font functions
120 LPD3DXFONT MakeFont(string name, int size);
121 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));
122 
123 //DirectSound functions
124 bool DirectSound_Init(HWND hwnd);
125 void DirectSound_Shutdown();
126 CSound* LoadSound(string filename);
127 void PlaySound(CSound *sound);
128 void LoopSound(CSound *sound);
129 void StopSound(CSound *sound);
复制代码

 

DirectX.cpp

复制代码
  1 #include "DirectX.h"
  2 #include <iostream>
  3 #include <string>
  4 using namespace std;
  5 
  6 //DirectSound object
  7 CSoundManager *dsound = NULL;
  8 
  9 //Direct3D variables
 10 LPDIRECT3D9 d3d = NULL; 
 11 LPDIRECT3DDEVICE9 d3ddev = NULL; 
 12 LPDIRECT3DSURFACE9 backbuffer = NULL;
 13 LPD3DXSPRITE spriteobj;
 14 
 15 //DirectInput variables
 16 LPDIRECTINPUT8 dinput = NULL;
 17 LPDIRECTINPUTDEVICE8 dimouse = NULL;
 18 LPDIRECTINPUTDEVICE8 dikeyboard = NULL;
 19 DIMOUSESTATE mouse_state;
 20 char keys[256];
 21 XINPUT_GAMEPAD controllers[4];
 22 
 23 
 24 bool Direct3D_Init(HWND window, int width, int height, bool fullscreen)
 25 {
 26     //initialize Direct3D
 27     d3d = Direct3DCreate9(D3D_SDK_VERSION);
 28     if (!d3d) return false;
 29 
 30     //set Direct3D presentation parameters
 31     D3DPRESENT_PARAMETERS d3dpp; 
 32     ZeroMemory(&d3dpp, sizeof(d3dpp));
 33     d3dpp.hDeviceWindow = window;
 34     d3dpp.Windowed = (!fullscreen);
 35     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
 36     d3dpp.EnableAutoDepthStencil = 1;
 37     d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
 38     d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
 39     d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
 40     d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
 41     d3dpp.BackBufferCount = 1;
 42     d3dpp.BackBufferWidth = width;
 43     d3dpp.BackBufferHeight = height;
 44 
 45     //create Direct3D device
 46     d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
 47         D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
 48     if (!d3ddev) return false;
 49 
 50 
 51     //get a pointer to the back buffer surface
 52     d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
 53 
 54     //create sprite object
 55     D3DXCreateSprite(d3ddev, &spriteobj);
 56 
 57     return 1;
 58 }
 59 
 60 void Direct3D_Shutdown()
 61 {
 62     if (spriteobj) spriteobj->Release();
 63 
 64     if (d3ddev) d3ddev->Release();
 65     if (d3d) d3d->Release();
 66 }
 67 
 68 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source)
 69 {
 70     //get width/height from source surface
 71     D3DSURFACE_DESC desc;
 72     source->GetDesc(&desc);
 73 
 74     //create rects for drawing
 75     RECT source_rect = {0, 0, (long)desc.Width, (long)desc.Height };
 76     RECT dest_rect = { (long)x, (long)y, (long)x+desc.Width, (long)y+desc.Height};
 77     
 78     //draw the source surface onto the dest
 79     d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE);
 80 
 81 }
 82 
 83 LPDIRECT3DSURFACE9 LoadSurface(string filename)
 84 {
 85     LPDIRECT3DSURFACE9 image = NULL;
 86     
 87     //get width and height from bitmap file
 88     D3DXIMAGE_INFO info;
 89     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
 90     if (result != D3D_OK)
 91         return NULL;
 92 
 93     //create surface
 94     result = d3ddev->CreateOffscreenPlainSurface(
 95         info.Width,         //width of the surface
 96         info.Height,        //height of the surface
 97         D3DFMT_X8R8G8B8,    //surface format
 98         D3DPOOL_DEFAULT,    //memory pool to use
 99         &image,             //pointer to the surface
100         NULL);              //reserved (always NULL)
101 
102     if (result != D3D_OK) return NULL;
103 
104     //load surface from file into newly created surface
105     result = D3DXLoadSurfaceFromFile(
106         image,                  //destination surface
107         NULL,                   //destination palette
108         NULL,                   //destination rectangle
109         filename.c_str(),       //source filename
110         NULL,                   //source rectangle
111         D3DX_DEFAULT,           //controls how image is filtered
112         D3DCOLOR_XRGB(0,0,0),   //for transparency (0 for none)
113         NULL);                  //source image info (usually NULL)
114 
115     //make sure file was loaded okay
116     if (result != D3D_OK) return NULL;
117 
118     return image;
119 }
120 
121 
122 LPDIRECT3DTEXTURE9 LoadTexture(std::string filename, D3DCOLOR transcolor)
123 {  
124     LPDIRECT3DTEXTURE9 texture = NULL;
125 
126     //get width and height from bitmap file
127     D3DXIMAGE_INFO info;
128     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
129     if (result != D3D_OK) return NULL;
130 
131     //create the new texture by loading a bitmap image file
132     D3DXCreateTextureFromFileEx( 
133         d3ddev,                //Direct3D device object
134         filename.c_str(),      //bitmap filename
135         info.Width,            //bitmap image width
136         info.Height,           //bitmap image height
137         1,                     //mip-map levels (1 for no chain)
138         D3DPOOL_DEFAULT,       //the type of surface (standard)
139         D3DFMT_UNKNOWN,        //surface format (default)
140         D3DPOOL_DEFAULT,       //memory class for the texture
141         D3DX_DEFAULT,          //image filter
142         D3DX_DEFAULT,          //mip filter
143         transcolor,            //color key for transparency
144         &info,                 //bitmap file info (from loaded file)
145         NULL,                  //color palette
146         &texture );            //destination texture
147 
148     //make sure the bitmap textre was loaded correctly
149     if (result != D3D_OK) return NULL;
150 
151     return texture;
152 }
153 
154 
155 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, int framenum, int framew, int frameh, int columns)
156 {
157     D3DXVECTOR3 position( (float)destx, (float)desty, 0 );
158     D3DCOLOR white = D3DCOLOR_XRGB(255,255,255);
159 
160     RECT rect;
161      rect.left = (framenum % columns) * framew;
162     rect.top = (framenum / columns) * frameh;
163     rect.right = rect.left + framew;
164     rect.bottom = rect.top + frameh;
165 
166     spriteobj->Draw( texture, &rect, NULL, &position, white);
167 }
168 
169 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay)
170 {
171     if ((int)GetTickCount() > starttime + delay)
172     {
173         starttime = GetTickCount();
174 
175         frame += direction;
176         if (frame > endframe) frame = startframe;
177         if (frame < startframe) frame = endframe;
178     }    
179 }
180 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, 
181     int frame, int columns, float rotation, float scaling, D3DCOLOR color)
182 {
183     //create a scale vector
184     D3DXVECTOR2 scale( scaling, scaling );
185 
186     //create a translate vector
187     D3DXVECTOR2 trans( x, y );
188 
189     //set center by dividing width and height by two
190     D3DXVECTOR2 center( (float)( width * scaling )/2, (float)( height * scaling )/2);
191 
192     //create 2D transformation matrix
193     D3DXMATRIX mat;
194     D3DXMatrixTransformation2D( &mat, NULL, 0, &scale, &center, rotation, &trans );
195     
196     //tell sprite object to use the transform
197     spriteobj->SetTransform( &mat );
198 
199     //calculate frame location in source image
200     int fx = (frame % columns) * width;
201     int fy = (frame / columns) * height;
202     RECT srcRect = {fx, fy, fx + width, fy + height};
203 
204     //draw the sprite frame
205     spriteobj->Draw( image, &srcRect, NULL, NULL, color );
206 }
207 
208 //bounding  box collision detection
209 int Collision(SPRITE sprite1, SPRITE sprite2)
210 {
211     RECT rect1;
212     rect1.left = (long)sprite1.x;
213     rect1.top = (long)sprite1.y;
214     rect1.right = (long)sprite1.x + sprite1.width * sprite1.scaling;
215     rect1.bottom = (long)sprite1.y + sprite1.height * sprite1.scaling;
216 
217     RECT rect2;
218     rect2.left = (long)sprite2.x;
219     rect2.top = (long)sprite2.y;
220     rect2.right = (long)sprite2.x + sprite2.width * sprite2.scaling;
221     rect2.bottom = (long)sprite2.y + sprite2.height * sprite2.scaling;
222 
223     RECT dest; //ignored
224     return IntersectRect(&dest, &rect1, &rect2);
225 }
226 
227 
228 bool CollisionD(SPRITE sprite1, SPRITE sprite2)
229 {
230     double radius1, radius2;
231 
232     //calculate radius 1
233     if (sprite1.width > sprite1.height)
234         radius1 = (sprite1.width * sprite1.scaling) / 2.0;
235     else
236         radius1 = (sprite1.height * sprite1.scaling) / 2.0;
237 
238     //center point 1
239     double x1 = sprite1.x + radius1;
240     double y1 = sprite1.y + radius1;
241     D3DXVECTOR2 vector1(x1, y1);
242 
243     //calculate radius 2
244     if (sprite2.width > sprite2.height)
245         radius2 = (sprite2.width * sprite2.scaling) / 2.0;
246     else
247         radius2 = (sprite2.height * sprite2.scaling) / 2.0;
248 
249     //center point 2
250     double x2 = sprite2.x + radius2;
251     double y2 = sprite2.y + radius2;
252     D3DXVECTOR2 vector2(x2, y2);
253 
254     //calculate distance
255     double deltax = vector1.x - vector2.x;
256     double deltay = vector2.y - vector1.y;
257     double dist = sqrt((deltax * deltax) + (deltay * deltay));
258 
259     //return distance comparison
260     return (dist < radius1 + radius2);
261 }
262 
263 bool DirectInput_Init(HWND hwnd)
264 {
265     //initialize DirectInput object
266     DirectInput8Create(
267         GetModuleHandle(NULL), 
268         DIRECTINPUT_VERSION, 
269         IID_IDirectInput8,
270         (void**)&dinput,
271         NULL);
272 
273     //initialize the keyboard
274     dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL);
275     dikeyboard->SetDataFormat(&c_dfDIKeyboard);
276     dikeyboard->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
277     dikeyboard->Acquire();
278 
279     //initialize the mouse
280     dinput->CreateDevice(GUID_SysMouse, &dimouse, NULL);
281     dimouse->SetDataFormat(&c_dfDIMouse);
282     dimouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
283     dimouse->Acquire();
284     d3ddev->ShowCursor(false);
285 
286     return true;
287 }
288 
289 void DirectInput_Update()
290 {
291     //update mouse
292     dimouse->Poll();
293     if (!SUCCEEDED(dimouse->GetDeviceState(sizeof(DIMOUSESTATE),&mouse_state)))
294     {
295         //mouse device lose, try to re-acquire
296         dimouse->Acquire();
297     }
298 
299     //update keyboard
300     dikeyboard->Poll();
301     if (!SUCCEEDED(dikeyboard->GetDeviceState(256,(LPVOID)&keys)))
302     {
303         //keyboard device lost, try to re-acquire
304         dikeyboard->Acquire();
305     }
306 
307     //update controllers
308     for (int i=0; i< 4; i++ )
309     {
310         ZeroMemory( &controllers[i], sizeof(XINPUT_STATE) );
311 
312         //get the state of the controller
313         XINPUT_STATE state;
314         DWORD result = XInputGetState( i, &state );
315 
316         //store state in global controllers array
317         if (result == 0) controllers[i] = state.Gamepad;
318     }
319 }
320 
321 
322 int Mouse_X()
323 {
324     return mouse_state.lX;
325 }
326 
327 int Mouse_Y()
328 {
329     return mouse_state.lY;
330 }
331 
332 int Mouse_Button(int button)
333 {
334     return mouse_state.rgbButtons[button] & 0x80;
335 }
336 
337 bool Key_Down(int key) 
338 {
339     return (bool)(keys[key] & 0x80);
340 }
341 
342 
343 void DirectInput_Shutdown()
344 {
345     if (dikeyboard) 
346     {
347         dikeyboard->Unacquire();
348         dikeyboard->Release();
349         dikeyboard = NULL;
350     }
351     if (dimouse) 
352     {
353         dimouse->Unacquire();
354         dimouse->Release();
355         dimouse = NULL;
356     }
357 }
358 
359 bool XInput_Controller_Found()
360 {
361     XINPUT_CAPABILITIES caps;
362     ZeroMemory(&caps, sizeof(XINPUT_CAPABILITIES));
363     XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps);
364     if (caps.Type != 0) return false;
365     
366     return true;
367 }
368 
369 void XInput_Vibrate(int contNum, int amount)
370 {
371     XINPUT_VIBRATION vibration;
372     ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) );
373     vibration.wLeftMotorSpeed = amount;
374     vibration.wRightMotorSpeed = amount; 
375     XInputSetState( contNum, &vibration );
376 }
377 
378 LPD3DXFONT MakeFont(string name, int size)
379 {
380     LPD3DXFONT font = NULL;
381 
382     D3DXFONT_DESC desc = {
383         size,                   //height
384         0,                      //width
385         0,                      //weight
386         0,                      //miplevels
387         false,                  //italic
388         DEFAULT_CHARSET,        //charset
389         OUT_TT_PRECIS,          //output precision
390         CLIP_DEFAULT_PRECIS,    //quality
391         DEFAULT_PITCH,          //pitch and family
392         ""                      //font name
393     };
394 
395     strcpy(desc.FaceName, name.c_str());
396 
397     D3DXCreateFontIndirect(d3ddev, &desc, &font);
398 
399     return font;
400 }
401 
402 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color)
403 {
404     //figure out the text boundary
405     RECT rect = { x, y, 0, 0 };
406     font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color); 
407 
408     //print the text
409     font->DrawText(spriteobj, text.c_str(), text.length(), &rect, DT_LEFT, color); 
410 }
411 
412 bool DirectSound_Init(HWND hwnd)
413 {
414     //create DirectSound manager object
415     dsound = new CSoundManager();
416 
417     //initialize DirectSound
418     HRESULT result;
419     result = dsound->Initialize(hwnd, DSSCL_PRIORITY);
420     if (FAILED(result))
421         return false;
422 
423     //set the primary buffer format
424     result = dsound->SetPrimaryBufferFormat(2, 22050, 16);
425     if (FAILED(result))
426         return false;
427 
428     return true;
429 }
430 
431 void DirectSound_Shutdown()
432 {
433     if (dsound)
434         delete dsound;
435 }
436 
437 CSound* LoadSound(string filename)
438 {
439     HRESULT result;
440 
441     //create local reference to wave data
442     CSound *wave = NULL;
443 
444     //attempt to load the wave file
445     char s[255];
446     sprintf(s, "%s", filename.c_str());
447     result = dsound->Create(&wave, s);
448     if (FAILED(result))
449         wave = NULL;
450 
451     return wave;
452 }
453 
454 void PlaySound(CSound *sound)
455 {
456     sound->Play();
457 }
458 
459 void LoopSound(CSound *sound)
460 {
461     sound->Play(0, DSBPLAY_LOOPING);
462 }
463 
464 void StopSound(CSound *sound)
465 {
466     sound->Stop();
467 }
复制代码

 

main.cpp

复制代码
 1 #include "DirectX.h"
 2 using namespace std;
 3 
 4 bool gameover = false;
 5 
 6 //windows event handling function
 7 LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 8 {
 9     switch (message)
10     {
11     case WM_DESTROY:
12         gameover = true;
13         PostQuitMessage(0);
14         return 0;
15     }
16 
17     return DefWindowProc(hwnd, message, wParam, lParam);
18 }
19 
20 
21 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
22 {
23     //set the windows properties
24     WNDCLASSEX wc;
25     wc.cbSize = sizeof(WNDCLASSEX);
26     wc.style = CS_HREDRAW | CS_VREDRAW;
27     wc.lpfnWndProc = (WNDPROC)WinProc;
28     wc.cbClsExtra = 0;
29     wc.cbWndExtra = 0;
30     wc.hInstance = hInstance;
31     wc.hIcon = NULL;
32     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
33     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
34     wc.lpszMenuName = NULL;
35     wc.lpszClassName = APPTITLE.c_str();
36     wc.hIconSm = NULL;
37     RegisterClassEx(&wc);
38 
39     //determine the resolution of the clients desktop screen
40     int screenWidth = GetSystemMetrics(SM_CXSCREEN);
41     int screenHeight = GetSystemMetrics(SM_CYSCREEN);
42 
43     //place the window in the middle of screen
44     int posX = (GetSystemMetrics(SM_CXSCREEN) - SCREENW) / 2;
45     int posY = (GetSystemMetrics(SM_CYSCREEN) - SCREENH) / 2;
46 
47     //Create a window
48     HWND window;
49     window = CreateWindow(APPTITLE.c_str(), APPTITLE.c_str(),
50         WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, posX, posY, SCREENW, SCREENH,
51         NULL, NULL, hInstance, NULL); 
52     if (window == 0)
53         return false;
54 
55     //display the window
56     ShowWindow(window, nCmdShow);
57     UpdateWindow(window);
58 
59     //initialize the game
60     if (!Game_Init(window))
61         return 0;
62 
63     //main message loop
64     MSG msg;
65     while (!gameover)
66     {
67         //process windows events
68         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
69         {
70             //handle any event messages
71             TranslateMessage(&msg);
72             DispatchMessage(&msg);
73         }
74 
75         //process game loop
76         Game_Run(window);
77     }
78 
79     //free game resources
80     Game_End();
81 
82     return msg.wParam;
83 }
复制代码

 

下面是game.cpp文件,先看开头部分。宏定义D3DFVF_MYVERTEX表示顶点流的类型,D3DFVF_XYZ与D3DFVF_TEX1分别代表顶点位置与纹理坐标。这里的cube数组是立方体的顶点信息,由6个面组成。

复制代码
 1 #include "DirectX.h"
 2 using namespace std;
 3 
 4 const string APPTITLE = "Direct3D Cube";
 5 const int SCREENW = 1024;
 6 const int SCREENH = 576;
 7 
 8 DWORD screentimer = timeGetTime();
 9 
10 //vertex and quad definitions
11 #define D3DFVF_MYVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
12 
13 struct VERTEX
14 {
15     float x, y, z;
16     float tu, tv;
17 };
18 
19 struct QUAD
20 {
21     VERTEX vertices[4];
22     LPDIRECT3DVERTEXBUFFER9 buffer;
23     LPDIRECT3DTEXTURE9 texture;
24 };
25 
26 VERTEX cube[] = {
27     {-1.0f, 1.0f,-1.0f, 0.0f,0.0f},     //side 1
28     { 1.0f, 1.0f,-1.0f, 1.0f,0.0f },
29     {-1.0f,-1.0f,-1.0f, 0.0f,1.0f },
30     { 1.0f,-1.0f,-1.0f, 1.0f,1.0f },
31     
32     {-1.0f, 1.0f, 1.0f, 1.0f,0.0f },    //side 2
33     {-1.0f,-1.0f, 1.0f, 1.0f,1.0f },
34     { 1.0f, 1.0f, 1.0f, 0.0f,0.0f },
35     { 1.0f,-1.0f, 1.0f, 0.0f,1.0f },
36     
37     {-1.0f, 1.0f, 1.0f, 0.0f,0.0f },    //side 3
38     { 1.0f, 1.0f, 1.0f, 1.0f,0.0f },
39     {-1.0f, 1.0f,-1.0f, 0.0f,1.0f },
40     { 1.0f, 1.0f,-1.0f, 1.0f,1.0f },
41     
42     {-1.0f,-1.0f, 1.0f, 0.0f,0.0f },    //side 4
43     {-1.0f,-1.0f,-1.0f, 1.0f,0.0f },
44     { 1.0f,-1.0f, 1.0f, 0.0f,1.0f },
45     { 1.0f,-1.0f,-1.0f, 1.0f,1.0f },
46 
47     { 1.0f, 1.0f,-1.0f, 0.0f,0.0f },    //side 5
48     { 1.0f, 1.0f, 1.0f, 1.0f,0.0f },
49     { 1.0f,-1.0f,-1.0f, 0.0f,1.0f },
50     { 1.0f,-1.0f, 1.0f, 1.0f,1.0f },
51     
52     {-1.0f, 1.0f,-1.0f, 1.0f,0.0f },    //side 6
53     {-1.0f,-1.0f,-1.0f, 1.0f,1.0f },
54     {-1.0f, 1.0f, 1.0f, 0.0f,0.0f },
55     {-1.0f,-1.0f, 1.0f, 0.0f,1.0f }
56 };
57 
58 QUAD *quads[6];
59 D3DXVECTOR3 cameraSource;
60 D3DXVECTOR3 cameraTarget;
复制代码

 

 函数SetVertex调用SetPosition设置四边形的顶点信息。CreateVertex用于创建顶点。

复制代码
 1 void SetPosition(QUAD* quad, int ivert, float x, float y, float z)
 2 {
 3     quad->vertices[ivert].x = x;
 4     quad->vertices[ivert].y = y;
 5     quad->vertices[ivert].z = z;
 6 }
 7 
 8 void SetVertex(QUAD *quad, int ivert, float x, float y, float z, float tu, float tv)
 9 {
10     SetPosition(quad, ivert, x, y, z);
11     quad->vertices[ivert].tu = tu;
12     quad->vertices[ivert].tv = tv;
13 }
14 
15 VERTEX CreateVertex(float x, float y, float z, float tu, float tv)
16 {
17     VERTEX vertex;
18     vertex.x = x;
19     vertex.y = y;
20     vertex.z = z;
21     vertex.tu = tu;
22     vertex.tv = tv;
23     
24     return vertex;
25 }
复制代码

 

在下面的CreateQuad函数中,首先使用D3DXCreateTextureFromFile用图片文件创建了纹理,然后赋值给quad->texture。接着用CreateVertexBuffer创建了顶点缓存并赋值给quad->buffer,quad由3部分组成,下面就剩下顶点信息vertices了。下面对quad->vertices进行了默认的初始化工作,我们实际使用的顶点数据来源于之前的cube数组。

复制代码
 1 QUAD* CreateQuad(char *textureFilename)
 2 {
 3     QUAD *quad = (QUAD*)malloc(sizeof(QUAD));
 4 
 5     //load the texture
 6     D3DXCreateTextureFromFile(d3ddev, textureFilename, &quad->texture);
 7 
 8     //create vertex buffer for quad
 9     d3ddev->CreateVertexBuffer(
10         4*sizeof(VERTEX),
11         0,
12         D3DFVF_MYVERTEX, D3DPOOL_DEFAULT,
13         &quad->buffer, NULL);
14 
15     //create the four corners of this quad triangle strip
16     quad->vertices[0] = CreateVertex(-1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
17     quad->vertices[1] = CreateVertex(1.0f, 1.0f, 0.0f, 1.0f, 0.0f);
18     quad->vertices[2] = CreateVertex(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f);
19     quad->vertices[3] = CreateVertex(1.0f, -1.0f, 0.0f, 1.0f, 1.0f);
20 
21     return quad;
22 }
23 
24 void DeleteQuad(QUAD *quad)
25 {
26     if (quad == NULL)
27         return;
28 
29     if (quad->buffer != NULL)
30         quad->buffer->Release();
31 
32     if (quad->texture != NULL)
33         quad->texture->Release();
34 
35     free(quad);
36 }
复制代码

 

下面的函数DrawQuad用于绘制四边形。首先,需要把初始化好的顶点信息传递给顶点缓存,这里定义了一个临时指针变量temp,然后调用lock函数来锁住顶点缓冲区,同时使用temp指向了顶点缓存。然后,就可以用memcpy给这个代表顶点缓存的temp赋值了,最后要Unlock才行。接着用SetTexture设置使用的纹理,用SetStreamSource设置流源,使Direct3D知道顶点的来源以及需要渲染多少顶点。最后,绘制流源指定的基元(primitive),即基础图元。在DirectX中,基础图元只有点、线、三角形,这里使用三角形条的方式绘制四边形。传入的参数0代表索引,2代表两个三角形,而参数TRIANGLESTRIP也能换成TRIANGLELIST,只是绘制方式不同,下面就是区别。三角形列表需要6个顶点来绘制一个四边形,而三角形条只需要4个顶点信息。

复制代码
 1 void DrawQuad(QUAD *quad)
 2 {
 3     //fill vertex buffer with quad vertices
 4     void *temp = NULL;
 5     quad->buffer->Lock(0, sizeof(quad->vertices), (void**)&temp, 0);
 6     memcpy(temp, quad->vertices, sizeof(quad->vertices));
 7     quad->buffer->Unlock();
 8 
 9     //draw the textured dual triangle strip
10     d3ddev->SetTexture(0, quad->texture);
11     d3ddev->SetStreamSource(0, quad->buffer, 0, sizeof(VERTEX));
12     d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
13 }
复制代码

 

SetIdentity函数最后使用了SetTransform,下面还会使用,这个函数用于在渲染之前进行矩阵转换,你不妨再看看前面的世界变换、视图变换、投影变换这些概念。D3DXMatrixTranslation用于设置平移矩阵,将设置的矩阵信息保存在矩阵matWorld中。D3DTS_WORLD是一个宏定义,这段就表示进行世界变换的操作。

复制代码
 1 void SetIdentity()
 2 {
 3     //set default position, scale, rotation
 4     D3DXMATRIX matWorld;
 5     D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f);
 6     d3ddev->SetTransform(D3DTS_WORLD, &matWorld);
 7 }
 8 
 9 void ClearScene(D3DXCOLOR color)
10 {
11     d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1.0f, 0);
12 }
复制代码

 

下面的SetCamera函数用于设置相机信息,显然这里的相机是虚拟的,用视图变换来表示。看到D3DXMatrixLookAtLH这个重要的函数,这个函数最终得到一个用于视图变换的观察矩阵matView,参数cameraSource表示相机的位置(观察点),cameraTarget表示相机朝着什么方向看的向量,updir代表当前世界方向向上的向量,默认为(0, 1, 0)。最后,通过SetTransform(D3DTS_VIEW,&matView)进行了视图变换。

复制代码
 1 void SetCamera(float x, float y, float z, float lookx, float looky, float lookz)
 2 {
 3     D3DXMATRIX matView;
 4     D3DXVECTOR3 updir(0.0f, 1.0f, 0.0f);
 5 
 6     //move the camera
 7     cameraSource.x = x;
 8     cameraSource.y = y;
 9     cameraSource.z = z;
10 
11     //point the camera
12     cameraTarget.x = lookx;
13     cameraTarget.y = looky;
14     cameraTarget.z = lookz;
15 
16     //set up the camera view matrix
17     D3DXMatrixLookAtLH(&matView, &cameraSource, &cameraTarget, &updir);
18     d3ddev->SetTransform(D3DTS_VIEW, &matView);
19 }
复制代码

 

最后还有一个投影变换,使用SetTransform(D3DTS_PROJECTION, &matProj)完成,Projection就是投影的意思。参数fieldOfView代表视景体,aspectRatio代表图像的宽高比,nearRange与farRange代表近平面与远平面。

复制代码
1 void SetPerspective(float fieldOfView, float aspectRatio, float nearRange, float farRange)
2 {
3     //set the perspective so things in the distance will look smaller
4     D3DXMATRIX matProj;
5     D3DXMatrixPerspectiveFovLH(&matProj, fieldOfView, aspectRatio, nearRange, farRange);
6     d3ddev->SetTransform(D3DTS_PROJECTION, &matProj);
7 }
复制代码

 

下面这个函数用于初始化立方体,调用CreateQuad函数创建了带纹理贴图的四边形,然后用cube数组对这些四边形的顶点赋值。

复制代码
 1 void Init_Cube()
 2 {
 3     for (int q = 0; q < 6; q++)
 4     {
 5         int i = q*4;
 6         quads[q] = CreateQuad("cube.bmp");
 7         for (int v = 0; v < 4; v++)
 8         {
 9             quads[q]->vertices[v] = CreateVertex(
10                 cube[i].x, cube[i].y, cube[i].z,
11                 cube[i].tu, cube[i].tv);
12             i++;
13         }
14     }
15 }
复制代码

 

我们还要做一件事,就是让立方体旋转起来。在Rotate_Cube中,xrot、yrot、zrot组成了旋转需要的旋转轴,而我们对3D物体进行旋转还需要进行旋转的旋转矩阵matRot。这里还设置了平移矩阵matTrans,不过这里暂时没有平移。函数D3DXMatrixRotationYawPitchRoll用于创建旋转矩阵,最后用matRot*matTrans来得到一个组合了平移与旋转的矩阵matWorld。

复制代码
 1 void Rotate_Cube()
 2 {
 3     static float xrot = 0.0f;
 4     static float yrot = 0.0f;
 5     static float zrot = 0.0f;
 6 
 7     //rotate the x and y axes
 8     xrot += 0.2f;
 9     yrot += 0.00f;
10 
11     //create the matrices
12     D3DXMATRIX matWorld;
13     D3DXMATRIX matTrans;
14     D3DXMATRIX matRot;
15 
16     //get an identity matrix
17     D3DXMatrixTranslation(&matTrans, 0.0f, 0.0f, 0.0f);
18 
19     //rotate the cube
20     D3DXMatrixRotationYawPitchRoll(&matRot,D3DXToRadian(xrot),D3DXToRadian(yrot),D3DXToRadian(zrot));
21     matWorld = matRot * matTrans;
22 
23     //complete the operation
24     d3ddev->SetTransform(D3DTS_WORLD, &matWorld);
25 }
复制代码

 

下面是Game_Init函数,可以直接从SetCamera开始看起。如果改变SetCamera函数的参数,就能使图像放大与缩小。

复制代码
 1 bool Game_Init(HWND window)
 2 {
 3     srand(time(NULL));
 4 
 5     //initialize Direct3D
 6     if (!Direct3D_Init(window, SCREENW, SCREENH, false))
 7     {
 8         MessageBox(window,"Error initializing Direct3D",APPTITLE.c_str(),0);
 9         return false;
10     }
11 
12     //initialize DirectInput
13     if (!DirectInput_Init(window))
14     {
15         MessageBox(window,"Error initializing DirectInput",APPTITLE.c_str(),0);
16         return false;
17     }
18 
19     //initialize DirectSound
20     if (!DirectSound_Init(window))
21     {
22         MessageBox(window,"Error initializing DirectSound",APPTITLE.c_str(),0);
23         return false;
24     }
25 
26     //position the camera
27     SetCamera(0.0f, 2.0f, -4.0f, 0, 0, 0);
28 
29     float ratio = (float)SCREENW / (float)SCREENH;
30     SetPerspective(45.0f, ratio, 0.1f, 10000.0f);
31 
32     //turn dynamic lighting off, z-buffer on
33     d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
34     d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);
35 
36     //set the Direct3D stream to use the custom vertex
37     d3ddev->SetFVF(D3DFVF_MYVERTEX);
38 
39     //convert the cube values into quads
40     Init_Cube();
41 
42     return true;
43 }
复制代码

 

函数Game_Run变得很简单,先Rotate_Cube使立方体产生旋转效果,接着在for循环中DrawQuad绘制立方体的6个面就可以了。

复制代码
 1 void Game_Run(HWND window)
 2 {
 3     if (!d3ddev) return;
 4     DirectInput_Update();
 5     d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
 6 
 7     //slow rendering to approximately 60 fps
 8     if (timeGetTime() > screentimer + 14)
 9     {
10         screentimer = GetTickCount();
11 
12         Rotate_Cube();
13 
14         //start rendering
15         if (d3ddev->BeginScene())
16         {
17            for (int n = 0; n < 6; n++)
18            {
19                DrawQuad(quads[n]);
20            }
21 
22             //stop rendering
23             d3ddev->EndScene();
24             d3ddev->Present(NULL, NULL, NULL, NULL);
25         }
26     }
27 
28     //exit with escape key or controller Back button
29     if (KEY_DOWN(VK_ESCAPE)) gameover = true;
30     if (controllers[0].wButtons & XINPUT_GAMEPAD_BACK) gameover = true;
31 
32 }
复制代码

 

最后是Game_End函数

复制代码
1 void Game_End()
2 {
3     for (int q = 0; q < 6; q++)
4         DeleteQuad(quads[q]);
5     DirectSound_Shutdown();
6     DirectInput_Shutdown();
7     Direct3D_Shutdown();
8 }
复制代码

 

本文只是用DirectX 9的知识简单的绘制了一个立方体,如果不使用纹理图片,直接使用顶点颜色信息也是可以的。下面是运行截图,源代码,参考自游戏编程入门。


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例程序,可以实现电脑相机实时采集视频流,用OpenGL渲染一个正方体,并将正方体的中心放在指定的坐标点上。 ```python import cv2 import numpy as np from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * # 相机坐标点 camera_coord = (0, 0, -5) # 正方体顶点坐标 vertices = np.array([ [-1, -1, -1], [ 1, -1, -1], [ 1, 1, -1], [-1, 1, -1], [-1, -1, 1], [ 1, -1, 1], [ 1, 1, 1], [-1, 1, 1], ], dtype=np.float32) # 正方体面的顶点索引 faces = np.array([ [0, 1, 2, 3], [1, 5, 6, 2], [5, 4, 7, 6], [4, 0, 3, 7], [3, 2, 6, 7], [0, 4, 5, 1], ], dtype=np.int32) # 正方体颜色 colors = np.array([ [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0], [0, 1, 1], [1, 0, 1], ], dtype=np.float32) def draw_cube(): glBegin(GL_QUADS) for i in range(len(faces)): glColor3fv(colors[i]) for j in faces[i]: glVertex3fv(vertices[j]) glEnd() def display(): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glEnable(GL_DEPTH_TEST) # 绘制视频流 ret, frame = cap.read() if ret: glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(0, 0, -1) glRotatef(180, 0, 1, 0) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, frame.shape[1], frame.shape[0], 0, GL_BGR, GL_UNSIGNED_BYTE, frame) glBegin(GL_QUADS) glTexCoord2f(0, 0); glVertex3f(-1, -1, 0) glTexCoord2f(1, 0); glVertex3f( 1, -1, 0) glTexCoord2f(1, 1); glVertex3f( 1, 1, 0) glTexCoord2f(0, 1); glVertex3f(-1, 1, 0) glEnd() # 绘制正方体 glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(*camera_coord) draw_cube() glutSwapBuffers() def reshape(width, height): glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45, width/height, 0.1, 100) glMatrixMode(GL_MODELVIEW) if __name__ == '__main__': # 打开相机 cap = cv2.VideoCapture(0) # 初始化OpenGL窗口 glutInit() glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH) glutInitWindowSize(640, 480) glutCreateWindow("Real-time Video with 3D Cube") # 绑定回调函数 glutDisplayFunc(display) glutReshapeFunc(reshape) # 初始化OpenGL glClearColor(0, 0, 0, 0) glEnable(GL_TEXTURE_2D) # 开始主循环 glutMainLoop() # 释放资源 cap.release() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值