ฉันจะเรียงลำดับสไปรต์ภาพสามมิติลงในลำดับที่ถูกต้องได้อย่างไร


19

ในเกม 2D บนลงล่างปกติสามารถใช้แกน y ของหน้าจอเพื่อจัดเรียงภาพ ในตัวอย่างนี้ต้นไม้ถูกจัดเรียงอย่างถูกต้อง แต่ผนังมีมิติเท่ากัน:

ภาพตัวอย่าง: จัดเรียงตามหน้าจอ y

กำแพง 2 คือหนึ่งพิกเซลใต้กำแพง 1 ดังนั้นจะถูกวาดหลังกำแพง 1 และสิ้นสุดที่ด้านบน

ถ้าฉันจัดเรียงตามแกน y มีมิติเท่ากันผนังปรากฏในลำดับที่ถูกต้อง แต่ต้นไม้ไม่ได้:

ภาพตัวอย่าง: เรียงตาม isometric y

ฉันจะทำอย่างถูกต้องได้อย่างไร


3
ดูเหมือนว่าคุณจะพบปัญหาที่พบบ่อยในอัลกอรึทึมของ Painter วิธีแก้ปัญหา "ทั่วไป" คือการใช้ z-buffer =) วิธีแก้ไขปัญหาบางอย่างรวมถึงการใช้ศูนย์วัตถุเป็นคีย์การเรียงลำดับแทนที่จะเป็นบางมุม
Jari Komppa

คำตอบ:


12

เกม Isometric เป็นแบบ 3 มิติดังนั้นภายในคุณควรจัดเก็บพิกัด 3D สำหรับแต่ละเอนทิตีในเกม พิกัดที่แท้จริงที่คุณเลือกนั้นเป็นแบบสุ่ม แต่สมมติว่า X และ Y เป็นแกนสองแกนบนพื้นดินและ Z นั้นอยู่บนพื้นดินขึ้นสู่อากาศ

ตัวแสดงภาพจะต้องฉายภาพนั้นลงใน 2D เพื่อวาดสิ่งต่างๆบนหน้าจอ "Isometric" เป็นหนึ่งในการฉายดังกล่าว การฉายภาพจาก 3D เป็น 2D นั้นค่อนข้างง่าย สมมติว่าแกน X เปลี่ยนจากซ้ายบนไปล่างขวาและลงหนึ่งพิกเซลสำหรับพิกเซลแนวนอนแต่ละอัน ในทำนองเดียวกันแกน Y จะเปลี่ยนจากบนขวาไปซ้ายล่าง แกน Z ตรงขึ้น หากต้องการแปลงจาก 3D เป็น 2D แล้วเพียงแค่:

function projectIso(x, y, z) {
    return {
        x: x - y,
        y: (x / 2) + (y / 2) - z
    };
}

ตอนนี้กับคำถามเดิมของคุณเรียงลำดับ ตอนนี้เรากำลังทำงานกับวัตถุของเราโดยตรงในแบบ 3 มิติการเรียงลำดับจะง่ายขึ้นมาก ในพื้นที่พิกัดของเราที่นี่สไปรต์ที่ไกลที่สุดมีพิกัด x, y และ z ที่ต่ำที่สุด (นั่นคือทั้งสามแกนชี้ออกจากหน้าจอ) ดังนั้นคุณเพียงแค่เรียงพวกเขาด้วยผลรวมของเหล่านั้น:

function nearness(obj) {
    return obj.x + obj.y + obj.z;
}

function closer(a, b) {
    if (nearness(a) > nearness(b)) {
        return "a";
    } else {
        return "b";
    }
}

เพื่อหลีกเลี่ยงการเรียงลำดับใหม่หน่วยงานของคุณทุกกรอบใช้นกพิราบอาศัยการจัดเรียงที่มีรายละเอียดที่นี่


1
ฉันรู้ว่ามันเก่าการเริ่มต้นที่ดี แต่คุณรู้วิธีที่จะรวมขอบเขต 3 มิติของวัตถุไม่ใช่แค่การแปลเท่านั้น เมื่อพวกเขาซ้อนการเรียงลำดับความลึกจะซับซ้อนมากขึ้น
Rob

4

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

โปรดทราบว่าสำหรับวัตถุ A และ B ใด ๆ ทั้ง A ควรวาดก่อน B (A <- B), B ควรวาดก่อน A (B <- A) หรือสามารถวาดในลำดับใดก็ได้ พวกเขาเรียงลำดับบางส่วน หากคุณวาดตัวอย่างสองสามตัวอย่างด้วยวัตถุที่ทับซ้อนกัน 3 คุณอาจสังเกตเห็นว่าแม้ว่าวัตถุที่ 1 และ 3 อาจไม่ทับซ้อนกันดังนั้นจึงไม่มีการพึ่งพาโดยตรงลำดับการวาดขึ้นอยู่กับวัตถุที่ 2 ที่อยู่ระหว่างพวกเขา คุณวางไว้คุณจะได้รับคำสั่งวาดต่างกัน Bottomline - การเรียงลำดับแบบดั้งเดิมไม่ทำงานที่นี่

