สถานะใดที่ถูกเก็บไว้ใน OpenGL Vertex Array Object (VAO) และฉันจะใช้ VAO อย่างถูกต้องได้อย่างไร


25

ฉันสงสัยว่าสถานะใดที่เก็บไว้ใน OpenGL VAO ฉันเข้าใจว่า VAO มีสถานะที่เกี่ยวข้องกับข้อมูลจำเพาะของจุดยอดของจุดยอดบัฟเฟอร์ (แอตทริบิวต์ใดที่อยู่ในบัฟเฟอร์และบัฟเฟอร์ใดถูกผูกมัด ... ) เพื่อให้เข้าใจการใช้ VAO ที่ถูกต้องได้ดีขึ้นฉันต้องการทราบว่าพวกเขามีสถานะเป็นอย่างไร


ฉันควรใช้ VAO อย่างไร

จากตัวอย่างง่ายๆฉันเข้าใจว่าการใช้งาน VAO ที่ถูกต้องมีดังนี้:

ติดตั้ง

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

การกระทำ

Bind VAO
---- Draw
Unbind VAO

จากนี้ฉันคิดว่าอย่างน้อยการผูกบัฟเฟอร์จุดสุดยอดและข้อมูลจำเพาะคุณลักษณะจุดสุดยอดจะถูกเก็บไว้ใน VAO ฉันไม่แน่ใจว่ารูปแบบการใช้งานนี้จะขยายไปสู่สถานการณ์ที่มีพื้นผิว (หลาย) และโปรแกรม Shader (หลายรายการ) ได้อย่างไร เป็นโปรแกรมที่ใช้งาน Shaderเก็บไว้ใน VAO? และการผูกพื้นผิว (ด้วยการตั้งค่าการสุ่มตัวอย่าง / การห่อ ) ใน VAO ด้วยหรือไม่ เหมือนกันสำหรับเครื่องแบบ ?


ดังนั้นคำถามของฉันคือ:

  • อะไรที่แน่นอนรัฐถูกเก็บไว้ในOpenGL VAO ? (การผูก VBO, ข้อกำหนดคุณลักษณะ, โปรแกรม shader ที่ใช้งาน, การเชื่อมพื้นผิว, การตั้งค่าการสุ่มตัวอย่าง / การห่อพื้นผิว, เครื่องแบบ ... ?)
  • ฉันจะใช้ VAO อย่างถูกต้องในการตั้งค่าการเรนเดอร์ที่ซับซ้อนมากขึ้นได้อย่างไรที่มีพื้นผิว (หลาย) ที่มีการตั้งค่าการสุ่มตัวอย่าง / การห่อที่เกี่ยวข้อง (หลาย) โปรแกรม shader และชุดเครื่องแบบเกี่ยวข้อง

1
VAO เก็บข้อมูลเกี่ยวกับตำแหน่งของแอตทริบิวต์จุดสุดยอด นอกจากนี้ยังเก็บ ID ของ VBOs ที่มีคุณสมบัติเหล่านี้ คุณไม่จำเป็นต้องผูก VBO เมื่อคุณวาดอะไรคุณต้องผูกมันก่อนที่จะเรียก glVertexAttribPointer () เมื่อคุณสร้าง VAO
HolyBlackCat

คำตอบ:


18

VAO เก็บข้อมูลเกี่ยวกับตำแหน่งของแอตทริบิวต์จุดสุดยอด (และข้อมูลอื่น ๆ ที่เกี่ยวข้องกับพวกเขา)
"VBO bindings, active shader program, texture bindings, texture sampling/wrapping settings, uniforms"ไม่เกี่ยวข้องกับมันอย่างสมบูรณ์

คุณอาจถามว่าทำไมไม่จำ VBO ผูกพัน เนื่องจากคุณไม่จำเป็นต้องผูก VBO เพื่อวาดอะไรคุณจะต้องผูกมันเมื่อสร้าง VAO: เมื่อคุณโทรglVertexAttribPointer(...)VAO จะจดจำสิ่งที่ VBO ผูกไว้ในขณะนี้ และ VAO จะใช้คุณลักษณะจาก VBOs เหล่านี้เมื่อคุณวาดแม้ว่า VBOs เหล่านี้จะไม่ถูกผูกไว้ในขณะนี้


นอกจากนี้ VAO และ VBO จะต้องใช้งานแตกต่างกันเล็กน้อย:

สิ่งนี้จะไม่ทำงาน

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

เพราะคุณต้องผูก VBO เพื่อระบุตำแหน่งของแอตทริบิวต์

