写在前面:正当很高兴地完成了矩阵相关的旋转后,发现如果涉及到旋转;矩阵,欧拉角(EulerAngles) ,四元数(Quaternions)这三个概念哪本书上都会提。这次先讲下欧拉角。
1.什么是欧拉角
欧拉角是由三个角组成,这三个角分别是Yaw,Pitch,Roll。很难翻译这三个单词,Yaw 表示绕y轴旋转的角度,Pitch表示绕x轴旋转的角度,Roll表示绕z轴旋转的角度。也就是说,任意的旋转角度都可以通过这三次按照先后顺序旋转得到。矩阵很难让人具体形象表示,欧拉角就容易多了。注意可能很多地方三个角的先后次序不一样,我们这里选择跟DirectX 中的D3DXMatrixRotationYawPitchRoll函数保持一致,先绕y轴旋转,在绕x轴旋转,最后绕z轴旋转。
感觉Yaw(偏航),Pitch(投掷;倾斜;坠落),Roll(转动) 介绍飞机旋转的比较多,窃了三张图来更象形地表示下:
2.欧拉角中的旋转
还记得这三个矩阵吗?绕相关轴旋转,乘以相关矩阵就行了,也就是说欧拉角最终还是转换成矩阵相乘,不过是要与三个矩阵相乘。
我们知道可以先把这三个矩阵相乘,这样可以节约计算量。就是要先计算这三个矩阵相乘,注意矩阵相乘次序是不可更改的,更改了结果就不一样了。
欧拉角的三个角,可以转变为矩阵与矩阵的相乘。
3.开始替换D3DXMatrixRotationYawPitchRoll函数
Directx 9.0中有个函数叫D3DXMatrixRotationYawPitchRoll(D3DXMATRIX *pOut, FLOAT Yaw, FLOAT Pitch, FLOAT Roll)。根据上面复杂的矩阵,我们用C++替换成下面的函数。可能这个函数还有优化空间,数学太差啊。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//-----------------------------------------------------------------------------
// Name: setupRotate()
// Desc: 绕3个角度旋转
//-----------------------------------------------------------------------------
VOID
setupRotate(D3DXMATRIXA16 *returnMatrix,
float
yaw,
float
pitch,
float
roll)
{
float
sx =
sin
(pitch);
float
sy =
sin
(yaw);
float
sz =
sin
(roll);
float
cx =
cos
(pitch);
float
cy =
cos
(yaw);
float
cz =
cos
(roll);
returnMatrix->_11 = cz * cy - sx * sy * sz;
returnMatrix->_12 = cy * sz + sx * sy * cz;
returnMatrix->_13 = -sy * cx;
returnMatrix->_14 = 0.0f;
returnMatrix->_21 = -cx * sz;
returnMatrix->_22 = cx * cz;
returnMatrix->_23 = sx;
returnMatrix->_24 = 0.0f;
returnMatrix->_31 = sy * cz + sx * cy * sz;
returnMatrix->_32 = sy * sz - sx * cy * cz;
returnMatrix->_33 = cx * cy;
returnMatrix->_34 = 0.0f;
returnMatrix->_41 = 0.0f;
returnMatrix->_42 = 0.0f;
returnMatrix->_43 = 0.0f;
returnMatrix->_44 = 1.0f;
}
|
先看下我们使用这个函数的例子效果:跟随鼠标移动的水壶,而不是自己在那旋转个不停。
对上面这张gif图片是如何制作感兴趣?看截取视频,然后制成gif 教程
除了上面的函数之外的核心代码(需要对Windows中的消息处理熟悉):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
float
g_fSpinX = 0.0f;
float
g_fSpinY = 0.0f;
//鼠标最后位置
static
POINT ptLastMousePosit;
//当前鼠标位置
static
POINT ptCurrentMousePosit;
static
bool
bMousing;
switch
( msg )
{
case
WM_LBUTTONDOWN:
// 当鼠标左键按下时,记录当前的位置(屏幕坐标),并设置按下标志
{
ptLastMousePosit.x = ptCurrentMousePosit.x = LOWORD (lParam);
ptLastMousePosit.y = ptCurrentMousePosit.y = HIWORD (lParam);
bMousing =
true
;
}
break
;
case
WM_LBUTTONUP:
{
bMousing =
false
;
}
break
;
case
WM_MOUSEMOVE:
// 鼠标移动时,保存X/Y轴的移动距离
{
ptCurrentMousePosit.x = LOWORD (lParam);
ptCurrentMousePosit.y = HIWORD (lParam);
if
( bMousing )
{
g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x);
g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y);
}
ptLastMousePosit.x = ptCurrentMousePosit.x;
ptLastMousePosit.y = ptCurrentMousePosit.y;
}
break
;
}
//最后两个值传到我们写好的函数中即可
setupRotate(&matWorld,D3DXToRadian(g_fSpinX),D3DXToRadian(g_fSpinY),0.0f);
|
完整代码:如果觉得看起来太累,拉到最底部,下载整个项目来看。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
|
//-----------------------------------------------------------------------------
// File: Lights.cpp
// Copyright (c) Microsoft Corporation & Waitingfy.com. All rights reserved.
//-----------------------------------------------------------------------------
#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#include <strsafe.h>
#include <math.h>
#include <assert.h>
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL;
// Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
// Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
// Buffer to hold vertices
ID3DXMesh* Objects = 0;
//茶壶
float
g_fSpinX = 0.0f;
float
g_fSpinY = 0.0f;
// A structure for our custom vertex type. We added a normal, and omitted the
// color (which is provided by the material)
struct
CUSTOMVERTEX
{
D3DXVECTOR3 position;
// The 3D position for the vertex
D3DXVECTOR3 normal;
// The surface normal for the vertex
};
// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)
//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT
InitD3D(
HWND
hWnd )
{
// Create the D3D object.
if
( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return
E_FAIL;
// Set up the structure used to create the D3DDevice. Since we are now
// using more complex geometry, we will create a device with a zbuffer.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp,
sizeof
(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// Create the D3DDevice
if
( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return
E_FAIL;
}
// Turn off culling
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// Turn on the zbuffer
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
return
S_OK;
}
//-----------------------------------------------------------------------------
// Name: Cleanup()
// Desc: Releases all previously initialized objects
//-----------------------------------------------------------------------------
VOID
Cleanup()
{
if
( g_pVB != NULL )
g_pVB->Release();
if
( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if
( g_pD3D != NULL )
g_pD3D->Release();
if
(Objects != NULL){
Objects->Release();
}
}
//-----------------------------------------------------------------------------
// Name: setupRotate()
// Desc: 绕3个角度旋转
//-----------------------------------------------------------------------------
VOID
setupRotate(D3DXMATRIXA16 *returnMatrix,
float
yaw,
float
pitch,
float
roll)
{
float
sx =
sin
(pitch);
float
sy =
sin
(yaw);
float
sz =
sin
(roll);
float
cx =
cos
(pitch);
float
cy =
cos
(yaw);
float
cz =
cos
(roll);
returnMatrix->_11 = cz * cy - sx * sy * sz;
returnMatrix->_12 = cy * sz + sx * sy * cz;
returnMatrix->_13 = -sy * cx;
returnMatrix->_14 = 0.0f;
returnMatrix->_21 = -cx * sz;
returnMatrix->_22 = cx * cz;
returnMatrix->_23 = sx;
returnMatrix->_24 = 0.0f;
returnMatrix->_31 = sy * cz + sx * cy * sz;
returnMatrix->_32 = sy * sz - sx * cy * cz;
returnMatrix->_33 = cx * cy;
returnMatrix->_34 = 0.0f;
returnMatrix->_41 = 0.0f;
returnMatrix->_42 = 0.0f;
returnMatrix->_43 = 0.0f;
returnMatrix->_44 = 1.0f;
}
//-----------------------------------------------------------------------------
// Name: SetupMatrices()
// Desc: Sets up the world, view, and projection transform matrices.
//-----------------------------------------------------------------------------
VOID
SetupMatrices()
{
// 旋转
D3DXMATRIXA16 matWorld;
D3DXMatrixIdentity( &matWorld );
//根据x轴和y轴移动距离旋转
setupRotate(&matWorld,D3DXToRadian(g_fSpinX),D3DXToRadian(g_fSpinY),0.0f);
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
// 摄像机的位置
D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
// 设置视锥体大小
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
//-----------------------------------------------------------------------------
// Name: SetupLights()
// Desc: Sets up the Lights and materials for the scene.
//-----------------------------------------------------------------------------
VOID
SetupLights()
{
// 初始化一个材料
D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl,
sizeof
(D3DMATERIAL9) );
mtrl.Diffuse = mtrl.Ambient = D3DXCOLOR(1.0f,1.0f,0.0f,1.0f);
//材质有漫射和环境光的设置,都为黄色
g_pd3dDevice->SetMaterial( &mtrl );
// 初始化一个白色的方向光
///*
D3DXVECTOR3 vecDir;
D3DLIGHT9 light;
ZeroMemory( &light,
sizeof
(D3DLIGHT9) );
light.Type = D3DLIGHT_DIRECTIONAL;
//方向光
light.Diffuse = D3DXCOLOR(1.0f,1.0f,1.0f,1.0f);
//设置光源的漫射光颜色为白色
light.Direction = D3DXVECTOR3(0.0f,0.0f,1.0f);
//光的传播方向平行z轴
light.Range = 1000.0f;
g_pd3dDevice->SetLight( 0, &light );
g_pd3dDevice->LightEnable( 0, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
//*/
// Finally, turn on some ambient light.
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 );
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Draws the scene
//-----------------------------------------------------------------------------
VOID
Render()
{
// 背景为蓝色
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Begin the scene
if
( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// 茶壶的材料颜色也定义在这个函数中
SetupLights();
// Setup the world, view, and projection matrices
SetupMatrices();
// Render the vertex buffer contents
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0,
sizeof
(CUSTOMVERTEX) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
//创建一个茶壶
//Objects = 0;
D3DXMATRIX Worlds;
D3DXCreateTeapot(g_pd3dDevice, &Objects, 0);
Objects->DrawSubset(0);
Objects->Release();
Objects = 0;
// End the scene
g_pd3dDevice->EndScene();
}
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
//Objects->Release();
}
//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT
WINAPI MsgProc(
HWND
hWnd,
UINT
msg,
WPARAM
wParam,
LPARAM
lParam )
{
static
POINT ptLastMousePosit;
static
POINT ptCurrentMousePosit;
static
bool
bMousing;
switch
( msg )
{
case
WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return
0;
case
WM_LBUTTONDOWN:
// 当鼠标左键按下时,记录当前的位置(屏幕坐标),并设置按下标志
{
ptLastMousePosit.x = ptCurrentMousePosit.x = LOWORD (lParam);
ptLastMousePosit.y = ptCurrentMousePosit.y = HIWORD (lParam);
bMousing =
true
;
}
break
;
case
WM_LBUTTONUP:
{
bMousing =
false
;
}
break
;
case
WM_MOUSEMOVE:
// 鼠标移动时,保存X/Y轴的移动距离
{
ptCurrentMousePosit.x = LOWORD (lParam);
ptCurrentMousePosit.y = HIWORD (lParam);
if
( bMousing )
{
g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x);
g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y);
}
ptLastMousePosit.x = ptCurrentMousePosit.x;
ptLastMousePosit.y = ptCurrentMousePosit.y;
}
break
;
}
return
DefWindowProc( hWnd, msg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
INT
WINAPI WinMain(
HINSTANCE
hInst,
HINSTANCE
,
LPSTR
,
INT
)
{
// Register the window class
WNDCLASSEX wc = {
sizeof
(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"D3D Tutorial"
, NULL };
RegisterClassEx( &wc );
// Create the application's window
HWND
hWnd = CreateWindow(
"D3D Tutorial"
,
"D3D Tutorial 04: Lights"
,
WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
GetDesktopWindow(), NULL, wc.hInstance, NULL );
// Initialize Direct3D
if
( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// Enter the message loop
MSG msg;
ZeroMemory( &msg,
sizeof
(msg) );
while
( msg.message!=WM_QUIT )
{
if
( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render();
}
}
UnregisterClass(
"D3D Tutorial"
, wc.hInstance );
return
0;
}
|
文章源地址:http://www.waitingfy.com/?p=375
YawPitchRoll (本站下载)
http://download.csdn.net/detail/fox64194167/4856842(CSDN下载,免积分)
参考资源:http://hi.baidu.com/_鈊_烦_薏乱/blog/item/bac886c46164c1d438db49e7.html