OpenGL hướng đối tượng


12

Tôi đã sử dụng OpenGL được một thời gian và đã đọc một số lượng lớn các hướng dẫn. Bên cạnh thực tế là nhiều người trong số họ vẫn sử dụng đường ống cố định, họ thường ném tất cả các khởi tạo, thay đổi trạng thái và vẽ trong một tệp nguồn. Điều này tốt cho phạm vi giới hạn của một hướng dẫn, nhưng tôi đang gặp khó khăn trong việc tìm cách mở rộng nó thành một trò chơi đầy đủ.

Làm thế nào để bạn phân chia việc sử dụng OpenGL của bạn trên các tệp? Về mặt khái niệm, tôi có thể thấy những lợi ích của việc có một lớp kết xuất hoàn toàn hiển thị các công cụ trên màn hình, nhưng làm thế nào các công cụ như shader và đèn hoạt động? Tôi có nên có các lớp riêng cho những thứ như đèn và bóng không?


1
Có những trò chơi mã nguồn mở ngoài kia cũng như các hướng dẫn lớn hơn có nhiều mã hơn. Kiểm tra một số trong số họ và xem cách tổ chức mã.
MichaelHouse

Bạn có phải là người mới bắt đầu khi nói đến công cụ kết xuất?
Samaursa

Câu hỏi này không thể được trả lời một cách hợp lý mà không thu hẹp phạm vi. Chỉ là những gì bạn đang cố gắng để xây dựng? Loại trò chơi nào, loại đồ họa nào, v.v?
Nicol Bolas

1
@Sullivan: "Tôi nghĩ rằng những loại khái niệm này sẽ áp dụng cho hầu hết mọi trò chơi." Họ không. Nếu bạn yêu cầu tôi tạo Tetris, tôi sẽ không bận tâm tạo một lớp bao bọc lớn hoặc thứ gì đó xung quanh OpenGL. Chỉ cần sử dụng nó trực tiếp. Nếu bạn yêu cầu tôi tạo ra thứ gì đó như Mass Effect, thì chúng ta sẽ cần nhiều lớp trừu tượng xung quanh hệ thống kết xuất của chúng ta. Ném động cơ Unreal vào Tetris là sử dụng súng săn để săn ruồi; nó làm cho nhiệm vụ khó khăn hơn nhiều so với việc chỉ viết mã trực tiếp. Bạn chỉ nên xây dựng một hệ thống lớn và phức tạp khi bạn cần , và không lớn hơn.
Nicol Bolas

1
@Sullivan: Sự phức tạp duy nhất mà câu hỏi của bạn ngụ ý là nơi bạn nói về việc chia nhỏ trên nhiều tệp. Đó là điều tôi sẽ làm ngay cả trong Tetris. Và có nhiều mức độ phức tạp giữa Tetris và động cơ Unreal. Vì vậy, một lần nữa: bạn đang hỏi về cái nào?
Nicol Bolas

Câu trả lời:


6

Tôi nghĩ OO OpenGL là không cần thiết. Nó khác khi bạn nói về lớp shader, model, v.v.

Về cơ bản, bạn sẽ thực hiện khởi tạo trò chơi / công cụ trước tiên (và những thứ khác). Sau đó, bạn sẽ tải kết cấu, mô hình và trình đổ bóng vào RAM (nếu cần) và Đối tượng đệm, và tải lên / biên dịch trình đổ bóng. Sau đó, bạn, trong cấu trúc dữ liệu hoặc lớp của trình đổ bóng, mô hình, có ID int của các trình tạo bóng, mô hình và các đối tượng bộ đệm kết cấu.

Tôi nghĩ rằng hầu hết các động cơ đều có các thành phần động cơ và tất cả chúng đều có giao diện nhất định. Tất cả các công cụ tôi đã xem xét đều có một số thành phần như Renderer hoặc SceneManager hoặc cả hai (phụ thuộc vào độ phức tạp của trò chơi / công cụ). Hơn bạn có thể có lớp OpenGLRenderer và / hoặc DXRenderer thực hiện giao diện Renderer. Sau đó, nếu bạn có Trình quản lý cảnhTrình kết xuất, bạn có thể thực hiện một số thao tác sau:

  • Traverse SceneManager và gửi từng đối tượng đến Renderer để kết xuất
  • Đóng gói chữ hoa trong một số phương thức SceneManager
  • Gửi Trình quản lý cảnh đến Trình kết xuất để nó xử lý

