OpenGL: Có thể sử dụng VAO mà không cần chỉ định VBO


12

Trên tất cả các hướng dẫn tôi có thể tìm thấy về VAO (Đối tượng mảng Vertex), họ chỉ ra cách sử dụng chúng bằng cách định cấu hình các thuộc tính đỉnh và ràng buộc VBO (Đối tượng đệm của Vertex). Nhưng tôi muốn tạo một VAO sẽ được cấu hình cho một bộ VBO kết hợp với một shader cố định, trong đó mỗi bộ đệm sử dụng cùng một mẫu dữ liệu (đỉnh, uv, màu, v.v.). Vì vậy, tôi muốn tạo một VAO cho nhiều VBO sẽ được rút ra bằng một shader.

Tôi không thể tìm thấy bất kỳ bản demo nào về điều này, vì vậy tôi quyết định chỉ dùng thử. Nhưng nó không hoạt động và gặp sự cố trong glDrawArraycuộc gọi. Có vẻ như VBO không bị ràng buộc. Đây là mã tôi đang sử dụng:

Kết xuất:

/* Prepare vertex attributes */
glBindVertexArrayOES(vao);

/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());

/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);

glBindVertexArrayOES(0);

Sáng tạo VAO:

glBindVertexArrayOES(vao);

glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);

glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));

glBindVertexArrayOES(0);

Trường hợp lsđơn giản structchứa các vị trí thuộc tính.

Trong phần Kết xuất, hoán đổi glBindBufferglBindVertexArrayOESxung quanh cũng không hoạt động.

Vì vậy, câu hỏi là: Thậm chí có thể làm như vậy hay tôi sẽ phải tạo cho mỗi bộ đệm một VAO? Và nếu tôi phải tạo VAO cho mỗi VBO, có thể cập nhật dữ liệu của VBO bằng cách sử dụng glBufferSubDatakết hợp với VAO không?

Câu trả lời:


18

VAO không chứa trạng thái "glBindBuffer", ngoại trừ GL_ELEMENT_ARRAY_BUFFERtrạng thái ràng buộc của. Điều bạn không hiểu là glBindBuffer(GL_ARRAY_BUFFER) không làm gì cả . Chà, nó không làm bất cứ điều gì liên quan đến kết xuất. Thử nó; ngay trước khi gọi glDraw *, gọi glBindBuffer(GL_ARRAY_BUFFER, 0); kết xuất của bạn sẽ hoạt động tốt.

Cách thức glVertexAttribPointerhoạt động là nó nhìn vào những gì được ràng buộc với GL_ARRAY_BUFFER tại thời điểm glVertexAttribPointerđược gọi . Không phải lúc kết xuất. Không muộn. Ngay tại thời điểm chính xác. Nó lấy bất kỳ đối tượng bộ đệm nào ở đó và lưu trữ nó trong một phần khác của trạng thái OpenGL, được gói gọn trong VAO.

Nói chung, bạn có hai tùy chọn, một trong số đó là mới và có lẽ không nên sử dụng tại thời điểm này.

Tùy chọn đầu tiên của bạn là đặt tất cả các đối tượng sử dụng cùng một định dạng đỉnh (nghĩa là: mọi thứ trừ đối tượng đệm và offset) trong cùng một đối tượng đệm. Về cơ bản, xây dựng một mảng khổng lồ chứa tất cả các đỉnh cho tất cả các đối tượng sử dụng cùng định dạng.

Khi đến lúc kết xuất, bạn có thể kết xuất một phần của các đỉnh. glDrawArrayscần một loạt các yếu tố để kết xuất và bạn có thể điều chỉnh các chỉ mục của mình glDrawElementsđể thực hiện tương tự. Ngoài ra, bạn có thể sử dụng glDrawElementsBaseVertexđể thiên vị các đỉnh , sao cho phần bù được thêm vào mỗi chỉ mục. Giá trị bù này là số đỉnh trước đỉnh đó trong mảng lớn.

Cách khác là sử dụng hệ thống phân tách thuộc tính định dạng tương đối mới được thêm vào trong GL 4.3. Nó sẽ cho phép bạn thay đổi bộ đệm mà không cần đặt lại định dạng. Do đó, bạn sẽ liên kết một VAO duy nhất, sau đó chỉ cần thay thế trong các bộ đệm khác nhau khi cần glBindVertexBuffer. Điều này cũng có sẵn trong ES 3.1.


1
Trình điều khiển NV GL4.3 hiện đã được phát hành đầy đủ.
Maximus Minimus

Cảm ơn bạn rất nhiều vì đã giải thích cách hoạt động của glVertexAttribPulum. Điều đó đã được khai sáng và giải thích tại sao và làm thế nào nó hoạt động.
Martijn Courteaux

5

VAO lưu trữ trạng thái glVertexAttribPulum. Thay đổi VAO không ảnh hưởng đến glBindBuffer hiện tại, cũng không thay đổi glBindBuffer ảnh hưởng đến VAO. Chỉ cuộc gọi glVertexAttribPulum ảnh hưởng đến VAO, bằng cách ghi lại bộ đệm đang sử dụng tại cuộc gọi.

Vì vậy, câu trả lời cho câu hỏi của bạn là không.

Một tùy chọn nếu bạn muốn giảm số lượng đối tượng là đặt tất cả dữ liệu lưới của bạn vào một VBO lớn và chỉ định nơi dữ liệu lưới nằm trong VBO trong cuộc gọi glDrawArrays bằng cách sử dụng các đối số 'đầu tiên' và 'đếm'.


Tất cả các bài viết trên internet trên VAO đều cho thấy ràng buộc VAO tự động ràng buộc VBO. Vì vậy, tôi nghĩ rằng VAO là một cấu hình chứa cả trạng thái glVertexAttribPulum trạng thái glBindBuffer . Và có, ràng buộc VBO khi VAO bị ràng buộc thay đổi VAO. Tôi đang nói điều này bởi vì tôi đã thử nghiệm điều này và nó thực sự hiệu quả. Thông tin này đến từ đâu?
Martijn Courteaux

2
@MartijnCourteaux: " Tất cả các bài viết trên internet trên VAO đều cho thấy ràng buộc một VAO tự động ràng buộc VBO. " Không, họ không làm vậy. OpenGL Wiki về đặc tả đỉnh không có. Thật vậy, hãy cho tôi xem một bài viết duy nhất trên internet nói rằng bất kỳ glBindBuffertrạng thái nào ngoại trừ GL_ELEMENT_ARRAY_BUFFER được thay đổi bằng cách ràng buộc VAO.
Nicol Bolas

Câu trả lời khác giải thích tốt cách thức hoạt động của phương thức glVertexAttribPulum. Nó sử dụng VBO bị ràng buộc tại thời điểm đó. Bạn đúng rồi! Cảm ơn, tôi hiểu ngay bây giờ.
Martijn Courteaux
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.