ทางออกหนึ่งคือการใช้การเปรียบเทียบ (กล่าวถึงโดย Dani) และเปรียบเทียบแต่ละวัตถุกับวัตถุอื่น ๆ เพื่อกำหนดการอ้างอิงของพวกเขาและสร้างกราฟการพึ่งพา (ซึ่งจะเป็น DAG) จากนั้นจัดเรียงทอพอโลยีบนกราฟเพื่อกำหนดลำดับการวาด หากมีวัตถุไม่มากเกินไปสิ่งนี้อาจเร็วพอ (มันO(n^2))

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

จากนั้นวนซ้ำวัตถุทั้งหมด X และใช้ต้นไม้รูปสี่เหลี่ยมเพื่อตรวจสอบว่ามีวัตถุใด ๆ Y ในแถบด้านบนวัตถุ X ซึ่งเริ่มต้นด้วยซ้ายสุดและสิ้นสุดด้วยมุมขวาสุดของวัตถุ X - สำหรับ Y, Y <ทั้งหมด - X. เช่นนี้คุณจะต้องสร้างกราฟและจัดเรียงทอพอโลยี

แต่คุณสามารถหลีกเลี่ยงได้ คุณใช้รายการของวัตถุ Q และตารางของวัตถุ T คุณวนซ้ำช่องที่มองเห็นได้ทั้งหมดจากค่าที่น้อยลงไปจนถึงค่าที่ใหญ่กว่าบนแกน x (หนึ่งแถว) ไปทีละแถวบนแกน y หากมีมุมด้านล่างของวัตถุที่ช่องนั้นให้ทำตามขั้นตอนด้านบนเพื่อพิจารณาการขึ้นต่อกัน หากวัตถุ X ขึ้นอยู่กับวัตถุอื่น ๆ Y ที่อยู่เหนือส่วนหนึ่ง (Y <- X) และ Y ดังกล่าวทั้งหมดอยู่ใน Q แล้วให้เพิ่ม X เป็น Q หากมีบาง Y ที่ไม่ได้อยู่ใน Q เพิ่ม X ไป T และแสดงว่า Y <- X ทุกครั้งที่คุณเพิ่มวัตถุใน Q คุณจะลบการอ้างอิงของวัตถุที่ค้างอยู่ใน T หากการอ้างอิงทั้งหมดถูกลบออกวัตถุจาก T จะถูกย้ายไปยัง Q

เรากำลังสมมติว่าวัตถุสไปรต์ไม่ได้มองออกจากช่องด้านล่างซ้ายหรือขวา (เฉพาะที่ด้านบนเช่นต้นไม้ในภาพของคุณ) สิ่งนี้ควรปรับปรุงประสิทธิภาพสำหรับวัตถุจำนวนมาก วิธีการนี้จะเป็นอีกครั้งO(n^2)แต่ในกรณีที่เลวร้ายที่สุดซึ่งรวมถึงวัตถุขนาดแปลกและ / หรือการกำหนดค่าแปลก ๆ ของวัตถุ O(n * logn * sqrt(n))ในกรณีส่วนใหญ่มันเป็น การทราบความสูงของสไปรท์สามารถกำจัดได้sqrt(n)เพราะคุณไม่ต้องตรวจสอบแถบทั้งหมดด้านบน ขึ้นอยู่กับจำนวนวัตถุบนหน้าจอคุณอาจลองแทนที่ต้นไม้รูปสี่เหลี่ยมด้วยอาร์เรย์ที่ระบุว่าจะใช้สล็อตใด (ดูสมเหตุสมผลถ้ามีวัตถุจำนวนมาก)

ในที่สุดอย่าลังเลที่จะตรวจสอบซอร์สโค้ดนี้สำหรับแนวคิดบางอย่าง: https://github.com/axel22/sages/blob/master/src/gui/scala/name/brijest/sages/gui/Canvas.scala


2

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

คุณควรเรียงลำดับตามหน้าจอ Y ต่อรายการและพูดว่าสิ่งที่ซับซ้อนกว่านั้นคือ "ปัญหาการออกแบบ" ตัวอย่างเช่นหากคุณกำลังเขียนเนื้อหาเพียงบอกนักออกแบบของคุณเกี่ยวกับอัลกอริทึมการเรียงลำดับและผลัก wall2 2 พิกเซลขึ้นไปเพื่อแก้ไขปัญหา นั่นคือวิธีที่เราต้องแก้ไขในเกมภาพวาดสามมิติที่ฉันทำงาน ซึ่งอาจรวมถึงการเอารายการ "ยาว" และแบ่งออกเป็นชิ้นย่อยขนาดกระเบื้อง

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


