Tôi đang làm việc thông qua các hướng dẫn tuyệt vời tại arcsynthesis trong khi xây dựng một engine đồ họa và phát hiện ra tôi không hiểu VAO nhiều như tôi nghĩ Tôi đã có.Vertex Array Objects - Lẫn lộn liên quan đến chính xác thông tin trạng thái nào được lưu về vùng đệm vertex bị ràng buộc hiện tại
Từ hướng dẫn Chapter 5. Objects In Depth
Buffer Binding và Attribute Hiệp hội
Bạn có thể nhận thấy rằng glBindBuffer (GL_ARRAY_BUFFER) không nằm trong danh sách đó, mặc dù nó là một phần của thiết lập thuộc tính cho rendering. Ràng buộc với GL_ARRAY_BUFFER không phải là một phần của một VAO vì sự liên kết giữa một đối tượng đệm và một thuộc tính đỉnh không xảy ra khi bạn gọi glBindBuffer (GL_ARRAY_BUFFER). Sự liên kết này xảy ra khi bạn gọi glVertexAttribPointer.
Khi bạn gọi glVertexAttribPointer, OpenGL nhận bất kỳ bộ đệm nào tại thời điểm cuộc gọi này được liên kết với GL_ARRAY_BUFFER và liên kết nó với thuộc tính đỉnh đã cho. Hãy suy nghĩ của GL_ARRAY_BUFFER ràng buộc như một con trỏ toàn cầu mà glVertexAttribPointer đọc. Vì vậy, bạn được tự do ràng buộc bất cứ điều gì bạn muốn hoặc không có gì ở tất cả để GL_ARRAY_BUFFER sau khi thực hiện một cuộc gọi glVertexAttribPointer; nó sẽ không ảnh hưởng gì đến kết xuất cuối cùng. Vì vậy, VAOs lưu trữ các đối tượng đệm nào được liên kết với các thuộc tính nào; nhưng chúng không lưu trữ bản thân ràng buộc GL_ARRAY_BUFFER.
Ban đầu tôi bỏ lỡ dòng cuối cùng "... nhưng chúng không lưu trữ chính bản thân GL_ARRAY_BUFFER". Trước khi tôi nhận thấy dòng này tôi nghĩ rằng bộ đệm hiện đang bị ràng buộc đã được lưu khi glVertexAttribPointer được gọi. Thiếu kiến thức này, tôi đã xây dựng một lớp lưới và có thể có được một cảnh với một số mắt lưới dựng hình đúng cách.
Một phần của mã đó được liệt kê bên dưới. Lưu ý rằng tôi không gọi glBindBuffer trong hàm vẽ.
// MESH RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(vertex), &_vertices[0], GL_STATIC_DRAW);
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_normal);
glEnableVertexAttribArray(e_aid_color);
glEnableVertexAttribArray(e_aid_tex);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, pos));
glVertexAttribPointer(e_aid_normal, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, norm));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, col));
glVertexAttribPointer(e_aid_tex, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, tex));
/* ... */
/* DRAW FUNCTION */
/* ... */
glBindVertexArray(_vertex_array_object_id);
glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
Bây giờ tôi sắp bắt đầu ánh sáng Tôi muốn nhận được một số debug vẽ lên để tôi có thể xác minh tất cả normals của tôi là chính xác. Hiện tại tôi chỉ lưu trữ tất cả các dòng được hiển thị cho một khung trong một vectơ. Vì dữ liệu này có khả năng sẽ thay đổi mọi khung hình, tôi đang sử dụng GL_DYNAMIC_DRAW và chỉ định dữ liệu ngay trước khi tôi hiển thị nó.
Ban đầu khi tôi thực hiện việc này, tôi sẽ nhận được các dòng rác sẽ chỉ ra thành vô hạn. Mã vi phạm là bên dưới:
// DEBUG DRAW LINE RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
// Note: no buffer data supplied here!!!
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_color);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, pos));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, col));
/* ... */
/* DRAW FUNCTION */
/* ... */
glBindVertexArray(_vertex_array_object_id);
// Specifying buffer data here instead!!!
glBufferData(GL_ARRAY_BUFFER, _line_vertices.size() * sizeof(line_vertex), &_line_vertices[0], GL_DYNAMIC_DRAW);
glDrawArrays(GL_LINES, 0, _line_vertices.size());
Sau một chút săn bắn, cũng như tìm kiếm các chi tiết tôi đã bỏ lỡ trên, tôi thấy rằng nếu tôi gọi glBindBuffer trước glBufferData trong chức năng vẽ, mọi thứ hoạt động ra tốt đẹp.
Tôi nhầm lẫn là tại sao kết xuất lưới của tôi lại hoạt động ở vị trí đầu tiên. Tôi chỉ cần gọi glBindBuffer một lần nữa nếu tôi thay đổi dữ liệu trong bộ đệm? Hoặc là hành vi không xác định nếu bạn không ràng buộc bộ đệm và tôi đã chỉ là không may mắn và nó đã làm việc?
Lưu ý rằng tôi đang nhắm mục tiêu OpenGL phiên bản 3.0.
Ok, điều đó có ý nghĩa hơn. Tôi có một chi tiết nhỏ mà tôi vẫn còn hơi mờ. Hãy nói tôi gọi glBindVertexArray với VAO 1 mà nhớ VBO 1 đã bị ràng buộc khi glVertexAttribPointer được gọi. Sau đó tôi gọi glBindBuffer với VBO 2, tiếp theo là glDrawArrays. Bộ đệm nào nên được sử dụng, VBO 1 hoặc VBO 2? Tôi không tin rằng đây là điều mà người ta thường làm, tôi chỉ muốn chắc chắn rằng tôi hiểu chuyện gì đang xảy ra. –
VBO 1 sẽ được sử dụng. Lưu ý rằng điều này đúng dù bạn có đang sử dụng VAO hay không. Ngoài ra bạn có thể đã bị ràng buộc một số VBOs trong khi bạn đã có VAO ràng buộc (có lẽ là một khác nhau cho mỗi thuộc tính). Một khi bạn đã gọi glVertexAttribPointer bộ đệm bị ràng buộc tại thời điểm đó là một trong đó sẽ được sử dụng. – GuyRT
Tuyệt vời, đó là điều tốt để biết! Cảm ơn một tấn cho việc làm rõ! –