Trình kết xuất có thể gọi hàm vẽ của đối tượng sẽ gọi hàm vẽ của mỗi lưới được cấu tạo và lưới sẽ liên kết đối tượng kết cấu, liên kết shader, gọi hàm vẽ OpenGL và sau đó không sử dụng các shader, kết cấu và đối tượng đệm dữ liệu đối tượng.

Chú ý: đây chỉ là ví dụ, bạn nên nghiên cứu SceneManager chi tiết hơn và phân tích trường hợp sử dụng của bạn để xem tùy chọn thực hiện tốt nhất là gì

Tất nhiên, bạn sẽ có các thành phần khác của công cụ, như MemoryManager , ResourceLoader v.v., sẽ đảm nhiệm cả việc sử dụng bộ nhớ video và RAM, do đó chúng có thể tải / hủy tải một số mô hình / trình tạo bóng / kết cấu nhất định khi cần. Các khái niệm cho điều này bao gồm bộ nhớ đệm, ánh xạ bộ nhớ, v.v. Có rất nhiều chi tiết và khái niệm về từng thành phần.

Hãy xem mô tả chi tiết hơn về các công cụ trò chơi khác, có rất nhiều trong số họ và tài liệu của họ có sẵn khá nhiều.

Nhưng vâng, các lớp học làm cho cuộc sống dễ dàng hơn; bạn hoàn toàn nên sử dụng chúng và ghi nhớ về đóng gói, kế thừa, giao diện và nhiều thứ hay ho hơn.


Đây là câu trả lời tôi đã tìm kiếm. Tuy nhiên, khi bạn nói rằng ... tải kết cấu, mô hình và trình đổ bóng vào RAM (nếu cần) và Đối tượng đệm, và tải lên / biên dịch trình đổ bóng ... thì đưa tôi trở lại câu hỏi ban đầu của tôi; Tôi có nên sử dụng các đối tượng để đóng gói những thứ như mô hình và shader không?
Sullivan

đối tượng là thể hiện của một lớp và 'bạn hoàn toàn nên sử dụng chúng'.
edin-m

Xin lỗi, tôi có ý hỏi 'tôi nên sử dụng đồ vật như thế nào'. Lỗi của tôi.
Sullivan

Vâng, nó phụ thuộc vào thiết kế lớp học của bạn. Một số ví dụ cơ bản sẽ là trực quan, một cái gì đó như: object3d (lớp) có mắt lưới (lớp); mỗi lưới có vật liệu (lớp); mỗi vật liệu có kết cấu (có thể là lớp, hoặc chỉ id) và shader (lớp). Nhưng khi bạn đọc về từng thành phần, bạn sẽ thấy có những cách tiếp cận khác nhau nhưng bằng nhau để tạo ra Trình quản lý cảnh, Trình kết xuất, Trình quản lý bộ nhớ (tất cả các thành phần này có thể là một lớp hoặc nhiều lớp, được kế thừa, v.v.). Hàng chục cuốn sách được viết về chủ đề này (kiến trúc công cụ trò chơi), và để trả lời chi tiết câu hỏi người ta có thể viết một.
edin-m

Tôi nghĩ rằng đây là câu trả lời tốt nhất tôi sẽ nhận được. Cảm ơn sự giúp đỡ của bạn :)
Sullivan

2

OpenGL đã có sẵn một số khái niệm 'Đối tượng'.

Ví dụ, mọi thứ có id đều có thể thông qua như một đối tượng (Cũng có những thứ được đặt tên cụ thể là 'Đối tượng'). Bộ đệm, Kết cấu, Đối tượng bộ đệm Vertex, Đối tượng mảng Vertex, Đối tượng bộ đệm khung, v.v. Với một chút công việc bạn có thể bao bọc các lớp học xung quanh chúng. Nó cũng cung cấp cho bạn một cách dễ dàng để quay lại các chức năng OpenGL cũ không dùng nữa nếu ngữ cảnh của bạn không hỗ trợ các tiện ích mở rộng. Ví dụ: VertexBufferObject có thể quay lại sử dụng glBegin (), glVertex3f (), v.v.

