การใช้ความละเอียดบัฟเฟอร์ความลึกเต็มรูปแบบสำหรับการแสดงผล 2D


9

ฉันกำลังทำงานกับโหมดแสดงภาพแบบด้านหน้าไปด้านหลังสำหรับเครื่องยนต์ 2D โดยใช้การฉายภาพแบบออโธกราฟฟิค ฉันต้องการใช้บัฟเฟอร์ความลึกเพื่อหลีกเลี่ยงการถอนเงินมากเกินไป ฉันมีบัฟเฟอร์ความลึก 16 บิตกล้องที่ Z = 100 ดูที่ Z = 0, z ใกล้เคียงคือ 1 และ zFar คือ 1,000 แต่ละสไปรต์ที่แสดงผลจะตั้งค่าพิกัด Z ของมันเป็นค่าที่ห่างไกลมากขึ้น อะไรก็ตามที่อยู่ด้านล่าง

อย่างไรก็ตามฉันทราบวิธีการที่ตำแหน่ง Z ลงท้ายด้วยค่าบัฟเฟอร์ Z คือไม่ใช่เชิงเส้น ฉันต้องการใช้ความละเอียดเต็มรูปแบบของบัฟเฟอร์ความลึก 16 บิตนั่นคืออนุญาตให้มีค่าที่ไม่ซ้ำกัน 65536 ชิ้น ดังนั้นสำหรับทุก sprite ที่เรนเดอร์ฉันต้องการเพิ่มตำแหน่ง Z ไปยังตำแหน่งถัดไปเพื่อให้สัมพันธ์กับค่าบัฟเฟอร์ความลึกที่ไม่ซ้ำกันถัดไป

กล่าวอีกนัยหนึ่งฉันต้องการเปลี่ยนดัชนีที่เพิ่มขึ้น (0, 1, 2, 3 ... ) ของสไปรต์ที่ถูกดึงเข้าไปในตำแหน่ง Z ที่เหมาะสมสำหรับแต่ละสไปรต์เพื่อให้มีค่าบัฟเฟอร์ความลึกที่ไม่ซ้ำกัน ฉันไม่แน่ใจเกี่ยวกับคณิตศาสตร์ที่อยู่เบื้องหลังสิ่งนี้ การคำนวณเพื่อทำสิ่งนี้คืออะไร?

หมายเหตุฉันทำงานใน WebGL (โดยทั่วไป OpenGL ES 2) และฉันต้องการสนับสนุนฮาร์ดแวร์ที่หลากหลายดังนั้นในขณะที่ส่วนขยายเช่น gl_FragDepth อาจทำให้สิ่งนี้ง่ายขึ้นฉันไม่สามารถใช้ด้วยเหตุผลด้านความเข้ากันได้


ฉันนึกภาพไม่ออกเลยว่าการใช้บัฟเฟอร์ z จะมอบประสิทธิภาพที่เพิ่มขึ้นให้กับคุณ (ถ้ามี) หลังจากที่คุณได้เพิ่มการเขียนบัฟเฟอร์การคำนวณและการเปรียบเทียบทั้งหมดกับการคัดลอกพื้นผิวด้านหน้าไปข้างหน้า woes
Matt Esch

@MattEsch: แนวคิดคือการคำนวณทั้งหมดนั้นทำใน GPU ด้วยความเร็วสูงอย่างเห็นได้ชัดดังนั้นจึงเหมาะสมที่จะทำเช่นนั้น
แพนด้า Pyjama

@MattEsch: FWIW นี้มุ่งเน้นไปที่ GPU ในตัวของ Intel ซึ่งใช้หน่วยความจำระบบแทนหน่วยความจำ GPU โดยเฉพาะ สิ่งนี้ทำให้พวกเขาค่อนข้างช้าและมีแนวโน้มที่จะกดขีด จำกัด อัตราการเติมหากถอนสไปรท์จำนวนมากออกไป Intel แนะนำวิธีนี้สำหรับฉันในการหลีกเลี่ยง สันนิษฐานว่าการนำการทดสอบเชิงลึกมาใช้นั้นได้รับการปรับให้เหมาะสมและสามารถประหยัดอัตราการเติมได้ มันยังคงที่จะเห็นว่าฉันยังไม่ได้ทำโปรไฟล์!
AshleysBrain

