วิธีปรับปรุงประสิทธิภาพการทำงานเป็นชุด


9

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

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

ทำไม? ฉันมีวัตถุเกม 200 (หรือมากกว่า) และพวกมันได้รับการอัพเดท 60 ครั้งต่อวินาที ทุกเฟรมที่ฉันต้องคำนวณตำแหน่งใหม่ (การแปลและการหมุน) สำหรับจุดยอดในซีพียู (GPU บนแพลตฟอร์มมือถือไม่รองรับการติดตั้งดังนั้นฉันจึงไม่สามารถทำได้ที่นั่น) และทำการคำนวณนี้ 48000 ต่อวินาที (200 * 60 * 4 ตั้งแต่ เทพดาทุกคนมี 4 จุดยอด) ดูเหมือนว่าจะช้าเกินไป

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

ขอบคุณ

คำตอบ:


5

คุณใช้พอร์ต irrlichtสำหรับ Android หรือไม่? สำหรับสไปรต์ 2d บน Android และ iphone ฉันใช้เทคนิคเดียวกับคุณ: การแบตช์ ฉันลองวิธีแก้ปัญหามากมายใน OpenGL ES 1.x และ 2.x:

  • จัดเรียงตาม z (parallax) และตามพื้นผิวทำการแปลงบน CPU และเรียกใช้ glDrawArrays หรือ glDrawElements (วิธีที่เร็วที่สุด) ใช้หนึ่งเนื้อใหญ่ถ้าคุณสามารถ
  • เคล็ดลับเดียวกันกับ VBO ไม่เร็วเพราะสำหรับแต่ละเฟรมคุณจะรีเฟรชข้อมูลทั้งหมด มันจะมีประโยชน์สำหรับสไปรต์สถิตยศาสตร์
  • ใช้ OpenGL ES 2.x และใช้ Vertex shader เพื่อคำนวณตำแหน่ง (ช้ากว่า)
  • ใช้ PointSprites (ไม่มีวิธีแก้ปัญหาถ้าไม่ใช่สแควร์และพิกเซลโปร่งใสมากเกินไปจะฆ่า fillrate)
  • ใช้ส่วนขยาย gldrawtexoes ...
  • ใช้ drawcall สำหรับสไปรต์แต่ละอัน (ช้าที่สุด)

เช่นเดียวกับคุณการแปลงทั้งหมดจะกระทำโดย CPU สำหรับ OGLES 1.x หรือ OGLES 2.x หากคุณมีคำแนะนำนีออนคุณสามารถใช้พวกเขาเพื่อเพิ่มความเร็วในการคำนวณของคุณ

ป.ล. : บนอุปกรณ์ iphone หรือ android ฉันไม่ได้ CPU จำกัด แต่อัตราการเติม จำกัด ดังนั้นจึงเป็นสิ่งสำคัญมากที่จะ จำกัด การถอนเงินมากเกินไป


ยอดเยี่ยมนี่คือสิ่งที่ฉันกำลังมองหา ฉันไม่ทราบถึงพอร์ต Irrlicht ของคุณ แต่ฉันมีรุ่นของฉันใน Irrlicht ที่ทำงานบน iOS แล้ว คุณบอกว่าคุณไม่ได้ จำกัด ซีพียู - คุณวาดสไปรต์กี่ภาพ? และอะไรคือสิ่งที่ framerates ของคุณสำหรับ 100 sprite บน iPhone? ถ้าฉันมีวัตถุ 200 ชิ้นฉันจะทำการคำนวณ 48,000 ครั้งต่อวินาที จุดของคุณเกี่ยวกับการกรอกเป็นสิ่งที่ดี
user4241

สไปรต์คงที่ (พื้นหลัง) อยู่ใน VBO ฉันใช้ VBO หนึ่งรายการต่อพารัลแลกซ์ มิฉะนั้นฉันมีสไปรต์ 100 ถึง 200 รายการบน Moblox บนไอโฟนทั้งหมดรวมถึง 3G ฉันมีมากกว่า 30fps (เท่าที่จำได้) แต่สไปรต์ขนาดใหญ่นั้นมีราคาแพงมาก (เติมปัญหา) ....
เอลลิส

ฉันทำงานกับเอ็นจิ้นอนุภาคซึ่งฉันสามารถใช้อนุภาคได้มากถึง 20,000 ตำแหน่งพร้อมการคำนวณตำแหน่งทั้งหมดบน CPU และฉันมี 10fps ด้วยการตั้งค่าสุดขีด (บน 3GS และ iPhone4) ดังนั้น 1,000 sprites จะต้องเป็นไปได้ใน 3GS หรือ iPhone4 ที่มีอัตราเฟรมที่ดี
Ellis

ขอบคุณมีประโยชน์มาก! คุณนำเครื่องยนต์อนุภาคไปใช้งานอย่างไร? ฉันคิดว่าคุณกำลังเล่นกับ shaders?
user4241