Có một số cách bạn có thể cần phải di chuyển khỏi các khái niệm OpenGL truyền thống, ví dụ bạn có thể muốn lưu trữ siêu dữ liệu về bộ đệm trong các đối tượng bộ đệm. Ví dụ nếu bộ đệm lưu trữ các đỉnh. Định dạng của các đỉnh là gì (tức là vị trí, quy tắc, texcoords, v.v.). Nó sử dụng nguyên thủy gì (GL_TRIANGLES, GL_TRIANGLESTRIP, v.v ...), thông tin kích thước (có bao nhiêu phao được lưu trữ, bao nhiêu hình tam giác mà chúng đại diện, v.v ...). Chỉ để làm cho nó dễ dàng để cắm chúng vào các lệnh vẽ mảng.

Tôi khuyên bạn nên xem OGLplus . Đó là các ràng buộc C ++ cho OpenGL.

Cũng glxx , điều đó chỉ dành cho tải mở rộng.

Ngoài việc gói API OpenGL, bạn nên xem xét xây dựng một cấp độ cao hơn một chút trên đầu trang.

Ví dụ, một lớp trình quản lý vật liệu chịu trách nhiệm cho tất cả các shader của bạn, tải và sử dụng chúng. Ngoài ra, nó sẽ chịu trách nhiệm chuyển tài sản cho họ. Bằng cách đó bạn chỉ có thể gọi: liệu.usePhong (); vật liệu.setTexture (đôi khi); vật liệu.setColor (). Điều này cho phép linh hoạt hơn vì bạn có thể sử dụng những thứ mới hơn như các đối tượng bộ đệm thống nhất được chia sẻ để chỉ có 1 bộ đệm lớn chứa tất cả các thuộc tính mà trình tạo bóng của bạn sử dụng trong 1 khối nhưng nếu nó không hỗ trợ bạn sẽ quay lại tải lên mỗi chương trình đổ bóng. Bạn có thể có 1 shader nguyên khối lớn và trao đổi giữa các mô hình shader khác nhau bằng cách sử dụng các thói quen thống nhất nếu nó được hỗ trợ hoặc bạn có thể quay lại sử dụng một loạt các shader nhỏ khác nhau.

Bạn cũng có thể xem xét mở rộng từ thông số kỹ thuật GLSL để viết mã shader của bạn. Ví dụ: #incoide sẽ cực kỳ hữu ích và rất dễ thực hiện trong mã tải shader của bạn (cũng có phần mở rộng ARB cho nó). Bạn cũng có thể tạo mã của mình một cách nhanh chóng dựa trên những tiện ích mở rộng nào được hỗ trợ, ví dụ: sử dụng một đối tượng đồng phục được chia sẻ hoặc quay lại sử dụng đồng phục thông thường.

Cuối cùng, bạn sẽ muốn một API đường ống kết xuất mức cao hơn thực hiện những việc như biểu đồ cảnh, hiệu ứng đặc biệt (làm mờ, phát sáng), những thứ đòi hỏi nhiều lần kết xuất như bóng, ánh sáng và như vậy. Và trên hết là một API trò chơi không liên quan gì đến API đồ họa mà chỉ giao dịch với các đối tượng trong một thế giới.


2
"Tôi khuyên bạn nên xem OGLplus. Đó là các ràng buộc C ++ cho OpenGL." Tôi muốn giới thiệu chống lại điều đó. Tôi yêu RAII, nhưng nó hoàn toàn không phù hợp với hầu hết các đối tượng OpenGL. Các đối tượng OpenGL được liên kết với cấu trúc toàn cầu: bối cảnh OpenGL. Vì vậy, bạn sẽ không thể tạo các đối tượng C ++ này cho đến khi bạn có một bối cảnh và bạn sẽ không thể xóa các đối tượng này nếu bối cảnh đã bị phá hủy. Ngoài ra, nó cung cấp cho ảo tưởng rằng bạn có thể sửa đổi các đối tượng mà không thay đổi trạng thái toàn cầu. Đây là một lời nói dối (trừ khi bạn đang sử dụng EXT_DSA).
Nicol Bolas

@NicolBolas: Tôi không thể kiểm tra xem có bối cảnh không và chỉ khởi tạo sau đó? Hoặc có lẽ chỉ cho phép người quản lý tạo các đối tượng yêu cầu bối cảnh OpenGL? --- btw, bộ hướng dẫn tuyệt vời (liên kết trong hồ sơ của bạn)! Bằng cách nào đó tôi không bao giờ bắt gặp chúng khi tìm kiếm OpenGL / Graphics.
Samaursa

