下面将学习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
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, ¢er, 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的知识简单的绘制了一个立方体,如果不使用纹理图片,直接使用顶点颜色信息也是可以的。下面是运行截图,源代码,参考自游戏编程入门。