intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

[C/C++] Đồ họa với OpenGL

Chia sẻ: Abcdef_45 Abcdef_45 | Ngày: | Loại File: PDF | Số trang:6

238
lượt xem
37
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Lập trình 3D thì phổ biến nhất là dùng Direct3D hoặc OpenGL. Direct3D chỉ dùng được trên Windows, còn OpenGL đã là Industrial Standard từ khá lâu và có thể dùng được trên mọi OS. Nếu không bị bắt buộc phải dùng Direct3D, nên chọn OpenGL Để học OpenGL, có lẽ không thể thiếu cuốn OpenGL Programming Guide, còn gọi là The Red Book. Ngoài ra nên tham khảo tutorial trên NeHe  

Chủ đề:
Lưu

Nội dung Text: [C/C++] Đồ họa với OpenGL

  1. [C/C++] Đồ họa với OpenGL Lập trình 3D thì phổ biến nhất là dùng Direct3D hoặc OpenGL. Direct3D chỉ dùng được trên Windows, còn OpenGL đã là Industrial Standard t ừ khá lâu và có thể dùng được trên mọi OS. Nếu không bị bắt buộc phải dùng Direct3D, nên chọn OpenGL Để học OpenGL, có lẽ không thể thiếu cuốn OpenGL Programming Guide, còn gọi là The Red Book. Ngoài ra nên tham khảo tutorial trên NeHe Dùng thư viện cấp cao kiểu graphics hay game engine, nh ư Irrlicht vs  Ogre3D. Các này thì không cần biết OpenGL là gì. Dùng trực tiếp API do OpenGL cung cấp kèm hoặc không kèm thư viện  AUX. AUX là thư viện để tạo cửa sổ và quản lí input từ chuột, bàn phím. Không dùng AUX thì ta ph ải tự làm các việc trên. Nếu dùng AUX thì chương trình sẽ cross-platform Cách viết chương trình Bước 0 - Khai báo file header và library File header c ủa OpenGL thường được đặt riêng trong folder gl, nên khai:  #include gl\gl.h Chỉ với gl.h, đã có thể làm mọi thứ liên quan đến OpenGL. Tuy nhi ên để tiết kiệm thời gian, có thể xài một số utility function. Những utility function n ày nằm trong glu.h: #include gl\glu.h Function của gl.h và glu.h có prefix tương ứng là gl và glu. Sau khi compile, để link thành chương trình .exe, cần khai file library Nếu chỉ include gl.h, chỉ cần khai file opengl32.lib. Nếu x ài thêm glu.h thì khai thêm glu32.lib. Phần khai này tùy compiler/linker, nếu xài IDE của Visual C++ 6 thì vào Project -> Settings -> Link, rồi gõ file .lib thích hợp vào Object/library modules. Fig2. Khai library
  2. Mẹo: với Visual C++, có thể khai file library ngay trong source code, chú ý không có dấu chấm phẩy. #pragma comment(lib, "opengl32.lib") #pragma comment(lib, "glu32.lib") Bước 1 - Khởi tạo  1.1 - Lấy device context của window Trong Windows, m ọi thứ đều là window. Muốn vẽ hình 3D lên window nào thì lấy device context của window đó. Để lấy device context của window n ào, phải có handle c ủa window đó. Ex: Chương trình Dialog based, xài MFC. Trên dialog đặt 1 cái Static Text có id l à IDC_STATIC_OPENGL, hình 3D sẽ được vẽ lên đây. Fig3. Static Text đã được kéo to ra HWND m_StaticWnd; // global HDC m_StaticDC; // global m_StaticWnd = ::GetDlgItem(m_hWnd, IDC_STATIC_OPENGL); // m_hWnd là handle c ủa dialog m_StaticDC = ::GetDC(m_StaticWnd); Để phân biệt, khi xài API function trực tiếp, thêm dấu :: đằng trước. Bây giờ khi đã có device context c ủa Static Text. Vì device context này chỉ được release khi thoát chương trình, nên khai báo thêm m_StaticWnd và m_StaticDC trong phần global. 1.2 - Thay đổi pixel format của device context Device context c ần được thay đổi phù hợp để OpenGL có thể vẽ lên đó. PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 24, 0, 0, 0, 0, 0, 0,
  3. 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0 }; int PixelFormat = ::ChoosePixelFormat(m_StaticDC, &pfd); ::SetPixelFormat(m_StaticDC, PixelFormat, &pfd); Các tham số có thể tham khảo trong MSDN. PFD_DOUBLEBUFFER - Khi có tham số này, OpenGL không vẽ trực tiếp lên device context, mà sẽ vẽ lên buffer. Muốn hiện buffer này lên màn hình, sẽ swap buffer này với device context, xem bước 2. Nếu OpenGL vẽ trực tiếp lên device context, tốc độ sẽ rất chậm, vì vẽ được cái gì thì sẽ phải update lên màn hình cái đấy ngay. - PFD_SUPPORT_GDI và PFD_DOUBLEBUFFER là mutually exclusive, nên các thao tác GDI trên device context này sẽ không có tác dụng. 1.3 - Tạo renderring context cho OpenGL Bước này báo cho OpenGL biết sẽ vẽ lên device context nào. HGLRC m_OpenGLRC; // global m_OpenGLRC = wglCreateContext(m_StaticDC); wglMakeCurrent(m_StaticDC, m_OpenGLRC); Muốn OpenGL vẽ lên device context nào, wglMakeCurrent đến device context đó. Rendering context này chỉ được delete khi thoát ch ương trình, nên khai báo trong phần global. 1.4 - Setup trạng thái cho OpenGL Điều chỉnh góc nhìn, màu nền,.. như sau: // xóa đen window glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); glFlush(); // chỉnh viewport RECT rect; ::GetWindowRect(m_StaticWnd, &rect); int width = rect.right - rect.left;
  4. int height = rect.bottom - rect.top; glViewport(0, 0, width, height); // chỉnh góc nhìn double aspect = (double)width/height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, 0.1, 1000); // chọn rendering mode glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDrawBuffer(GL_BACK); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); Để hiểu rõ, tham khảo thêm MSDN. Nếu size của window bị thay đổi, nên gọi lại phần "chỉnh viewport" và "chỉnh góc nhìn". Bước 2 - Update window  Chỉ nên update window khi chương trình ở trong trạng thái idle. Xem ghi chú về idle ở c uối bài viết này. Render(); // gọi Render SwapBuffers(m_StaticDC); // swap buffer v ới device context -> hiện buffer lên màn hình Muốn vẽ cái gì lên window thì vẽ ở Render. Vì phần vẽ này thường rất dài và phức tạp, nên mới được tách ra thành 1 function. void Render() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // xóa toàn bộ glPushMatrix(); // OpenGL painting commands go here, dài và ph ức tạp lắm nghe :p glPopMatrix(); } glPushMatrix và glPopMatrix dùng để lưu và phục hồi trạng thái của OpenGL. Nếu trong painting commands có command nào đó làm thay đổi trạng thái của
  5. OpenGL, mà Render không lưu và ph ục hồi trạng thái ban đầu, thì sau vài lần gọi Render, hình vẽ hiển thị lên màn hình sẽ không như ý muốn. Nhớ rằng OpenGL là state machine. Bước 3 - Dọn dẹp  Khi chương trình chương trình kết thúc, cần release device context và delete rendering context. ReleaseDC(m_StaticWnd, m_StaticDC); // đây là lí do tôi khai m_StaticWnd trong phần global wglMakeCurrent(NULL, NULL); wglDeleteContext(m_OpenGLRC); Fig4. In Action Ghi chú về idle 1. Chương trình Dialog based, xài MFC  Không xài được cả WM_ENTERIDLE lẫn CWinApp::OnIdle() => xài WM_KICKIDLE trong afxpriv.h File header c ủa dialog, phần message map, thêm: afx_msg LRESULT OnKickIdle(WPARAM , LPARAM); File implementation c ủa dialog, thêm: Code: #include ON_MESSAGE(WM_KICKIDLE, OnKickIdle) LRESULT CMyDlg::OnKickIdle(WPARAM wParam, LPARAM lParam) { Render(); SwapBuffers(m_StaticDC); return 0; } 2. Chương trình BCB  __fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner) { Application->OnIdle = OnIdle;
  6. _control87(MCW_EM, MCW_EM); } void __fastcall TForm1::OnIdle(TObject* Sender, bool &d one) { done = false; Render(); SwapBuffers(m_StaticDC); }  3. Chương trình Win32 Cách 1: Xài WM_ENTERIDLE Cách 2: While (!done) { // is there a msg waiting? if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) done = TRUE; else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { Render(); SwapBuffers(m_StaticDC); } } Bài viết được sưu tầm tại Blog cộng đồng CNTT.
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2