2

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

(a.posX + a.sizeX <= b.posX) หรือ (a.posY + a.sizeY <= b.posY) หรือ (a.posZ + a.sizeZ <= b.posZ)

แน่นอนว่านี่เป็นความคิดแรกสำหรับการใช้ isometric ที่ไร้เดียงสา สำหรับสถานการณ์ที่ซับซ้อนมากขึ้น (ถ้าคุณต้องการหมุนมุมมองตำแหน่งต่อพิกเซลบนแกน z ฯลฯ ) คุณจะต้องตรวจสอบเงื่อนไขเพิ่มเติม


+1 หากคุณมีไทล์ที่มีความกว้าง / ความสูงต่างกันให้ดูที่ฟังก์ชั่นเปรียบเทียบในคำตอบนี้
mucaho

2

ฉันใช้สูตรง่าย ๆ ที่ทำงานได้ดีกับเอนจินไอโซเมตริกตัวน้อยของฉันใน OpenGL:

วัตถุแต่ละชิ้นของคุณ (ต้นไม้กระเบื้องปูพื้นตัวละคร ... ) มีตำแหน่ง X และ Y บนหน้าจอ คุณต้องเปิดใช้งานการทดสอบความลึกและค้นหาค่า Z ที่ดีสำหรับแต่ละค่า คุณสามารถทำสิ่งต่อไปนี้:

z = x + y + objectIndex

ฉันใช้และดัชนีที่แตกต่างกันสำหรับพื้นและวัตถุที่จะอยู่เหนือพื้น (0 สำหรับพื้นและ 1 สำหรับวัตถุทั้งหมดที่มีความสูง) มันน่าจะใช้ได้ดี



1

หากคุณเปรียบเทียบค่า y ที่ตำแหน่ง x เดียวกันมันจะทำงานทุกครั้ง ดังนั้นอย่าเปรียบเทียบกึ่งกลางกับกึ่งกลาง เปรียบเทียบกึ่งกลางของสไปรท์หนึ่งด้วยตำแหน่ง x เดียวกันกับสไปรต์อื่น

ป้อนคำอธิบายรูปภาพที่นี่

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

วิธีที่ง่ายกว่าคือการแบ่งสไปรต์ทั้งหมดออกเป็นสามกลุ่ม: เส้นทแยงมุมตามแกน x, เส้นทแยงมุมตามแกน y และแนวราบ หากวัตถุทั้งสองเส้นทแยงมุมตามแกนเดียวกันให้เรียงวัตถุตามแกนอื่น


0

คุณต้องกำหนดรหัสที่เป็นเอกลักษณ์ให้กับวัตถุทั้งหมดที่เป็นประเภทเดียวกัน จากนั้นคุณเรียงลำดับวัตถุทั้งหมดตามตำแหน่งและวาดกลุ่มของวัตถุตามลำดับรหัส ดังนั้นวัตถุ 1 ในกลุ่ม A จะไม่ถอนเงินเกินวัตถุ 2 ในกลุ่ม A เป็นต้น


0

นี่ไม่ใช่คำตอบจริงๆ แต่เป็นเพียงคำอธิบายและการโหวตฉันต้องการจะให้คำตอบของ axel22 ที่นี่ /gamedev//a/8181/112940

ฉันไม่มีชื่อเสียงพอที่จะโหวตหรือแสดงความคิดเห็นคำตอบอื่น ๆ แต่ย่อหน้าที่สองของคำตอบของเขาน่าจะเป็นสิ่งที่สำคัญที่สุดที่ควรทราบเมื่อพยายามเรียงลำดับเอนทิตีในเกมภาพวาดสามมิติโดยไม่ต้องอาศัย 3D "ทันสมัย" เทคนิคเช่น Z-buffer

ในเครื่องยนต์ของฉันฉันต้องการทำสิ่งต่าง ๆ "โรงเรียนเก่า" 2D บริสุทธิ์ และฉันใช้เวลามากในการทำให้สมองของฉันพยายามคิดออกว่าทำไมการที่ฉันเรียกว่า "เรียงลำดับ" (ในกรณีของฉันมันคือ c ++ std :: sort) ทำงานไม่ถูกต้องในการกำหนดค่าแผนที่บางอย่าง

เมื่อฉันตระหนักว่านี่เป็นสถานการณ์ "บางส่วนที่สั่ง" คือฉันสามารถแก้ไขได้

จนถึงวิธีแก้ปัญหาการทำงานทั้งหมดที่ฉันพบบนเว็บใช้การเรียงลำดับโทโพโลยีเพื่อจัดการกับปัญหาอย่างถูกต้อง การเรียงลำดับโทโพโลยีน่าจะเป็นวิธีที่จะไป

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