一、
MFC
框架下使用
OpenGL
繪圖演示平移、旋轉(zhuǎn)、縮放等操作的具體實(shí)現(xiàn)
二、
實(shí)現(xiàn)算法
繪制的圖形以各種頂點(diǎn)及頂點(diǎn)之間的線、面構(gòu)成
要想對(duì)這些圖形進(jìn)行操作,只需要對(duì)各種頂點(diǎn)在坐標(biāo)系中的坐標(biāo)進(jìn)行轉(zhuǎn)換即可
頂點(diǎn)在
OpenGL
中的坐標(biāo)以四維形式表示:(
X,Y,Z,W
)
其中
X,Y,Z
對(duì)應(yīng)三維系統(tǒng)中
X
,
Y
,
Z
三個(gè)柚;
W
默認(rèn)為
1
,一般為了方便各種操作時(shí)坐標(biāo)換算而將三維坐標(biāo)系提升為四次,即齊次坐標(biāo)系。
①
平移操作——對(duì)應(yīng)
glTranslate
函數(shù):
初始點(diǎn):(
X,Y,Z,W
)
使用轉(zhuǎn)換矩陣
TMatrix
:
1, 0, 0, Tx
0, 1, 0, Ty
0, 0, 1, Tz
0, 0, 0, 1
(X’, Y’, Z’) =
TMatrix * (X, Y, Z),
其中
Tx
,
Ty
,
Tz
對(duì)應(yīng)
glTranslate
函數(shù)中的三個(gè)參數(shù),分別表示三個(gè)方向的的平移量;原始坐標(biāo)右乘平移矩陣后即得到新的坐標(biāo)
③
縮放操作——對(duì)應(yīng)
glScale
函數(shù):
使用轉(zhuǎn)換矩陣為
SMatrix
:
Sx, 0, 0, 0
0, Sy, 0, 0
0, 0, Sz, 0
0, 0, 0, 1
(X’, Y’, Z’) =
SMatrix * (X, Y, Z)
此次自己實(shí)現(xiàn)的縮放函數(shù)與
OpenGL
有所不同,我實(shí)現(xiàn)的是與圖形的中心點(diǎn)為基準(zhǔn)進(jìn)行縮放,所以進(jìn)行矩陣變換前需要計(jì)算各個(gè)坐標(biāo)的位置并求幾何中心。
②
旋轉(zhuǎn)操作——對(duì)應(yīng)
glRotate
函數(shù)(逆時(shí)針?lè)较颍?/span>
在三維坐標(biāo)系統(tǒng)中,旋轉(zhuǎn)操作與二維情況有所不同,因?yàn)槿S中的一個(gè)點(diǎn)可以繞不同的方向進(jìn)行旋轉(zhuǎn),所以除了要指定旋轉(zhuǎn)角度外,還要指定旋轉(zhuǎn)軸
當(dāng)所取旋轉(zhuǎn)軸為
X
,
Y
或
Z
三個(gè)坐標(biāo)軸時(shí),與二維情況相似
即所選取的軸那一方向上的坐標(biāo)不變,在其它兩個(gè)軸所成的平面上進(jìn)行二維旋轉(zhuǎn)變換
根據(jù)這個(gè)規(guī)律可以把三維中繞任意軸旋轉(zhuǎn)的操作分為幾個(gè)操作來(lái)完成
步驟:
先將待旋轉(zhuǎn)的坐標(biāo)與旋轉(zhuǎn)軸平移,使旋轉(zhuǎn)軸經(jīng)過(guò)原點(diǎn)
進(jìn)行若干次旋轉(zhuǎn)操作,例旋轉(zhuǎn)軸與
Z
軸正向重合
依據(jù)對(duì)坐標(biāo)軸旋轉(zhuǎn)的方法將待旋轉(zhuǎn)坐標(biāo)進(jìn)行旋轉(zhuǎn)操作
應(yīng)用逆旋轉(zhuǎn)使旋轉(zhuǎn)軸回到原方向
應(yīng)用逆平移使旋轉(zhuǎn)軸回到原位置
二維情況下旋轉(zhuǎn)矩陣為:
cosQ, -sinQ, 0
sinQ, cosQ, 0
0, 0, 1
此次采用先繞
X
轉(zhuǎn)做旋轉(zhuǎn)
Rx
,再繞
Y
轉(zhuǎn)旋轉(zhuǎn)
Ry
使旋轉(zhuǎn)軸與
Z
轉(zhuǎn)正向重合,再繞
Z
軸做
Rz
旋轉(zhuǎn)
Q
度,再進(jìn)行逆操作還原位置
即
: (X’, Y’, Z’) = Rx*Ry*Rz(Q)*(Ry
-1
)*(Rx-1)
其中
Q
是需要旋轉(zhuǎn)的角度,
逆矩陣
A
-1
= A*/|A|
代數(shù)余子式:
(-1)^(i+j)Aij
三、
程序結(jié)構(gòu)
使用
MFC
生成程序界面,
OpenGL
負(fù)責(zé)繪制圖形
文檔
/
視圖結(jié)構(gòu)
文件數(shù)據(jù)為,圖形的類(lèi)型以及各個(gè)頂點(diǎn)坐標(biāo)
從菜單中選擇要進(jìn)行的操作:平移,旋轉(zhuǎn),縮放后出現(xiàn)對(duì)話框輸入?yún)?shù)
平移——
3
個(gè)參數(shù),分別表示
X,Y,Z
各個(gè)軸向的平移量
旋轉(zhuǎn)——
4
個(gè)參數(shù),第一個(gè)角度
Angle,
后三個(gè)表示轉(zhuǎn)軸向量
縮放——
3
個(gè)參數(shù),表示
X,Y,Z
軸方向上的縮放比例,可以為負(fù)數(shù)
文件數(shù)據(jù)為:
一個(gè)
CArray<Point,
Point> m_PointArray
保存圖形的各個(gè)頂點(diǎn)信息
一個(gè)表示圖形形狀的
int m_nShape
表示
glBegin
函數(shù)里的參數(shù)
四、
MFC
中使用
OpenGL
繪圖
具體還沒(méi)有研究,只是照搬網(wǎng)上教程,以后補(bǔ)上
View
頭文件中加入
HGLRC m_hRC; //Rendering
Context
CDC* m_pDC; //Device
Context
BOOL InitializeOpenGL(); //Initialize OpenGL
BOOL SetupPixelFormat(); //Set up the Pixel Format
實(shí)現(xiàn)部分:
InitializeOpenGL
BOOL CHomeWork1View::InitializeOpenGL()
{
//
Get a DC for the Client Area
m_pDC
=
new
CClientDC(
this
);
//
Failure to Get DC
if
(m_pDC
==
NULL)
{
MessageBox(_T(
"
Error Obtaining DC
"
));
return
FALSE;
}
//
Failure to set the pixel format
if
(
!
SetupPixelFormat())
{
return
FALSE;
}
//
Create Rendering Context
m_hRC
=
::wglCreateContext (m_pDC
->
GetSafeHdc ());
//
Failure to Create Rendering Context
if
(m_hRC
==
0
)
{
MessageBox(_T(
"
Error Creating RC
"
));
return
FALSE;
}
//
Make the RC Current
if
(::wglMakeCurrent (m_pDC
->
GetSafeHdc (), m_hRC)
==
FALSE)
{
MessageBox(_T(
"
Error making RC Current
"
));
return
FALSE;
}
//
Specify Black as the clear color
::glClearColor(
0.0f
,
0.0f
,
0.0f
,
0.0f
);
//
Specify the back of the buffer as clear depth
::glClearDepth(
1.0f
);
//
Enable Depth Testing
::glEnable(GL_DEPTH_TEST);
return
TRUE;
}
SetupPixelFormat
BOOL CHomeWork1View::SetupPixelFormat()
{
static
PIXELFORMATDESCRIPTOR pfd
=
{
sizeof
(PIXELFORMATDESCRIPTOR),
//
size of this pfd
1
,
//
version number
PFD_DRAW_TO_WINDOW
|
//
support window
PFD_SUPPORT_OPENGL
|
//
support OpenGL
PFD_DOUBLEBUFFER,
//
double buffered
PFD_TYPE_RGBA,
//
RGBA type
24
,
//
24-bit color depth
0
,
0
,
0
,
0
,
0
,
0
,
//
color bits ignored
0
,
//
no alpha buffer
0
,
//
shift bit ignored
0
,
//
no accumulation buffer
0
,
0
,
0
,
0
,
//
accum bits ignored
16
,
//
16-bit z-buffer
0
,
//
no stencil buffer
0
,
//
no auxiliary buffer
PFD_MAIN_PLANE,
//
main layer
0
,
//
reserved
0
,
0
,
0
//
layer masks ignored
};
int
m_nPixelFormat
=
::ChoosePixelFormat(m_pDC
->
GetSafeHdc(),
&
pfd);
if
( m_nPixelFormat
==
0
)
{
return
FALSE;
}
if
( ::SetPixelFormat(m_pDC
->
GetSafeHdc(), m_nPixelFormat,
&
pfd)
==
FALSE)
{
return
FALSE;
}
return
TRUE;
}
此外需要將
View
類(lèi)中的
OnEraseBkgnd
消息屏蔽掉,使之直接返回
TRUE
,因?yàn)橄尘暗墓ぷ饕呀?jīng)將由
OpenGL
來(lái)做,不需要由這個(gè)函數(shù)再來(lái)做一遍。
在
PreCreateWindow
函數(shù)中修改
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
保證
OpenGL
不會(huì)繪制到其它窗口中去
在
OnCreate
函數(shù)中調(diào)用
InitializeOpenGL
函數(shù)就可以在
View
中進(jìn)行繪制了
另外,為了適應(yīng)窗口大小變化,還需要在
OnSize
函數(shù)中加入高速視域的代碼
OnSize
void
CHomeWork1View::OnSize(UINT nType,
int
cx,
int
cy)
{
CView::OnSize(nType, cx, cy);
//
TODO: 在此處添加消息處理程序代碼
GLdouble aspect_ratio;
//
width/height ratio
if
(
0
>=
cx
||
0
>=
cy )
{
return
;
}
//
select the full client area
::glViewport(
0
,
0
, cx, cy);
//
compute the aspect ratio
//
this will keep all dimension scales equal
aspect_ratio
=
(GLdouble)cx
/
(GLdouble)cy;
//
select the projection matrix and clear it
::glMatrixMode(GL_PROJECTION);
::glLoadIdentity();
//
select the viewing volume
::gluPerspective(
120
, aspect_ratio,
1.0f
,
150.0f
);
//
switch back to the modelview matrix and clear it
::glMatrixMode(GL_MODELVIEW);
::glLoadIdentity();
}
做好一切準(zhǔn)備工作后,就可以在
OnDraw
中使用
OpenGL
函數(shù)進(jìn)行繪制了,不過(guò)別忘了程序最后要進(jìn)行資源的釋放,在
OnDestroy
中加入清理工作
OnDestroy
void
CHomeWork1View::OnDestroy()
{
CView::OnDestroy();
//
TODO: 在此處添加消息處理程序代碼
//
Make the RC non-current
if
(::wglMakeCurrent (
0
,
0
)
==
FALSE)
{
MessageBox(_T(
"
Could not make RC non-current
"
));
}
//
Delete the rendering context
if
(::wglDeleteContext (m_hRC)
==
FALSE)
{
MessageBox(_T(
"
Could not delete RC
"
));
}
//
Delete the DC
if
(m_pDC)
{
delete m_pDC;
}
//
Set it to NULL
m_pDC
=
NULL;
}
最后程序演示結(jié)果:
五、
編程中遇到的問(wèn)題總結(jié)
1.
復(fù)習(xí)了操作符重載的相關(guān)內(nèi)容
2.
浮點(diǎn)數(shù)的比較,這個(gè)比較重要,以前在課上只是聽(tīng)說(shuō),沒(méi)有特別印象,在耗費(fèi)了我
2
個(gè)小時(shí)的調(diào)試之后,以后應(yīng)該再也不會(huì)忘了。
Fabs
(
f1-f2
)
<=
精度要求
3.
此次寫(xiě)的工具類(lèi)
Matrix
勝于處理向量,矩陣的相關(guān)操作,因?yàn)橥祽羞€不太完善,尤其是矩陣的一些操作比較求模,求逆都沒(méi)有實(shí)現(xiàn),以后補(bǔ)上
http://www.shnenglu.com/Files/sunshinealike/HomeWork1.rar