ดังนั้นคุณควรทำเช่นนี้:

Generate VAO
BindVAO
Generate VBO's
BindVBO's
Specify vertex attributes

คุณสามารถเปลี่ยนข้อมูลของ VBO ทุกครั้งที่คุณต้องการ แต่คุณต้องผูกไว้ก่อน

และการวาดควรมีลักษณะเช่นนี้:

Bind VAO
Draw


อย่างที่คุณอาจสังเกตเห็นว่าฉันลบunbindสายออกจากรายการของคุณ พวกเขาเกือบจะไร้ประโยชน์อย่างสมบูรณ์และพวกเขาจะทำให้โปรแกรมของคุณช้าลงเล็กน้อยดังนั้นฉันจึงไม่เห็นเหตุผลที่จะเรียกพวกเขา


9
"ดังนั้นฉันไม่เห็นเหตุผลที่จะเรียกพวกเขา" เพื่อป้องกันการเปลี่ยนแปลงโดยไม่ตั้งใจ โดยเฉพาะปัญหาเมื่อใช้ห้องสมุดบุคคลที่สาม
วงล้อประหลาด

ขอบคุณสำหรับคำตอบที่ยอดเยี่ยม! ดังนั้นในระยะสั้น VAO จะเก็บเฉพาะตำแหน่งแอ็ตทริบิวต์จุดสุดยอดเท่านั้น VBO จะไม่เด้งกลับมาเมื่อเชื่อม VAO เข้าด้วยกันเนื่องจาก VAO รู้ว่าบัฟเฟอร์ใดที่จะหาแอตทริบิวต์ได้สถานะอื่น ๆ ทั้งหมดอยู่ในสถานะ OpenGL ทั่วโลก
Jelle van Campen

@ JellevanCampen ใช่ถูกต้อง FYI, มันยังเก็บสถานะ off / on ของคุณสมบัติ ( gl{Enable|Disable}VertexAttribArray()), ค่าเริ่มต้นของพวกเขา ( glVertexAttrib*()), โหมด instancing ของพวกเขา ( glVertexAttribDivisor()) และอาจเป็นอย่างอื่น
HolyBlackCat

@HolyBlackCat คุณแน่ใจหรือไม่ว่าสถานะเริ่มต้น (glVertexAttrib ()) เป็นส่วนหนึ่งของสถานะ VAO วิกิ OpenGL อ้างเป็นอย่างอื่นโดยกล่าวว่าเป็นสถานะบริบท
rdb

@ndb ไม่ฉันไม่แน่ใจ ฉันคาดว่าพวกเขาจะเป็นส่วนหนึ่งของรัฐ VAO และฉันไม่ได้ตรวจสอบ
HolyBlackCat

4

โดยจะเก็บเฉพาะการเชื่อมจุดสุดยอดและการเชื่อมดัชนีบัฟเฟอร์

นั่นคือพารามิเตอร์ทั้งหมดของglVertexAttribPointerบวกบัฟเฟอร์ที่ถูกผูกไว้กับ Vertex_Array_buffer ณ เวลาที่มีการเรียกไปยังglVertexAttribPointerและ Element_Array_buffer ที่ถูกผูกไว้

เครื่องแบบเป็นส่วนหนึ่งของโปรแกรมปัจจุบัน

ทุกสิ่งทุกอย่างคือรัฐระดับโลก

สงสัยคุณสามารถตรวจสอบตารางสถานะในข้อมูลจำเพาะของรุ่นที่คุณใช้อยู่


ขอบคุณสำหรับคำตอบด้วย! นี่เป็นการล้างสิ่งต่าง ๆ สำหรับฉัน
Jelle van Campen

4

นี่คือคำอธิบายที่เรียบง่าย แต่มีประสิทธิภาพโดยทั่วไปวัตถุบัฟเฟอร์มีข้อมูลที่สามารถตีความได้ว่าเป็นเพียงข้อมูลบิตซึ่งไม่ได้มีความหมายใด ๆ ดังนั้นจึงเป็นข้อมูลที่สามารถดูได้ทุกทาง

i.e float vbo[]={1.0,2.0,34.0...}

และวิธีที่ OpenGL ได้รับการออกแบบมาเพื่อทำงานคือคุณต้องกำหนดว่าข้อมูลที่คุณส่งผ่านไปยังเฉดสีต่าง ๆ จะมีลักษณะอย่างไร

