Một số thuật ngữ hơi sai:
- A
Vertex Array
chỉ là một mảng (thường là a float[]
) chứa dữ liệu đỉnh. Nó không cần phải bị ràng buộc vào bất cứ điều gì. Đừng nhầm lẫn với a Vertex Array Object
hoặc VAO, tôi sẽ xem xét sau
- A
Buffer Object
, thường được gọi là a Vertex Buffer Object
khi lưu trữ các đỉnh, hay gọi tắt là VBO, là những gì bạn đang gọi chỉ là a Buffer
.
- Không có gì được lưu trở lại mảng đỉnh,
glVertexAttribPointer
hoạt động giống hệt glVertexPointer
hoặc glTexCoordPointer
hoạt động, chỉ thay vì các thuộc tính được đặt tên, bạn có thể cung cấp một số chỉ định thuộc tính của riêng bạn. Bạn chuyển giá trị này dưới dạng index
. Tất cả các glVertexAttribPointer
cuộc gọi của bạn sẽ được xếp hàng đợi cho lần tiếp theo bạn gọi glDrawArrays
hoặc glDrawElements
. Nếu bạn bị ràng buộc VAO, VAO sẽ lưu trữ các cài đặt cho tất cả các thuộc tính của bạn.
Vấn đề chính ở đây là bạn đang nhầm lẫn các thuộc tính đỉnh với VAO. Thuộc tính Vertex chỉ là cách mới để xác định đỉnh, texcoords, chuẩn, v.v. để vẽ. Trạng thái cửa hàng VAOs. Đầu tiên tôi sẽ giải thích cách hoạt động của bản vẽ với các thuộc tính đỉnh, sau đó giải thích cách bạn có thể cắt giảm số lượng lệnh gọi phương thức với VAO:
- Bạn phải kích hoạt một thuộc tính trước khi có thể sử dụng nó trong bộ đổ bóng. Ví dụ: nếu bạn muốn gửi các đỉnh tới một bộ đổ bóng, rất có thể bạn sẽ gửi nó dưới dạng thuộc tính đầu tiên, 0. Vì vậy, trước khi kết xuất, bạn cần bật nó với
glEnableVertexAttribArray(0);
.
- Bây giờ một thuộc tính đã được bật, bạn cần xác định dữ liệu mà nó sẽ sử dụng. Để làm như vậy, bạn cần phải ràng buộc VBO của mình -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
.
- Và bây giờ chúng ta có thể xác định thuộc tính -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
. Theo thứ tự của tham số: 0 là thuộc tính bạn đang xác định, 3 là kích thước của mỗi đỉnh, GL_FLOAT
là kiểu, GL_FALSE
có nghĩa là không chuẩn hóa mỗi đỉnh, 2 số không cuối cùng có nghĩa là không có khoảng cách hoặc độ lệch trên các đỉnh.
- Vẽ một cái gì đó với nó -
glDrawArrays(GL_TRIANGLES, 0, 6);
- Điều tiếp theo bạn vẽ có thể không sử dụng thuộc tính 0 (thực tế là như vậy, nhưng đây là một ví dụ), vì vậy chúng tôi có thể vô hiệu hóa nó -
glDisableVertexAttribArray(0);
Kết thúc điều đó trong glUseProgram()
các cuộc gọi và bạn có một hệ thống kết xuất hoạt động đúng với trình đổ bóng. Nhưng giả sử bạn có 5 thuộc tính khác nhau, đỉnh, texcoords, chuẩn, màu và tọa độ bản đồ ánh sáng. Trước hết, bạn sẽ thực hiện một glVertexAttribPointer
lệnh gọi cho mỗi thuộc tính này và bạn phải bật tất cả các thuộc tính trước đó. Giả sử bạn xác định các thuộc tính 0-4 như tôi đã liệt kê. Bạn sẽ kích hoạt tất cả chúng như vậy:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
Và sau đó bạn sẽ phải ràng buộc VBOs khác nhau cho mỗi thuộc tính (trừ khi bạn lưu trữ chúng tất cả trong một VBO và sử dụng offsets / sải chân), sau đó bạn cần phải thực hiện 5 khác nhau glVertexAttribPointer
cuộc gọi, từ glVertexAttribPointer(0,...);
để glVertexAttribPointer(4,...);
cho đỉnh đến tọa độ lightmap tương ứng.
Hy vọng rằng hệ thống chỉ có ý nghĩa. Bây giờ tôi sẽ chuyển sang VAO để giải thích cách sử dụng chúng để cắt giảm số lượng lệnh gọi phương thức khi thực hiện kiểu kết xuất này. Lưu ý rằng việc sử dụng VAO là không cần thiết.
A Vertex Array Object
hoặc VAO được sử dụng để lưu trữ trạng thái của tất cả các glVertexAttribPointer
cuộc gọi và VBO đã được nhắm mục tiêu khi mỗi glVertexAttribPointer
cuộc gọi được thực hiện.
Bạn tạo một với một cuộc gọi đến glGenVertexArrays
. Để lưu trữ mọi thứ bạn cần trong một VAO, hãy liên kết với nó glBindVertexArray
, sau đó thực hiện một cuộc gọi rút tiền đầy đủ . Tất cả các lệnh gọi ràng buộc hòa đều được VAO chặn và lưu trữ. Bạn có thể hủy liên kết VAO vớiglBindVertexArray(0);
Bây giờ khi bạn muốn vẽ đối tượng, bạn không cần phải gọi lại tất cả các liên kết VBO hoặc các glVertexAttribPointer
lệnh gọi, bạn chỉ cần liên kết VAO với glBindVertexArray
sau đó gọi glDrawArrays
hoặc glDrawElements
và bạn sẽ vẽ chính xác thứ giống như bạn. đã thực hiện tất cả các cuộc gọi phương thức đó. Bạn có thể cũng muốn hủy liên kết VAO sau đó.
Sau khi bạn hủy liên kết VAO, tất cả trạng thái sẽ trở lại như trước khi bạn ràng buộc VAO. Tôi không chắc liệu có bất kỳ thay đổi nào bạn thực hiện trong khi VAO bị ràng buộc hay không, nhưng điều đó có thể dễ dàng tìm ra bằng một chương trình thử nghiệm. Tôi đoán bạn có thể nghĩ rằng nó glBindVertexArray(0);
ràng buộc với VAO "mặc định" ...
Cập nhật: Ai đó đã làm tôi chú ý đến nhu cầu của một cuộc gọi rút thăm thực sự. Hóa ra, bạn thực sự không cần phải thực hiện lệnh gọi ĐẦY ĐỦ khi thiết lập VAO, chỉ cần tất cả những thứ ràng buộc. Không biết tại sao tôi nghĩ nó là cần thiết trước đó, nhưng nó đã được sửa chữa.