@Samaursa: Để kết thúc? Nếu bạn có người quản lý cho các đối tượng OpenGL, thì ... bạn không thực sự cần phải tự chăm sóc bản thân; người quản lý có thể làm điều đó cho họ. Và nếu bạn chỉ khởi tạo chúng khi một bối cảnh tồn tại, điều gì xảy ra nếu bạn cố gắng sử dụng một đối tượng không được khởi tạo đúng cách? Nó chỉ tạo ra điểm yếu trong cơ sở mã của bạn. Nó cũng không thay đổi bất cứ điều gì tôi đã nói về khả năng sửa đổi các đối tượng này mà không cần chạm vào trạng thái toàn cầu.
Nicol Bolas

@NicolBolas: "bạn sẽ không thể tạo các đối tượng C ++ này cho đến khi bạn có bối cảnh" ... có khác gì so với sử dụng các cấu trúc OpenGL không? Trong mắt tôi, oglplus::Contextlớp học làm cho sự phụ thuộc này rất rõ ràng - đó có phải là một vấn đề không? Tôi tin rằng nó sẽ giúp người dùng OpenGL mới tránh được nhiều vấn đề.
xtofl

1

Trong OpenGL hiện đại, bạn gần như có thể tách biệt hoàn toàn các đối tượng được kết xuất với nhau, sử dụng các chương trình tạo bóng và hỗn loạn khác nhau. Và thậm chí việc thực hiện một đối tượng có thể được tách thành nhiều lớp trừu tượng.

Ví dụ: nếu bạn muốn triển khai địa hình, bạn có thể xác định TerrainMesh có hàm tạo của nó tạo các đỉnh và chỉ mục cho địa hình và đặt chúng thành các mảng, và - nếu bạn đặt cho nó một vị trí thuộc tính - nó sẽ làm mờ dữ liệu của bạn. Nó cũng nên biết cách kết xuất nó và nên cẩn thận hoàn nguyên tất cả các thay đổi bối cảnh đã thực hiện để thiết lập kết xuất. Bản thân lớp này không biết gì về chương trình đổ bóng sẽ kết xuất nó và cũng không nên biết bất cứ điều gì về bất kỳ đối tượng nào khác trong cảnh. Ở trên lớp này, bạn có thể định nghĩa một Địa hình, nhận biết mã shader và công việc của nó là tạo kết nối giữa shader và TerrainMesh. Điều này có nghĩa là có được vị trí thuộc tính và thống nhất và tải về kết cấu, và những thứ như thế. Lớp này không nên biết bất cứ điều gì về cách thực hiện địa hình, thuật toán LoD sử dụng là gì, nó chỉ chịu trách nhiệm che bóng địa hình. Ở trên này, bạn có thể xác định chức năng không phải OpenGL như phát hiện va chạm và phát hiện va chạm, v.v.

Đến thời điểm này, mặc dù OpenGL được thiết kế để sử dụng ở mức độ thấp, bạn vẫn có thể xây dựng các lớp trừu tượng độc lập, cho phép bạn mở rộng quy mô với các ứng dụng với kích thước của trò chơi Unreal. Nhưng số lượng lớp bạn muốn / cần thực sự phụ thuộc vào kích thước của ứng dụng bạn muốn.

Nhưng đừng tự dối mình về kích thước này, đừng cố bắt chước mô hình đối tượng của Unity trong ứng dụng dòng 10k, kết quả sẽ là một thảm họa hoàn toàn. Xây dựng các lớp dần dần, chỉ tăng số lượng các lớp trừu tượng, khi cần thiết.


0

ioDoom3 có lẽ là một điểm khởi đầu tuyệt vời, vì bạn có thể dựa vào Carmack để theo dõi thực hành mã hóa tuyệt vời. Ngoài ra tôi tin rằng anh ta không sử dụng megatexturing trong Doom3, vì vậy nó tương đối thẳng về phía trước như một ống kết xuất.


6
"Như bạn có thể dựa vào Carmack để tuân theo thực tiễn mã hóa tuyệt vời" Ôi trời, đó là một điều tốt. Carmack theo sau thực hành mã hóa C ++ tuyệt vời. Đó là một cuộc bạo loạn! Ồ ... bạn không đùa đâu. Ừm ... bạn đã bao giờ thực sự nhìn vào mã của anh ấy chưa? Anh ấy là một lập trình viên C và đó là cách anh ấy nghĩ. Cái nào tốt cho C, nhưng câu hỏi là về C ++ .
Nicol Bolas

Tôi đến từ nền C nên mã của anh ấy rất có ý nghĩa với tôi: P và vâng, đã dành một chút thời gian để làm việc trên các trò chơi dựa trên trận động đất.
chrisvarnz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.