ในการที่คุณจะต้องกำหนดว่ามันจะอ่านข้อมูลนั้นอยู่ในรูปแบบใดและจะทำอย่างไรกับมันและวิธีการที่จะใช้และสิ่งที่ข้อมูลทั้งหมดนี้จะถูกเก็บไว้ใน VAO

ตัวอย่างเช่นคุณสามารถประกาศข้อมูลที่เก็บไว้ในอาร์เรย์เช่นนี้ float vbo = {11.0,2.0,3.0,4.0}

สิ่งที่จำเป็นต่อไป ณ จุดนี้คือวิธีการตีความข้อมูลจาก VBO ใน VAO และสิ่งที่หมายถึงมีดังนี้

VAO สามารถตั้งค่าให้อ่าน 2 float ต่อจุดสุดยอด (ซึ่งจะทำให้ 2 เวกเตอร์มีสองมิติ x, y) หรือคุณสามารถบอก Vao ให้ตีความมันเป็น 1 เวกเตอร์ที่มี 4 มิติเช่น x, y, z, w ฯลฯ

แต่ยังมีคุณสมบัติอื่น ๆ ของข้อมูลที่ถูกกำหนดและเก็บไว้ใน VAO เช่นรูปแบบข้อมูล (แม้ว่าคุณจะประกาศอาร์เรย์ของ float คุณสามารถบอก shader ให้อ่านมันเป็นจำนวนเต็มด้วยแน่นอนว่าระบบจะแปลงข้อมูลดิบใน กระบวนการจาก float เป็นจำนวนเต็มและมีชุดของกฎของตัวเองว่าจะทำอย่างไรในสถานการณ์เช่นนี้)

ดังนั้นโดยพื้นฐานแล้ว VBO คือข้อมูลและ VAO เก็บวิธีการตีความข้อมูลนั้นเนื่องจากเซิร์ฟเวอร์ shaders และ OpenGL ได้รับการออกแบบมาให้มีความซับซ้อนมากและจำเป็นต้องรู้ทุกอย่างก่อนที่จะตัดสินใจว่าจะดำเนินการอย่างไรและจะทำอย่างไร ที่จะนำมัน

แน่นอนว่ามันไม่ใช่เรื่องไร้สาระจริง ๆ แล้วมันต้องการประสิทธิภาพมากที่สุดเพราะจำเป็นต้องเก็บข้อมูลนั้นไว้ในหน่วยความจำเซิร์ฟเวอร์กราฟิกเพื่อให้ได้รับการประมวลผลที่มีประสิทธิภาพและรวดเร็วที่สุด (เว้นแต่จะตัดสินใจว่าไม่จำเป็นต้องทำเช่นนี้หาก ข้อมูลจะไม่ถูกประมวลผลในลักษณะดังกล่าวและใช้สำหรับข้อมูลอื่น ๆ ที่ไม่ได้เข้าถึงบ่อยๆ) และด้วยเหตุนี้จึงมีรายละเอียดว่าจะทำอย่างไรกับข้อมูลและวิธีการดำเนินการที่จำเป็นต้องเก็บไว้ใน VAO ดังนั้น VAO เป็นเหมือนส่วนหัวและ VBO เป็นเหมือนข้อมูลดิบบริสุทธิ์ที่ส่วนหัวใช้และกำหนด (ในกรณีนี้จะส่งผ่านไปยังแอตทริบิวต์จุดสุดยอดของ Shader) ยกเว้นว่า VBO จะไม่ จำกัด เพียงการใช้งานโดย VAO เดียวเท่านั้น สามารถใช้และนำกลับมาใช้ใหม่และถูกผูกไว้กับ VAO หลายตัวอย่างเช่น:

สิ่งที่คุณสามารถทำได้คือคุณสามารถผูกวัตถุบัฟเฟอร์หนึ่งกับ VAO1 และยัง (แยก) ผูกวัตถุบัฟเฟอร์เดียวกันกับ VAO2 ด้วยแต่ละการตีความมันแตกต่างกันดังนั้นถ้า shader ของคุณที่จะประมวลผลข้อมูลขึ้นอยู่กับ VAO ใด ผูกมันจะประมวลผลข้อมูลดิบเดียวกันแตกต่างไปจาก frambuffer (การวาดพิกเซลสู่หน้าต่าง) ทำให้การแสดงผลของข้อมูลเดียวกันแตกต่างกันซึ่งจะขึ้นอยู่กับวิธีที่คุณกำหนดการใช้งานใน VAO


นี่คือคำตอบที่ดีที่สุด!
CodingMadeEasy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.