Để thiết kế được cỏc ứng dụng 3D trong VC++ 6.0 đó hỗ trợ thư viện đồ hoạ
OpenGL .OpenGL sẽ trả về đối tượng trong khụng gian 2 chiều, 3 chiều vào trong một
bộ đệm .
Cỏc bước cơ bản để xõy dựng một ứng dụng 3D (sử dụng cỏc member function ) :
-Include thư viện -PreCreateWindow - OnCreate
-OnSize.
-OnEraseBkgnd -OnInitialUpdate
Cỏc hàm này đều nằm trong lớp CProjectView (với Project là tờn ứng dụng ).
3.7.1.Gộp cỏc file header và library .
Copy cỏc file glu.h, gl.h,glaux.h trong thư mục Microsoft Visual Studio\
VC98\ Include\GL và link cỏc file thư viện vào ứng dụng bằng cỏch chọn project > Add to Project > file , trong thư mục Microsoft Visual Studio\ VC98\Lib chọn GLAUX.LIB, GLU.LIB và OPENGL32.LIBđồng thời trong file nguồn (chẳng hạn ProjectView.cpp) phải thờm cỏc khai bỏo : #include “gl\gl.h”
#include “gl\glu.h”
Tạo ứng dụng MFC AppWizard với mụi trường Single Document.
3.7.2.Sử dụng hàm PreCreateWindow .
Hàm này cú mục đớch kiểm tra xem OpenGL đó được đưa vào ứng dụng hay chưa . OpenGL chỉ cú hiệu lực trong một khu vực của cửa sổ màn hỡnh nơi được khởi tạo dành cho nú .Vỡ vậy hàm PreCreateWindow đảm bảo chỳng đó được gắn khung hiển thị .Thờm cõu lệnh :
cs.style| =WS_CLIPSIBLINGS| WS_CLIPCHILDREN;
3.7.3.Hàm OnCreate
Trước khi OpenGL cú thể tạo được cỏc đường nột, hỡnh ảnh trờn một khung hỡnh (cửa sổ hay bitmap) , khung hỡnh phải được khởi tạo . Ở đõy sử dụng khỏi niờm PixelFormat để khởi tạo cỏc thuộc tớnh của khung hỡnh .Một
PixelFormat được xỏc định nhờ cấu trỳc PIXELFORMATDESCRIPTOR .
Mỗi khung hỡnh bản thõn đó cú định dạng sẵn. Cỏc khung hỡnh khỏc nhau cú những PixelFormat khỏc nhau và 1 thiết bị cú thể hỗ trợ vài kiểu định dạng .
3.7.3.1.Mụ tả PixelFormat :
ClientDC dc(this); //Hoặc cú thể dựng trực tiếp CDC *pDC;
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd,0,sizeof(pfd)); pfd.nSize=sizeof(pfd); pfd.nVersion=1;
pfd.dwFlags=PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL; pfd.iPixelType=PFD_TYPE_RGBA; pfd.iLayerType=PFD_MAIN_PLANE; pfd.cColorBits=24; pfd.cDepthBits=32;
Ở đõy dwFlags cú thể nhận cỏc giỏ trị :
*PFD_SUPPORT_OPENGL : sử dụng OpenGL trờn ứng dụng.
*PFD_DRAW_TO_WINDOW : tụ búng trờn khu vực cửa sổ khụng phải là bitmap . *PFD_DOUBLE_BUFFER : OpenGl sẽ tụ búng trờn bộ đệm sau đú mới trả lờn màn hỡnh .
3.7.3.2.Chọn và thiết lập cho PixelFormat :
Sau khi định dạng cần gọi hàm ChoosePixelFormat :
nPixelFormat =ChoosePixelFormat(dc.m_hDC,&pfd);
Ở trờn m_hDC thuộc lớp CDC và là biến cú sẵn .Chỳng ta cú thể tự do kiểm tra định dạng Pixel bằng hàm ChoosePixelFormat và cú thể chọn lại nếu khụng thớch .Sau khi chọn chuyển sang sử dụng hàm SetPixelFormat để sử dụng nú. Hàm này sẽ lấy một ngữ cảnh thiết bị DC làm thụng số đầu tiờn và thiết lập cửa sổ tương thớch với DC đú với kiểu Pixel đó chọn :
SetPixelFormat(dc.m_hDC,nPixelFormat,&pfd);
3.7.3.3.Tạo một ngữ cảnh để tụ búng (Rendering Context ) :
Tạo ra một OpenGL Rendering Context (GLRC thiết bị ngữ cảnh tụ búng ).Nú khỏc DC vỡ DC chứa đựng thụng tin cho GDI cũn RC chứa thụng tin về OpenGL . Để tạo một RC ta sử dụng hàm wglCreateContext nú trả lại kiểu HGLRC trong ứng dụng nú được lưu giữ nhờ một biến m_hrc (Với khai bỏo
HGRLC m_hrc;) :
wglCreateContext(dc.m_hRC) ;
3.7.4.Hàm OnSize ( ).
Khi ỏnh xạ hệ toạ độ 3D sang 2D, OpenGL phải biết được kớch cỡ của khu vực hiển thị đú .Trong hàm OnSize chỳng ta sẽ thiết lập những biến đổi cần thiết khi ỏnh xạ 3D sang màn hỡnh ,GDI khụng biết bất cứ điều gỡ về kớch thước thứ 3 .
Hàm wglMakeCurrent được sử dụng để thiết lập một RC : wglMakeCurrent(dc.m_hDC,m_hrc);
Đến dõy đó cú một RC hiện hành và ta cú thể sử dụng cỏc hàm OpenGL. Cỏc hàm dưới đõy sẽ thiết lập màn hỡnh :
Gldouble gldAspect=(GLdouble)cx /(GLdouble) cy; glMatrixMode(GL_PROJECTION);
glLoadIdentity( );
gluPerspective(30.0,glAspect,1.0,10.0); glViewport(0,0,cx,cy );
Tất cả cỏc hàm OpenGL đều cú tiền tố “gl” và cỏc ứng dụng của nú thỡ cú tiền tố “glu”. Hàm gluPerspective sẽ thiết lập gúc nhỡn 30o , glAspect là tỉ lệ được điều chỉnh với kớch thước của khu vực hiển thị. Cỏc tham số tiếp theo là khoảng cỏch từ điểm hiển thị tới
3.7.5.Hàm OnEraseBkgnd .
Sẽ trả lại giỏ trị TRUE nếu như vẽ màn hỡnh trắng trước khi tụ búng màn hỡnh với
OpenGl.
3.7.6.Hàm OnInitialUpdate .
Khi OpenGl xõy dựng một danh sỏch hiển thị và nú phải lưu danh sỏch này lại và khụng cần phải nhăc lại mỗi lần được hiện ra thỡ đõy là nới để chứa cỏc danh sỏch đú .
3.7.7.Hàm OnDraw(CDC*pDC)
Là nơi thực hiện tất cả cỏc cụng việc liờn quan đến việc tụ vẽ với OpenGL, tuy nhiờn để cho chương trỡnh bớt rườm rà thỡ xõy dựng cỏc hàm vẽ riờng (DrawScene ) và chỉ việc gọi chỳng vào OnDraw để thực thi. Trong hàm OnDraw chỉ thực hiện cỏc cụng việc :
-Lực chọn và nhận cỏc bảng màu trong DC. -Tao Rendering Context hiện hành .
-Vẽ với việc sử dụng cỏc cõu lệnh OpenGL (hoặc là gọi lại cỏc hàm DrawScene được viết riờng biệt ).
-Thay đổi khung đệm (Swap buffer) . -Chọn lại bảng màu gốc để trả lại vào DC.
Cấu trỳc hàm này sẽ như sau :
void CProjectView::OnDraw(CDC*pDC) {
//Chọn bảng màu :
Cpalette *OldPalete=pDC->SelectPalette(&m_Pal,0);
//Với m_Pal đó được khởi tạo
pDC->RealizePalette( );
//Tạo HGRLC hiện hành .
wglMakeCurrent(pDC->m_hDC,m_hrc);
//Gọi lại cỏc hàm DrawScene.
DrawScene(pDC);
//Thay đổi khung đệm
SwapBuffers(pDC->m_hDC);
//Trả lại bảng màu .
pDC->SelectPalette(OldPalette,0); wglMakeCurrent(NULL,NULL); }
3.7.8.Cỏc hàm DrawScene (được tạo thờm ).
Là cỏc hàm được tạo riờng ra để thực hiện cụng việc tụ vẽ với việc sử dụng cỏc hàm của OpenGL và được gọi lại vào trong hàm OnDraw .
Hàm glViewport để thay đổi gúc nhỡn của đối tượng, hàm glColor3d, glColor4d để tạo màu cho đối tượng….
3.7.9.Vớ dụ minh hoạ .
Khởi động VC++ 6.0 và mở một ứng dụng MFC AppWizard trờn mụi trường Single
cụng việc đơn giản là sử dụng thư viện đồ hoạ OpenGL để vẽ một khối hộp chữ nhật với hệ toạ độ oxyz và tụ màu cho chỳng .
Đầu tiờn , để sử dụng được openGl phải đưa thư viện GLU.LIB,
GLAUX.LIB và OpenGL32.LIB bằng cỏch chọn menu Project >Add to File > File ,
trong hộp thoại mở ra tỡm đến đường dẫn Microsoft Visual Studio >VC98>LIB và chọn cỏc thư viện để Insert nú vào ứng dụng :
Hỡnh 3.79.Đưa cỏc thư viện vào ứng dụng
Và copy cỏc file gl.h, glu.h, glaux.h trong thư mục GL vào ứng dụng .Trờn Files View chọn CMy3Dview.cpp để tiến hành gộp file :
#include "GL/gl.h" #include "GL/glu.h"
Mọi cụng việc sẽ chỉ làm trờn lớp CMy3DView.Mở File 3DView.cpp trong hàm
PreCreateWindow thờm vào cõu lệnh :
BOOL CMy3DView::PreCreateWindow(CREATESTRUCT& cs) {
cs.style|=WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
//Cõu lệnh này sẽ đảm bảo cho ứng dụng cú thể được thư viện đồ hoạ
return CView::PreCreateWindow(cs); }
Đặt và thiết lập định dạng Pixel cho màn hỡnh ứng dụng trong hàm OnCreate (giống như cỏch khởi tạo ở hàm OnInitDialog( ) trong mụi trường Dialog based ) :
int CMy3DView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; PIXELFORMATDESCRIPTOR pfd; int iPixelFormat; CDC*pDC;
memset(&pfd,0,sizeof(pfd)); pfd.nSize=sizeof(pfd); pfd.nVersion=1; pfd.dwFlags=PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL; pfd.iPixelType=PFD_TYPE_RGBA; pfd.iLayerType=PFD_MAIN_PLANE; pfd.cColorBits=24; pfd.cDepthBits=32; //Chọn và thiết lập Pixel iPixelFormat=ChoosePixelFormat(pDC->m_hDC,&pfd); SetPixelFormat(pDC->m_hDC,iPixelFormat,&pfd); //Tạo ngữ cảnh thiết bị tụ búng RC m_hglrc=wglCreateContext(pDC->m_hDC); ReleaseDC(pDC); return 0; }
Hoàn tất việc khởi tạo .Bước tiếp theo sẽ thực thi cỏc lệnh vẽ với OpenGL trong hàm
OnDraw tuy nhiờn để cho cấu trỳc chương trỡnh gọn gàng nờn đặt ra cỏc hàm vẽ riờng,
ở đõy sẽ tạo 2 hàm , hàm vẽ hệ toạ độ HeToaDo(CDC*pDC) và hàm vẽ khối hộp
HinhHop(CDC*pDC) sau đú gọi chỳng trong hàm OnDraw(CDC*pDC) để hoàn tất .
Trong File View chọn 3DView.h để thờm cỏc khai bỏo :
class CMy3DView : public CView {
………..
DECLARE_MESSAGE_MAP( ) public:
HGLRC m_hglrc;
//Biến này để lưu ngữ cảnh thiết bị để tụ búng
void HeToaDo(CDC*pDC); //Hàm vẽ hệ toạ độ
void HinhHop(CDC*pDC); //Hàm vẽ khối hộp
};
Quay trở lại File View và chọn 3DView.cpp để viết mó lệnh :
void CMy3DView::HeToaDo(CDC*pDC) {
glEnable(GL_LIGHTING); glEnable(GL_LIGHT0);
//Tạo ra cỏc chựm tối , sỏng để tạo sự tương phản
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//Xoỏ khung đệm, màu của màn hỡnh ứng dụng sẽ từ trắng sang đen .
glEnable(GL_COLOR_MATERIAL);
//Sẽ làm cho chức năng tụ màu cho vật thể cú hiệu lực với màu được định nghĩa ở //dưới glColor4d
glViewport(0,0,100,100);
glLoadIdentity();
glColor4d(0.0,0.0,1.0,1.0);
//Tạo màu cho nột vẽ //Tiến hành quay đối tượng
glRotated(10.0,1.0,0.0,0.0); //Quay quanh trục X
glRotated(30.0,0.0,1.0,0.0); //Quay quanh trục Y
glRotated(-10.0,0.0,0.0,1.0); //Quay quanh trục Z
glBegin(GL_LINES); //Tiến hành vẽ đường thẳng .
//Mọi cụng việc vẽ đều nằm trong cấu trỳc glBegin( ) ->glEnd( ); //Vẽ trục toạ độ
glVertex3f(0,0,0); Di chuyển tới điểm gốc 0 để vẽ
glVertex3f(0,0,1); //Vẽ trục Z glVertex3f(0,0,0); glVertex3f(0,1.0,0); //Vẽ trục Y glVertex3f(0,0,0); glVertex3f(1.0,0,0); //Vẽ trục X //Vẽ cỏc mũi tờn chỉ hướng glVertex3f(1,0,0); glVertex3f(0.8,0.1,0); glVertex3f(1,0,0); glVertex3f(0.8,-0.1,0); glVertex3f(1,0,0); glVertex3f(0.8,0,0.1); glVertex3f(0,1,0); glVertex3f(-0.1,0.8,0); glVertex3f(0,1,0); glVertex3f(0.1,0.8,0); glEnd( ); glFlush( ); } //……… Vẽ khối hộp chữ nhật : void CMy3DView::HinhHop(CDC*pDC) { glViewport(200,20,400,400); //Đặt gúc nhỡn glLoadIdentity(); //glClear(GL_UNSIGNED_INT); GLfloat light[4]={-10.0F,20.0F,100.0F,0.0F};
//Tham số đầu là độ tương phản giữa mặt bờn trỏi và mặt trước // Tham số thứ 2 là độ tương phản giữa mặt bờn trỏi và mặt trờn // Tham số thứ 3 là độ tương phản giữa mặt trờn và mặt trước
// Tham số thứ 3 là độ tương phản giữa mặt trước và cỏc mặt cũn lại
glRotated(15.0,1.0,0.0,0.0); //quay đối tượng 15 độ quanh trục X
glEnable(GL_LIGHT0); glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_POSITION,light);
//Chiếu sỏng lờn đối tượng bằng chựm sỏng light
glEnable(GL_COLOR_MATERIAL);// Thiết lập chế độ tụ màu cho bề mặt
glBegin(GL_QUADS); //Vẽ khối hộp glNormal3d(88.0,-5666.0,0.0); glVertex3d(0.5,-0.5,0.5); glVertex3d(-0.5,-0.5,0.5); glVertex3d(-0.5,-0.5,-0.5); glVertex3d(0.5,-0.5,-0.5); glNormal3d(2.0,99.0,-88.0); glVertex3d(-0.5,-0.5,-0.5); glVertex3d(-0.5,0.5,-0.5); glVertex3d(0.5,0.5,-0.5); glVertex3d(0.5,-0.5,-0.5); glNormal3d(1.0,0.0,0.0); glVertex3d(0.5,-0.5,-0.5); glVertex3d(0.5,0.5,-0.5); glVertex3d(0.5,0.5,0.5); glVertex3d(0.5,-0.5,0.5); glNormal3d(0.0,0.0,1.0); glVertex3d(-0.5,-0.5,0.5); glVertex3d(-0.5,0.5,0.5); glVertex3d(0.5,0.5,0.5); glVertex3d(0.5,-0.5,0.5); glNormal3d(-1.0,0.0,0.0); glVertex3d(-0.5,-0.5,0.5); glVertex3d(-0.5,0.5,0.5); glVertex3d(-0.5,0.5,-0.5); glVertex3d(-0.5,-0.5,-0.5); glNormal3d(0.0,1.0,0.0); glVertex3d(-0.5,0.5,0.5); glVertex3d(0.5,0.5,0.5); glVertex3d(0.5,0.5,-0.5); glVertex3d(-0.5,0.5,-0.5); glEnd(); glFlush(); wglMakeCurrent(NULL,NULL);
}
//………
Bõy giờ chỉ là gọi cỏc hàm này vào trong hàm OnDraw để thực thi lệnh :
void CMy3DView::OnDraw(CDC* pDC) {
CMy3DDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); wglMakeCurrent(pDC->m_hDC,m_hglrc); //Tạo ra ngữ cảnh thiết bị để tụ búng . HeToaDo(pDC); HinhHop(pDC); SwapBuffers(pDC->m_hDC); }
Ấn F5 để biờn dịch chương trỡnh , dưới đõy là kết quả :