ฉันใช้ตัวติดตั้งเพราะฉันต้องการ gl_PointSize เพื่อตั้งค่าแต่ละขนาดของอนุภาค ฉันไม่ทำงานกับ OGLES 1.x อีกต่อไปเพราะโทรศัพท์เก่าไม่ใช่เป้าหมายของฉัน ก่อนอื่นรหัสทั้งหมดของฉันคือ OGLES 1.x จากนั้น OGLES 1.x และ OGLES 2.x (ไม่มีการปรับปรุงประสิทธิภาพ) และตอนนี้ OGLES 2.x (ปรับปรุงการแสดงผล)
Ellis

1

ฉันอยากจะแนะนำให้มี VBO โดยแต่ละจุดสุดยอดจะมีตำแหน่ง / การหมุนของแต่ละวัตถุที่แสดงผลและการแบทช์ตามพื้นผิวที่คุณทำ ฉันไม่ค่อยคุ้นเคยกับ ogl ES ดังนั้นฉันไม่แน่ใจว่าเวอร์ชันของ glsl นั้นรองรับ แต่คุณอาจจะสามารถแบตช์ตามชุดของพื้นผิวและเก็บว่าพื้นผิวใดที่คุณกำลังผ่าน ในที่ที่คุณจะใช้ภายในจุดสุดยอด จุดสไปรท์จะปรับปรุงประสิทธิภาพการทำงานของคุณอย่างแน่นอนเพราะจะช่วยลดปริมาณข้อมูลที่คุณส่งไปอย่างมากและการแบตช์ไม่ควรลดประสิทธิภาพหากคุณทำอย่างถูกต้อง นอกจากนี้คุณสามารถปรับปรุงประสิทธิภาพได้เล็กน้อยโดยการคำนวณการหมุนบน shader และส่งผ่านค่า int / float ใน params หรือภายในจุดสุดยอดเท่านั้น (params จะเร็วขึ้น


ขอบคุณสำหรับคำตอบ. ข้อเสนอแนะของคุณเกี่ยวกับการคำนวณการหมุนใน shader คือ excellet แต่น่าเสียดายที่ฉันใช้ OpenGL ES 1 ซึ่งไม่รองรับ shaders ดังนั้นฉันจึงติดอยู่กับไปป์ไลน์ ฉันจะลองชี้สไปรท์ แต่ฉันไม่สามารถใช้ได้ในทุกกรณีเพราะมีขีด จำกัด สูงสุดสำหรับขนาดของมัน ฉันยังคงมองโลกในแง่ร้ายเล็กน้อยเกี่ยวกับ VBO ถ้าฉันคำนวณตำแหน่งของแต่ละจุดสุดยอดทุกเฟรม VBO จะช่วยได้อย่างไร
user4241

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

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

1

คุณพูดถึงแพลตฟอร์มมือถือที่ไม่มีอินสแตนซ์ แต่คุณยังมียอดสุดยอดใช่มั้ย

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

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


นี่เป็นวิธีแก้ปัญหาที่ดีสำหรับ OpenGL ES 2.0 น่าเสียดายที่ฉันใช้ ES 1 ซึ่งไม่ได้มีเฉดสีเลย
user4241

0

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


ฉันไม่เข้าใจวิธีนี้จะช่วยได้อย่างไรเมื่อฉันมีวัตถุเกม 200 รายการที่มีการแปลงเฉพาะ การใช้ glMultMatrix จะใช้การแปลงแบบเดียวกันกับวัตถุทั้งหมดซึ่งไม่ใช่สิ่งที่ฉันต้องการ นอกจากนี้การส่งข้อมูลไปยัง GPU ไม่ได้เป็นปัญหาคอขวด ถ้าฉันลบการแปลงซีพียู perfomance ดีมาก
user4241

ใช่ แต่ VBO ยังสามารถปรับปรุงประสิทธิภาพได้หากใช้อย่างถูกต้อง ปัจจุบันคุณแสดงวัตถุ 200 รายการของคุณอย่างไร คุณใช้ glBegin / glEnd หรือไม่
TheBuzzSaw

1
ฉันใช้โปรแกรม Irrlicht 3D พร้อมโหนดฉากที่กำหนดเองดังนั้นฉันจึงไม่ได้ใช้ OpenGL โดยตรง (แต่ฉันคิดว่ามันใช้ glBegin / glEnd อย่างง่ายในกรณีนี้) VBO จะช่วยจริงหรือไม่เพราะฉันจะต้องแก้ไขบัฟเฟอร์ทั้งหมดทุกเฟรม? นอกจากนี้สิ่งนี้ไม่ได้แก้ปัญหาพื้นฐานเกี่ยวกับการผูก CPU เนื่องจากการคำนวณจุดสุดยอดแปลง แต่ขอบคุณสำหรับคำตอบของคุณ!
user4241
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.