ควรแยกบัฟเฟอร์ออกไหม


12

ฉันทำการทดสอบกับ OpenGL ES 2 และได้รับคำถามโปรแกรมปัจจุบันของฉันเป็นเช่นนั้น:

Init
-------
-> create index buffer
-> fill index buffer glBufferData 
-> create vertex buffer
-> fill vertex buffer glBufferData 

Draw
-------
 1. Apply vertex buffer

    -> Bind VAO
       -> bind vertex buffer
          - enable attributs (glVertexPointer, …)
       -> unbind vertex buffer
    -> Unbind VAO
    -> Bind VAO

 3. Apply index buffer
 4. Draw

ปัญหา

รหัสขัดข้องที่ได้รับหลังจากการวิจัยบางอย่างฉันเข้าใจว่าทำไม: ฉันต้องยกเลิกการผูกบัฟเฟอร์ดัชนีของฉันในส่วน init (หลังจาก "เติมดัชนีบัฟเฟอร์ glBufferData") หรือเลิกผูกไว้ก่อน "Bind VAO" ตัวแรก

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

  • ฉันสามารถใส่บัฟเฟอร์ดัชนีใน VAO (บัฟเฟอร์ดัชนีหุ้น VAO ได้หรือไม่)?
  • ฉันต้องยกเลิกการผูกบัฟเฟอร์หลังจากการอัพเดทแต่ละครั้ง (glBufferData) หรือไม่?

ในแอปพลิเคชันของฉันฉันมีบัฟเฟอร์ที่อัปเดตในแต่ละเฟรม (ตัวอย่าง: อนุภาค) ดังนั้นฉันจึงมีสแต็ก OpenGL ดังนี้:

-> bind buffer 1
-> update buffer 1
-> close buffer 1
-> bind buffer 1
-> draw

3 บรรทัดแรกอัปเดตบัฟเฟอร์ Vertex ซึ่งเป็นวัตถุวาดล่าสุดที่ควรเป็นดังนี้:

-> bind buffer 1
-> update buffer 1
-> draw

ขอบคุณ

คำตอบ:


12

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

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

ตอนนี้รับลำดับการดำเนินการของคุณนี่คือคำสั่งโดยรวมที่ฉันคาดว่าจะเห็น:

ใน init:

  1. สร้าง & ผูก VAO VBO และ IBO ใด ๆ ที่คุณผูกไว้ในลำดับจะเชื่อมโยงกับ VAO ปัจจุบัน (อันนี้)

  2. สร้าง & ผูกบัฟเฟอร์ดัชนี

    • glBufferData/glMapBufferดัชนีเติมบัฟเฟอร์ด้วย
  3. สร้าง & ผูกบัฟเฟอร์จุดสุดยอด

    • glBufferData/glMapBufferบัฟเฟอร์เติมจุดสุดยอด
  4. ตั้งค่าคุณลักษณะจุดสุดยอดด้วยglEnableVertexAttribArray/glVertexAttribPointerฯลฯ

  5. ยกเลิกการผูกทุกอย่างเพื่อหลีกเลี่ยงการดัดแปลงบัฟเฟอร์และ VAO โดยไม่ตั้งใจ จำไว้ว่าให้แยก VAO แรก เช่น:glBindVertexArray(0);

เมื่อวาด:

  1. ถ้าเพียงแค่วาดบัฟเฟอร์ :

    • ผูก VAO;
    • ดำเนินการวาดการโทร
  2. หากการอัพเดตและการวาดภาพ :

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

นั่นง่ายอย่างนั้น คำสั่งของการดำเนินการนี้ควรทำงานได้โดยไม่มีปัญหา


2
ฉันต้องการที่จะเพิ่มว่าในการทดลองของฉัน (2014) กับกรณีในชีวิตจริง (แต่ shaders ง่ายที่จะไม่คอขวดที่ GPU) ฉันพบการปรับปรุงประสิทธิภาพการใช้ VAO จะไม่สำคัญ (<2% CPU ประหยัด) หลังจากการสั่งซื้อที่เหมาะสม ของการเรียกใช้การเรนเดอร์ถูกนำไปใช้เพื่อข้ามการติดตั้ง VBO อย่างสมบูรณ์เมื่อใช้ VBO เดียวกันกับการเรียกใช้การเรนเดอร์ต่อเนื่อง (ประหยัด CPU 10 ถึง 33%) และฉันกดปุ่มไดรเวอร์บางตัวด้วย VAO มันมีความสำคัญน้อยลงเมื่อใช้ shaders ที่ซับซ้อน, MSAA, ฯลฯ ซึ่งคอขวดที่ GPU ปล่อยให้ CPU ยังคงรออยู่เฉยๆแม้แต่บนมือถือ
Stephane Hockenhull

2
โปรดทราบว่าการจัดตำแหน่งจุดสุดยอดข้อมูลที่ไม่ถูกต้องในลักษณะที่ฮาร์ดแวร์ไม่รองรับจะบังคับให้ไดรเวอร์ GPU จัดลำดับข้อมูล VBO ใหม่ในแต่ละการตั้งค่าในขณะที่ไดรเวอร์สามารถเรียงลำดับใหม่ได้ด้วย VAO ตราบใดที่ไม่มีการเปลี่ยนแปลงดังนั้น ดีที่สุดในการจัดตำแหน่งและวางข้อมูลจุดสุดยอดอยู่ดี
Stephane Hockenhull

1
ทำไม VAO ต้องถูกยกเลิกการผูกมัดก่อนทุกอย่างอื่น?
Daniel Safari

@DanielSafari คุณหมายถึงหลังการตั้งค่าหรือไม่ หากคุณต้องการยกเลิกการผูกบัฟเฟอร์ก่อน (การผูกบัฟเฟอร์ 0 / null) มันจะล้างจุดผูกนั้นใน VAO ปัจจุบัน นั่นเป็นเหตุผลที่ควรตั้งค่า VAO ว่างไว้ก่อน
glampert

@glampert - ไม่นั่นไม่ใช่วิธีการผูก การเชื่อมบัฟเฟอร์จะใช้เมื่อเรียก glVertexAttribPointer และไม่ใช่เป็นอย่างอื่น (ยกเว้น: GL_ELEMENT_ARRAY_BUFFER) การเปลี่ยนการโยงบัฟเฟอร์หลังจากการเรียก glVertexAttribPointer ของคุณไม่มีผลกระทบ
Maximus Minimus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.