Tôi quyết định viết một chút về khía cạnh lập trình và cách các thành phần nói chuyện với nhau. Có lẽ nó sẽ làm sáng tỏ một số khu vực nhất định.
Sự trình bày
Điều gì làm cho thậm chí có hình ảnh duy nhất, mà bạn đã đăng trong câu hỏi của bạn, được vẽ trên màn hình?
Có nhiều cách để vẽ một hình tam giác trên màn hình. Để đơn giản, giả sử không có bộ đệm đỉnh được sử dụng. (Bộ đệm đỉnh là một vùng bộ nhớ nơi bạn lưu trữ tọa độ.) Giả sử chương trình chỉ đơn giản là nói với đường ống xử lý đồ họa về mọi đỉnh đơn (một đỉnh chỉ là tọa độ trong không gian) liên tiếp.
Nhưng , trước khi chúng ta có thể vẽ bất cứ thứ gì, trước tiên chúng ta phải chạy một số giàn giáo. Chúng ta sẽ thấy lý do sau:
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Drawing Using Triangles
glBegin(GL_TRIANGLES);
// Red
glColor3f(1.0f,0.0f,0.0f);
// Top Of Triangle (Front)
glVertex3f( 0.0f, 1.0f, 0.0f);
// Green
glColor3f(0.0f,1.0f,0.0f);
// Left Of Triangle (Front)
glVertex3f(-1.0f,-1.0f, 1.0f);
// Blue
glColor3f(0.0f,0.0f,1.0f);
// Right Of Triangle (Front)
glVertex3f( 1.0f,-1.0f, 1.0f);
// Done Drawing
glEnd();
Vậy điều đó đã làm gì?
Khi bạn viết chương trình muốn sử dụng card đồ họa, bạn thường sẽ chọn một số loại giao diện cho trình điều khiển. Một số giao diện nổi tiếng với trình điều khiển là:
Trong ví dụ này, chúng tôi sẽ gắn bó với OpenGL. Bây giờ, giao diện của bạn với trình điều khiển là thứ cung cấp cho bạn tất cả các công cụ bạn cần để làm cho chương trình của bạn nói chuyện với card đồ họa (hoặc trình điều khiển, sau đó nói chuyện với thẻ).
Giao diện này chắc chắn sẽ cung cấp cho bạn một số công cụ nhất định . Các công cụ này có hình dạng của API mà bạn có thể gọi từ chương trình của mình.
API đó là những gì chúng ta thấy đang được sử dụng trong ví dụ trên. Hãy xem xét kỹ hơn.
Giàn giáo
Trước khi bạn thực sự có thể thực hiện bất kỳ bản vẽ thực tế nào, bạn sẽ phải thực hiện thiết lập . Bạn phải xác định chế độ xem của mình (khu vực sẽ thực sự được hiển thị), phối cảnh của bạn ( máy ảnh vào thế giới của bạn), bạn sẽ sử dụng loại khử răng cưa nào (để làm phẳng hình tam giác của bạn) ...
Nhưng chúng tôi sẽ không nhìn vào bất kỳ điều đó. Chúng tôi sẽ chỉ xem qua những thứ bạn sẽ phải làm mọi khung hình . Như:
Xóa màn hình
Các đường ống đồ họa sẽ không xóa màn hình cho bạn mọi khung hình. Bạn sẽ phải nói với nó. Tại sao? Đây là lý do tại sao:
Nếu bạn không xóa màn hình, bạn sẽ chỉ cần vẽ lên mọi khung hình. Đó là lý do tại sao chúng tôi gọi glClear
với GL_COLOR_BUFFER_BIT
bộ. Các bit khác ( GL_DEPTH_BUFFER_BIT
) báo cho OpenGL để xóa bộ đệm độ sâu . Bộ đệm này được sử dụng để xác định các pixel ở phía trước (hoặc phía sau) các pixel khác.
Biến đổi
Nguồn hình ảnh
Biến đổi là phần mà chúng ta lấy tất cả các tọa độ đầu vào (các đỉnh của tam giác) và áp dụng ma trận ModelView của chúng ta. Đây là ma trận giải thích cách mô hình của chúng tôi (các đỉnh) được xoay, thu nhỏ và dịch (di chuyển).
Tiếp theo, chúng tôi áp dụng ma trận Chiếu của chúng tôi. Điều này di chuyển tất cả các tọa độ để chúng đối mặt với máy ảnh của chúng tôi một cách chính xác.
Bây giờ chúng tôi biến đổi một lần nữa, với ma trận Viewport của chúng tôi. Chúng tôi làm điều này để mở rộng mô hình của chúng tôi theo kích thước của màn hình của chúng tôi. Bây giờ chúng ta có một tập hợp các đỉnh đã sẵn sàng để được hiển thị!
Chúng ta sẽ quay lại để biến đổi một chút sau.
Đang vẽ
Để vẽ một hình tam giác, chúng ta chỉ cần nói với OpenGL để bắt đầu một danh sách các hình tam giác mới bằng cách gọi glBegin
với GL_TRIANGLES
hằng số.
Ngoài ra còn có các hình thức khác bạn có thể vẽ. Giống như một dải tam giác hoặc một quạt tam giác . Đây chủ yếu là tối ưu hóa, vì chúng yêu cầu ít giao tiếp giữa CPU và GPU để vẽ cùng một số lượng tam giác.
Sau đó, chúng tôi có thể cung cấp một danh sách gồm 3 đỉnh sẽ tạo thành mỗi tam giác. Mỗi tam giác sử dụng 3 tọa độ (như chúng ta đang ở trong không gian 3D). Ngoài ra, tôi cũng cung cấp một màu cho mỗi đỉnh, bằng cách gọi glColor3f
trước khi gọi glVertex3f
.
Độ bóng giữa 3 đỉnh (3 góc của tam giác) được tính toán bằng OpenGL tự động . Nó sẽ nội suy màu trên toàn bộ mặt của đa giác.
Sự tương tác
Bây giờ, khi bạn nhấp vào cửa sổ. Ứng dụng chỉ phải chụp thông báo cửa sổ báo hiệu nhấp chuột. Sau đó, bạn có thể chạy bất kỳ hành động trong chương trình của bạn mà bạn muốn.
Điều này trở nên khó khăn hơn rất nhiều khi bạn muốn bắt đầu tương tác với cảnh 3D của mình.
Trước tiên, bạn phải biết rõ pixel mà người dùng đã nhấp vào cửa sổ. Sau đó, tính đến viễn cảnh của bạn , bạn có thể tính toán hướng của tia, từ điểm chuột nhấp vào cảnh của bạn. Sau đó, bạn có thể tính toán nếu có bất kỳ đối tượng nào trong cảnh của bạn giao nhau với tia đó . Bây giờ bạn biết nếu người dùng nhấp vào một đối tượng.
Vì vậy, làm thế nào để bạn làm cho nó xoay?
Biến đổi
Tôi biết hai loại biến đổi thường được áp dụng:
- Chuyển đổi dựa trên ma trận
- Chuyển đổi dựa trên xương
Sự khác biệt là xương ảnh hưởng đến các đỉnh đơn . Ma trận luôn ảnh hưởng đến tất cả các đỉnh được vẽ theo cùng một cách. Hãy xem xét một ví dụ.
Thí dụ
Trước đó, chúng tôi đã tải ma trận danh tính trước khi vẽ tam giác của chúng tôi. Ma trận danh tính là một ma trận đơn giản không cung cấp sự biến đổi nào cả. Vì vậy, bất cứ điều gì tôi vẽ, chỉ bị ảnh hưởng bởi quan điểm của tôi. Vì vậy, tam giác sẽ không được quay ở tất cả.
Nếu tôi muốn xoay nó ngay bây giờ, tôi có thể tự mình làm toán (trên CPU) và chỉ cần gọi glVertex3f
với các tọa độ khác (được xoay). Hoặc tôi có thể để GPU làm tất cả công việc, bằng cách gọi glRotatef
trước khi vẽ:
// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);
amount
tất nhiên, chỉ là một giá trị cố định. Nếu bạn muốn tạo hiệu ứng , bạn sẽ phải theo dõi amount
và tăng nó lên từng khung hình.
Vì vậy, chờ đợi, những gì đã xảy ra với tất cả các ma trận nói chuyện trước đó?
Trong ví dụ đơn giản này, chúng ta không cần phải quan tâm đến ma trận. Chúng tôi chỉ đơn giản gọi glRotatef
và nó sẽ chăm sóc tất cả những thứ đó cho chúng tôi.
glRotate
tạo ra một vòng quay angle
độ quanh vectơ xyz. Ma trận hiện tại (xem glMatrixMode ) được nhân với ma trận xoay với sản phẩm thay thế ma trận hiện tại, như thể glMultMatrix được gọi với ma trận sau làm đối số của nó:
x 2 1 - c + cx y 1 - c - z sx z 1 - c + y s 0 y x 1 - c + z sy 2 1 - c + cy z 1 - c - x s 0 x z 1 - c - y sy z 1 - c + x sz 2 1 - c + c 0 0 0 0 1
Vâng, cảm ơn vì điều đó!
Phần kết luận
Điều rõ ràng là, có rất nhiều cuộc nói chuyện với OpenGL. Nhưng nó không cho chúng ta biết điều gì. Giao tiếp ở đâu?
Điều duy nhất mà OpenGL nói với chúng ta trong ví dụ này là khi nó hoàn thành . Mỗi hoạt động sẽ mất một khoảng thời gian nhất định. Một số hoạt động mất rất nhiều thời gian, những người khác là rất nhanh chóng.
Gửi một đỉnh cho GPU sẽ rất nhanh, tôi thậm chí sẽ không biết cách thể hiện nó. Gửi hàng ngàn đỉnh từ CPU đến GPU, mỗi khung hình, rất có thể, không có vấn đề gì cả.
Việc xóa màn hình có thể mất một phần nghìn giây hoặc tệ hơn (lưu ý, bạn thường chỉ có khoảng 16 mili giây để vẽ mỗi khung hình), tùy thuộc vào tầm nhìn của bạn lớn như thế nào. Để xóa nó, OpenGL phải vẽ từng pixel theo màu bạn muốn xóa, đó có thể là hàng triệu pixel.
Ngoài ra, chúng tôi chỉ có thể hỏi OpenGL về các khả năng của bộ điều hợp đồ họa của chúng tôi (độ phân giải tối đa, khử răng cưa tối đa, độ sâu màu tối đa, ...).
Nhưng chúng ta cũng có thể điền vào một kết cấu với các pixel mà mỗi pixel có một màu cụ thể. Do đó, mỗi pixel chứa một giá trị và kết cấu là một "tệp" khổng lồ chứa đầy dữ liệu. Chúng ta có thể tải nó vào card đồ họa (bằng cách tạo bộ đệm kết cấu), sau đó tải một shader , nói với shader đó sử dụng kết cấu của chúng ta làm đầu vào và chạy một số phép tính cực kỳ nặng nề trên "tệp" của chúng ta.
Sau đó, chúng ta có thể "kết xuất" kết quả tính toán của mình (dưới dạng màu mới) thành một kết cấu mới.
Đó là cách bạn có thể làm cho GPU hoạt động cho bạn theo những cách khác. Tôi cho rằng CUDA thực hiện tương tự như khía cạnh đó, nhưng tôi chưa bao giờ có cơ hội làm việc với nó.
Chúng tôi thực sự chỉ chạm nhẹ vào toàn bộ chủ đề. Lập trình đồ họa 3D là một địa ngục của một con thú.
Nguồn hình ảnh