Cổng nhìn là một miền hình chữ nhật nằm phía trong một cửa sổ (window) đang mở trên màn hình cho phép hiển thị hình ảnh. Hình ảnh của vật thể sau khi được chiếu lên khung nhìn sẽ được ánh xạ lên cổng nhìn. Ta có thể định nghĩa nhiều cổng nhìn để hiển thị nhiều khung cảnh khác nhau trên cửa sổ. Định nghĩa cổng nhìn ta dùng câu lệnh sau:
glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
Trong đó (x,y) xác định tọa độ góc trái phía dưới của cổng nhìn, tọa độ này là tọa độ trong cửa sổ đang mở. Góc trái phía dưới của cửa sổ có tọa độ là (0,0). Hai tham số width và height là chiều rộng và chiều cao của khung nhìn. Ở chế độ mặc định giá trị tham số của khung nhìn là (0, 0, winWidth, winHeight) trong đó winWidth và
winHeight là kích thước của cửa sổ nơi hiển thị khung nhìn.
Để định nghĩa của sổ trên màn hình ta dùng hai câu lệnh sau của GLUT:
glutInitWindowPosition (int x, int y); //Chỉ định vị trí góc trái trên của cửa sổ trong hệ tọa độ xoy của màn hình (Hình 2.11)
glutInitWindowSize (int Width, int Height); //Chỉ định kích thước của cửa sổ (pixels), hai kích thước thường được chọn bằng nhau để hình không bị méo Tỉ lệ hai kích thước của cổng nhìn nên chọn bằng với tỉ lệ hai kích thước của khung nhìn. Nếu hai tỉ lệ này không bằng nhau thì hình ảnh hiển thị trên màn hình sẽ bị méo (distorted).
\
Hình không bị méo Hình bị méo Hình 2.13 Ảnh được ánh xạ từ khung nhìn lên cổng nhìn
4.3.5. Điều khiển các ngăn xếp ma trận ( Matrix Stacks)
OpenGL biểu diễn các phép biến đổi điểm nhìn và mô hình bằng ngăn xếp ma trận Modelview (Modelview matrix stack). Ngăn xếp này có tối đa là 32 phần tử là các ma trận vuông 4x4 tương ứng các phép biến đổi tác động lên đối tượng vẽ và ma trận hiện thời luôn là ma trận nằm trên đỉnh của stack. Mỗi một phép biến đổi điểm nhìn hoặc biến đổi mô hình tạo ra một ma trận mới, ma trận này được nhân với ma trận hiện thời và kết quả trở thành ma trận hiện thời mới (ngăn xếp thêm 1 phần tử mới trên đỉnh).
Để biểu diễn các phép chiếu, OpenGL sử dụng một ngăn xếp khác được gọi là ngăn xếp ma trận phép chiếu (Projection matrix stack) gồm tối đa 2 phần tử ma trận vuông 4x4. Ma trận hiện thời mô tả phép chiếu đang được áp dụng cho đối tượng vẽ, hay nói cách khác ma trận này mô tả viewing volume.
Hình 2.14
Ngăn xếp
ma trận modelview và ma trận phép chiếu Ta có thể điều khiển ma trận hiện thời bằng các câu lệnh sau:
glLoadIdentity(); //Thiết lập ma trận hiện thời về ma trận đơn vị
glLoadMatrix{fd}(const TYPE *m); // Thiết lập giá trị cho ma trận hiện thời từ 16 giá trị được trỏ bởi m (m là ma trận một chiều hoặc hai chiều)
glMultMatrix{fd}(const TYPE *m); //Nhân ma trận có 16 giá trị được trỏ bởi m với ma trận hiện thời, kết quả là ma trận hiện thời mới
glPushMatrix(); //Sao chép thêm một ma trận hiện thời và đưa lên đỉnh của ngăn xếp
Hình 2.15 Sao chép và loại bỏ ma trận hiện thời
Lệnh glPushMatrix(); được hiểu là "Ghi nhớ ta đã ở đâu" (remember where you are) và glPopMatrix(); được hiểu là "Quay lại vị trí ta đã ở" (go back to where you were). Đây là hai câu lệnh rất hữu ích của OpenGL.
Việc tổ chức các ma trận theo ngăn xếp là rất phù hợp khi ta cần xây dựng các mô hình có sự phân cấp (hierarchical models) trong đó một đối tượng phức tạp được xây dựng từ những đối tượng đơn giản hơn. Đặc biệt khi đó là một hình ảnh động, sụ thay đổi trạng thái của một bộ phận kéo theo sự thay đổi của nhiều bộ phận khác.
Giả sử ta có đoạn chương trình như sau mô tả chuyển động một cánh tay của một robot: glTranslatef(); //Lệnh T1 glRotatef(); //Lệnh T2 glPushMatrix(); glTranslatef(); //Lệnh T3 glRotatef(); //Lệnh T4
gluCylinder(); //Vẽ cánh tay phía dưới glPopMatrix(); glScalef(); //Lệnh T5
gluCylinder(); //Vẽ cánh tay phía trên
Đoạn chương trình trên có thể có thể được diễn tả bởi sơ đồ sau T1→ T2→ T5→ Cánh tay phía trên
T3→ T4→ Cánh tay phía dưới
Muốn biết ảnh hưởng của các câu lệnh với hai hình lăng trụ ta duyệt sơ đồ trên theo thứ tự ngược lại.
Đây là những gì tác động lên cánh tay phía trên: T5: Kéo dãn đối tượng
T2: Quay đối tượng quanh một trục xuyên qua tâm của nó T1: Tịnh tiến đối tượng
Đây là những gì tác động lên cánh tay phía dưới:
tượng
T2: Quay đối tượng một lần nữa, lần này trục quay không qua tâm của nó T1: Tịnh tiến đối tượng một lần nữa
Nhận xét:
- Phép quay T2 tương đương với động tác quay tại khớp vai và phép quay T4 tương đưong với động tác quay tại khuỷu tay
- T3 và T4 nằm giữa hai lệnh glPushMatrix() và glPopMatrix() chỉ tác động lên cánh tay phía dưới
- Lệnh T1 và T2 tác động lên cánh tay phía trên và đương nhiên cũng có tác động đến cánh tay phía dưới vì khi cánh tay phía trên chuyển động thì cánh tay phía dưới cũng chuyển động theo.
Phần B. Ví dụ mô phỏng
Phần ví dụ này, nhóm Sử dụng VC++ kết hợp với OpenGl để mô phỏng động học robot. Nhóm em xin trình bày chi tiết như sau:
I. Môi trường làm việc trong VC++:
Trong hộp thoại này ta chọn MFC app Winzard(exe):tạo ứng dụng win32 với thư viện MFC.
Sau khi nhấn Finish, Winzard sẽ tạo cho chúng ta 5 lớp cơ bản: CDIEUApp: Đây là lớp dung để đăng ký tạo một ứng dụng CDIEUDoc: Đây là lớp để lưu trữ dữ liệu
CDIEUView: Đây là lớp cài đặt những gì thể hiện lên màn hình của ứng dụng CAboutDlg: Đây là lớp quản lý một Dialog mà mục đích của Wizard cung cấp cho chúng ta để hiển thị thông tin
CmainFrame: dùng để quản lý,khởi tạo các khung ứng dụng,các ToolBar,Menu… Ngoài ra chúng ta còn được cung cấp 3 thể để quản lý dự án:
+Thẻ Class View: dùng để quản lý lớp và các hàm tự do nằm trong dự án +Thẻ ResourceView: dùng quản lý các tài nguyên của dự án
+Thẻ FileView:Quản lý các file nằm trong dự án.
Thêm thư viện OpenGL cho ứng dụng và thêm các file khai báo và cài đặt(ST_SplitterWnd.CPP và ST_SplitterWnd.H)
Khai báo và sử dụng lớp ST_SplitterWnd: Đây là lớp dung để chia đôi khung ứng dụng khi chạy chương trình.Ta nhấn đúp vào lớp CMainFrame trong ClassView/file MainFrm.h
Ta phải khai báo thêm :
#include"Splitter/ST_SplitterWnd.h"
Ngoài ra khi sử dụng thư viện OpenGl thì ta phải khai báo trong lớp View
#include "OpenGL_LIB\ObjectsOpenGL.h" using namespace ObjectsOpenGL;
Đồng thời khai báo các biến con trỏ để khởi tạo thiết bị vẽ và môi trường vẽ:
Ta tiến hành thiết lập môi trường đồ hoạ OpenGL trong File DIEUView.CPP
II- Sử dụng VC++ kết hợp với OpenGl để mô phỏng động học robot
Tiếp theo ta sẽ thêm tài nguyên Dialog vào để tạo ra được các form hiển thị cũng như các nút điều khiển (<< >>)
Sauk hi hộp thoại hiện ra thì chọn IDD_FORMVIEW thì ta sẽ thấy hình ảnh form để design được thông qua control bar(có thể đặt tên của formview này thành 1 cái tên khác cho dễ quản lý.( Đối với việc chèn các biểu tượng như biểu tượng trường hay hình ảnh nào đó cũng làm tương tự, ta chỉ việc đổi từ chọn IDD_FORMVIEW thành
BITMAP thôi.)).
Từ trên phần điều khiển formview mà ta vừa design, click chuột phải và chọn Class wizard, sau khi nhấn OK nó sẽ ra bảng sau: Ta nhập tên nào đó vào( ví dụ là CCTRPANEL), lớp cơ sở là CFormView.
Thêm một số thuộc tính vào lớp CMainFrame để chia đôi khung ứng dụng( nếu không thì rất khó để quản lý và điều chỉnh).
Tiếp theo, thêm các hàm Oncreate, On Destroy, và Onsize vào để có thể thay đổi kích thước hay giá trị:
Nhấn Ctrl+W. Sau đó chọn lớp CMainFrame ở trên class name, chọn CMainFrame ở Object IDs, Bên hộp messages chọn OnCreateClient. Sau khi nhấn edit code thì hàm BOOL CMainFrame:: OnCreateClient hiện ra, edit lại hàm như bên dưới:
Chú ý là nếu đặt giá trị biến là
1( m_Splitter.Create(this,RUNTIME_CLASS(CCTRPANEL),RU
NTIME_CLASS(CCNCView),pContext,1) thì sẽ chia đôi theo hang dọc, còn 0 thì chia đôi theo hàng ngang.
Tuy nhiên khi biên dịch chương trình có thể sẽ xảy ra hiện tượng lỗi, điều này có thể xảy ra khi ta đã sử dụng con trỏ *GetDocument() của lớp CCNCDoc mà chưa khai báo. Ta vào lớp CCNCView.h để sửa lại:
Class CCNCDoc; vào.
Như vậy là cũng đã tương đối ổn rồi, tiếp theo ta chỉnh sửa trong project để link thư viện OpenGL vào dự án. Tiếp theo cài đặt hàm OnInitialUpdate() để có thể Update các khâu, khớp cũng như những thay đổi của robot:
Như vậy công đoạn cũng gần hoàn thiện, tiếp theo ta xây dựng hàm vẽ vật thể( Robot hay cơ cấu máy chúng ta đã thiết kế sẵn trên Solids, Catia hay Inventor rồi, sau đó ta lưu định dạng các file này dưới dạng *.STL), hàm OnDraw này sẽ chỉ có nhiệm vụ là kết nối các file này vào và lắp ghép chúng theo sự điều khiển củaât.Ta cần chú ý một điều là khoảng cách cũng như góc quay nó sẽ được tính theo khoảng cách của từng chi tiết (các part bạn thiết kế 3D) và được bắt đầu làm mốc từ O(0,0,0). Nếu ta đặt hệ tọa độ địa phương(coordinate) thì ta sẽ dựa vào đó để thực hiện hàm tịnh tiến và hàm quay.
Tuy nhiên, thông thường người ta sẽ không vẽ trực tiếp trên hàm OnDraw này mà dùng hàm OnDraw để quản lý hàm paint():
void CPSKView::OnDraw(CDC* pDC) {
CPSKDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);
Paint(); }
Để có được hàm Paint() ta click chuột phải vào lớp CCNCView và chọn Add Member Function và làm như bên dưới:
chính là phần mà dùng cài đặt màu của từng chi tiết.
Sau khi chỉnh sửa, ta có được hình ảnh của robot thông qua cửa sổ View. Việc tiếp theo ta cài đặt chương trình tính toán cho robot. Muốn được điều này ta phải có được bảng thông số động học cũng như giải được phương trình động học ngược. Khi đã có tất cả những thứ trên rồi, ta tiếp tục vào lớp CCTRPANEL để tạo ra hàm Calculate() (Cách làm tương tự hàm paint()).
Ta viết chương trình tính toán vào hàm đó. Khi đó ta sẽ thấy được các chuyển động của robot theo chương trình tính toán:
Ngoài ra, để tạo các hiệu ứng như kéo nhả chuột, rê chuột.. chúng ta cũng có thể làm được bằng các hàm như OnLButtonDown() OnLButtonUp(), OnMouseMove(), OnMouseWheel()…Muốn có được các hàm này hãy nhìn bên hình vẽ dưới:
Vậy nhóm em đã hướng dẫn cách mô phỏng chương trình robot thông qua VC++. Tất nhiên sẽ phải sửa nhiều chương trình thì mới chạy được.Sau đây là bonus một số chương trình hoàn thiện:
TÀI LIỆU THAM KHẢO [1] http://www.videotutorialsrock.com/
[2] Lập trình Opengl với thư viện AUX - Bùi Minh Trường
[3] The OpenGL Utility Toolkit (GLUT) Programming Interface - Mark J. Kilgard.
[4] www.hua.edu.vn
[5]. Đề tài OpenGL các khóa trước …….