Khi người dùng nhấn mouse trên hình ảnh của đối tượng 3D tại một tọa độ màn hình gồm hai thành phần (x,y), ta phải xác định xem tọa độ này thuộc đối tượng nào. Thư viện OpenGL cung cấp cho chúng ta ba giải pháp để thực hiện việc này.
a. Dùng cơ chế chọn lựa của OpenGL.
OpenGL cung cấp một cơ chế rất mạnh để chọn các đối tượng không gian từ một vùng tọa độ trên viewport.
OpenGL có ba chế độ dựng ảnh RENDER, SELECT và FEEDBACK. Chế độ
RENDER là chế độ chính dùng để xây dựng các hình ảnh 3D của đối tượng từ các dữ liệu về đỉnh, ánh sáng, màu…Chế độ FeedBack tương tự chế độ Render tuy nhiên đích
đến của việc dựng ảnh khơng là buffer của màn hình mà là buffer của người dùng. Cịn
trong chế độ Select, OpenGL chỉ kiểm tra xem đối tượng 3D có nằm trong một vùng viewport do người dùng định nghĩa.
Khi tiến hành render các đối tượng, mỗi đối tượng sẽ được gán một tên là một số
nguyên. Các tên này được OpenGL lưu trữ thông qua một stack – namestack. Mỗi khi OpenGL render các đối tượng này có một pixel nằm trong vùng chọn thì OpenGL sẽ chuyển toàn bộ nội dung của name stack sang một bộ đệm do người dùng định nghĩa. Từ nội dung của bộ đệm này ta có thể dễ dàng phát hiện ra đối tượng nào đã được
chọn. Sau đây là khung mã của việc chọn đối tượng qua cơ chế Select.
glSelectBuffer(size, buffer); // buffer chứa name của các đối tượng. glRenderMode(GL_SELECT); // chuyển sang chế độ select.
glMatrixMode(GL_PROJECTION); // thiết lập ma trận chiếu. glLoadIdentity();
glPickMatrix(x,w,w,h,viewport); // xác định vùng chọn. gluPerspective(…);
glMatrixMode(GL_MODEL_VIEW); glInitName();
// xác định các đối tượng bằng các vertex của chúng.
int hitcount = glRenderMode(GL_RENDER); // chuyển sang chế độ render và xác định số đối tượng nằm trong vùng chọn.
Đây là một phương pháp rất mạnh của OpenGL, tuy nhiên nó địi hỏi q trình tính
tốn khá nhiều, đặc biệt là khi số lượng đối tượng là rất lớn, khi đó có thể ảnh hưởng
đến hiệu suất của chương trình nếu việc xác định các đối tượng được chọn được tiến
hành thường xuyên, liên tục.
Luận văn tốt nghiệp GVHH: Nguyễn Hữu Hải.
OpenGL cung cấp các hàm chiếu để chuyển từ tọa độ cửa sổ (window coordinate)
sang tọa độ của đối tượng (object coordinate) hay tọa độ thế giới của GL ( world
coordinate) thông qua phép chiếu ngược.
glUnProject(xw,yw,zw,modelMatrix,projectMatrix,viewport,xo,yo,oz)
Trong đó (xw,yw,zw) là ba thành phần của tọa độ cửa số cần đổi. Thành phần xw được xác định bằng tọa độ x của mouse, thành phần yw được xác định bằng cách lấy chiều dài của viewport trừ đi thành phần tọa độ y của mouse (do hệ tọa độ màn hình có trục y hướng xuống). Cịn thành phần zw được xác định lần lược bằng 0 và 1. Qua hai phép chiếu ta xác định được hai điểm nằm trên mặt cắt gần và mặt cắt xa. Từ hai điểm này ta xây đựng một đoạn thẳng rồi đem nó giao với các đối tượng Tin để tìm ra tọa dộ mà người dùng đã chọn. Từ đó, xác định ra đối tượng Tin thực sự được chọn.
Phương pháp này rất tổng quát và xác định được tọa độ thực sự mà người dùng nhấn vào một đối tượng, nó đặc biệt cần thiết trong trường hợp đối tượng Tin có nhiều hơn một điểm như tam giác. Tuy nhiên, việc tính tốn để xác định một đối tượng vẫn còn cần phải thực hiện nhiều phép tính tốn số thực dấu chấm động để có thể xác định ra
đối tượng mà người dùng muốn chọn. Mặc dù ta có thể hạn chế bớt các phép tính này
thơng qua phép chỉ mục đa chiều đã được trình bày ở phần cơ sở dữ liệu.
c. Dùng cơ chế Double Buffer.
Doubel Buffer được dùng để tăng tốc quá trình hiển thị hình ảnh của OpenGL. Các câu lệnh của OpenGL khi được render sẽ tạo nên những pixel ảnh. Các pixel này được chứa ở một bộ đệm. Sau khi q trình render hồn tất, GL mới đổ nội dung bộ đệm ra màn hình, do đó q trình render được hiển thị nhanh hơn, giảm thiểu hiện tượng flicker khi render ảnh. Cơ chế này được gọi là Double Buffer. Như vậy tại mỗi thời
điểm ln có Front Buffer chứa nội dung hình ảnh hiển thị trên màn hình, và back
buffer chứa nội dung ảnh sẽ hiển thị tiếp theo. Do đó nội dung của back buffer và front buffer có thể hồn tồn khác nhau. Tất cả những câu lệnh của GL đều tác động lên back buffer mà hồn tồn khơng ảnh hưởng đến hình ảnh đang được hiển thị trên màn hình. Như vậy ta có thể tận dụng tính chất này để xác định một cách nhanh chóng các
đối tượng 3D.
Đầu tiên, ngay khi quá trình render ảnh kết thúc bằng lệnh glFlush() và nội dung của
back buffer được đổ vào front buffer bằng lện SwapBuffer(), ta tiến hành render lại một lần nữa toàn bộ khung ảnh. Tuy nhiên ở lần render này, thay vì vẽ đối tượng bằng màu sắc bình thường, ta dùng định danh của đối tượng để tô màu, định danh này là một số nguyên. Để tăng độ chính xác của phương pháp này, ta phải tắt tất cả các hiệu
ứng về ánh sáng, pha trộn, khử răng cưa v.v…. Khi đó, khi người dùng click mouse tại
một tọa độ nào đó, bằng thủ tục glReadPixels() để xác định pixel màu tại vị trí mouse trong back buffer. Từ giá trị màu này ta hồn tồn có thể xác định được đối tượng nào
được chọn.
Phương pháp này đơn giản và đạt hiệu quả rất cao trong trường hợp ta phải xác định
đối tượng tại một vị trí có tọa độ 2D trên màn hình. Việc render lại các đối tượng hình ảnh chỉ làm một lần rồi sau đó ta có dùng để xác định các đối tượng tại các vị trí bất kỳ
một cách rất nhanh chóng và rất đơn giản chỉ thơng qua các phép tính đơn giản nên nó hồn tồn khơng ảnh hưởng đến performance của tồn chương trình. Điều này đặc biệt quan trọng, nó này cung cấp cho ta khả năng theo dõi các đối tượng theo sự di chuyển của mouse chứ không nhất thiết phải đợi người dùng click mouse. Ở phần sau, ta sẽ thấy điều khiển World3D sử dụng phương pháp này để giả lập các event:
OnMouseMove ,OnMouseEnter và OnMouseLeave đối với các đối tượng 3D, trong
khi nếu áp dụng hai phương pháp trên thì việc xử lý các biến cố này thật sự là một gánh nặng cho CPU.