@PandaPajama การคัดลอกบล็อกหน่วยความจำจริง ๆ แล้วเร็วมากดังนั้นหากคุณเพียงแค่ตัดพื้นผิวบนพื้นผิวมันจะเร็วมากอย่างแน่นอน ค่าใช้จ่ายหลักครั้งแรกคือการรับข้อมูลไปยัง GPU ในตอนแรกซึ่งแอชลีย์ชี้ให้เห็นอาจมีราคาแพงกว่าใน GPU แบบรวม คุณพบว่าแม้แต่เกม 3 มิติจำนวนมากก็ยังทำงานบน CPU (เช่นภาพเคลื่อนไหวของกระดูก) เนื่องจากการอัปโหลดข้อมูลที่ต้องใช้ในการคำนวณเมทริกซ์ในตอนแรกนั้นแพงเกินไป
Matt Esch

@MattEsch: มีเพียงสิ่งเดียวที่คุณสามารถทำได้ด้วยการ blitting การหมุนภาพการปรับขนาดและการเสียรูปเป็นสิ่งสำคัญ แต่เนื่องจากคุณมีพิกเซล / จุดยอดยอด จำกัด ของสิ่งที่คุณสามารถทำได้กับฮาร์ดแวร์นั้นสูงกว่าสิ่งที่คุณทำได้เพียงแค่เบลอ
แพนด้า Pyjama

คำตอบ:


5

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

สิ่งที่คุณทำคือการที่คุณแผนที่ของคุณzNearไป0และคุณจะzFar 1สำหรับzNear=1และzFar=2ควรมีลักษณะเช่นนี้

Zbuffer

วิธีการคำนวณสิ่งนี้ถูกกำหนดโดย:

z_buffer_value = k * (a + (b / z))

ที่ไหน

 k = (1 << N), maximum value the Z buffer can store
 N = number of bits of Z precision
 a = zFar / ( zFar - zNear )
 b = zFar * zNear / ( zNear - zFar )
 z = distance from the eye to the object

... และ z_buffer_value เป็นจำนวนเต็ม

สมการข้างต้นถูกนำเสนอให้คุณด้วยความสุภาพของหน้าเจ๋ง ๆ นี้ซึ่งอธิบายถึง z-buffers ในวิธีที่ดีจริงๆ

ดังนั้นเพื่อที่จะค้นหาสิ่งที่จำเป็นzสำหรับการกำหนดz_buffer_valueเราแค่เคลียร์z:

z = (k * b) / (z_buffer_value - (k * a))

ขอบคุณสำหรับคำตอบ! ฉันสับสนเล็กน้อยว่าคุณมีสูตรขั้นสุดท้ายอย่างไร ถ้าฉันใช้z_buffer_value = k * (a + (b / z))และเพียงแค่จัดเรียงใหม่เพื่อแก้ปัญหาzแล้วฉันจะได้รับ: z = b / ((z_buffer_value / k) - a)- คุณมาถึงสูตรสุดท้ายที่แตกต่างกันอย่างไร
AshleysBrain

@AshleysBrain: คุณใช้ตัวหารและการล่มสลายไป(v / k) - a => (v - k * a) / k (k * b) / (v - (k * a))มันเป็นผลลัพธ์เดียวกัน
แพนด้า Pyjama

อ่าฉันเข้าใจแล้ว ขอบคุณสำหรับคำตอบมันทำงานได้ดี!
AshleysBrain

0

บางทีคุณควรเปลี่ยนวิธีการของคุณเป็นอะไรที่ง่ายกว่านี้ ฉันจะทำอะไร รักษาความลึก Z ของคุณ แต่เก็บรายการสิ่งที่คุณแสดง สั่งซื้อรายการตามค่าความลึก z และแสดงวัตถุในลำดับของรายการ

หวังว่านี่จะช่วยได้ ผู้คนมักบอกให้ฉันทำสิ่งต่าง ๆ ให้เรียบง่ายอยู่เสมอ


1
ขออภัยนั่นไม่ได้ช่วยอะไรมาก ฉันทำไปแล้ว คำถามเกี่ยวกับตำแหน่ง Z ที่จะเลือก
AshleysBrain

0

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


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