พื้นผิวของแผ่นสไปรต์ยกขอบของพื้นผิวที่อยู่ติดกัน


10

ฉันมีชุดสไปรต์แบบกำหนดเอง (openGL 2.0) ซึ่งใช้แผ่นงานสไปรต์ง่าย ๆ (พื้นผิวของฉันถูกจัดเรียงในแนวนอนติดกัน)

ตัวอย่างเช่นนี่คือแผ่นทดสอบสไปรต์ที่มีพื้นผิวที่เรียบง่าย 2 แบบ:

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

ตอนนี้สิ่งที่ฉันทำเมื่อสร้างวัตถุ openGL sprite ของฉันคือการระบุจำนวนเฟรมทั้งหมดในแอตลาสและเมื่อวาดให้ระบุเฟรมที่ฉันต้องการวาด

จากนั้นจะหาตำแหน่งที่จะจับพื้นผิวจาก:

การหารหมายเลขเฟรมที่ต้องการด้วยจำนวนเฟรมทั้งหมด (เพื่อรับค่าพิกัดซ้าย)

จากนั้นทำการดำน้ำ 1 ตามจำนวนเฟรมทั้งหมดและเพิ่มผลลัพธ์ลงในพิกัดด้านซ้ายที่คำนวณข้างต้น

ดูเหมือนว่าจะใช้งานได้ แต่บางครั้งฉันก็มีปัญหา พูดเช่นฉันต้องการวาด X ด้านล่างและฉันได้รับ ...........

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

ฉันเคยได้ยินเกี่ยวกับการใส่ 'padding' ของ 1 px ระหว่างแต่ละพื้นผิว แต่บางคนสามารถอธิบายได้อย่างแม่นยำว่ามันทำงานอย่างไร ฉันหมายความว่าถ้าฉันทำสิ่งนี้มันจะสลัดการคำนวณออกไปเพื่อให้ได้พื้นผิว

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

จะขอบคุณถ้ามีคนอธิบาย


คุณใช้GL_NEARESTหรือGL_LINEARแสดงพื้นผิวหรือไม่?
MichaelHouse

ฉันใช้ GL_Linear @ Byte56
BungleBonce

คำตอบ:


15

ปัญหาเกี่ยวกับการใช้ atlases พื้นผิวและการรั่วไหลของข้อความที่อยู่ติดกันนั้นเกี่ยวข้องกับวิธีการทำงานของการกรองพื้นผิวเชิงเส้น

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

นี่คือการสร้างภาพที่ดีของปัญหา:

  

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

โปรดทราบว่าเมื่อคุณใช้ตัวกรอง anisotropic คุณอาจต้องเพิ่มความกว้างของเส้นขอบ นี่เป็นเพราะตัวกรอง anisotropic จะเพิ่มขนาดของพื้นที่ใกล้เคียงตัวอย่างในมุมที่รุนแรง


ในการอธิบายสิ่งที่ฉันหมายถึงโดยใช้เส้นขอบรอบ ๆ ขอบของแต่ละพื้นผิวให้พิจารณาโหมดการตัดคำที่หลากหลายที่มีอยู่ใน OpenGL CLAMP TO EDGEความสนใจเป็นพิเศษ

  http://lucera-project.com/blog/wp-content/uploads/2010/06/wrap.png

แม้จะมีโหมดที่เรียกว่า "Clamp to Border" แต่จริงๆแล้วไม่ใช่สิ่งที่เราสนใจโหมดนั้นให้คุณกำหนดสีเดียวเพื่อใช้เป็นเส้นขอบรอบ ๆ พื้นผิวของคุณสำหรับพิกัดพื้นผิวใด ๆ ที่อยู่นอกมาตรฐาน [0.0 ช่วง -1.0]

สิ่งที่เราต้องการคือการทำซ้ำพฤติกรรมของCLAMP_TO_EDGEซึ่งพื้นผิวใด ๆ ที่ประสานงานนอกช่วงที่เหมาะสมสำหรับพื้นผิว (ย่อย -) ได้รับค่าของศูนย์เท็กเซลสุดท้ายในทิศทางที่มันเกินขอบเขตเนื่องจากคุณเกือบจะควบคุมได้อย่างสมบูรณ์ พิกัดพื้นผิวในระบบ atlas สถานการณ์เดียวที่พิกัดพื้นผิว (มีผลบังคับใช้) อาจอ้างถึงตำแหน่งนอกพื้นผิวของคุณอยู่ในระหว่างขั้นตอนถัวเฉลี่ยถ่วงน้ำหนักของการกรองพื้นผิว

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

นี่คือตัวอย่างของพื้นผิวที่แสดงเส้นขอบที่ชัดเจนยิ่งขึ้น แต่สำหรับจุดประสงค์ของคุณคุณสามารถทำให้เส้นขอบ 1 texel หรือ 2 texels กว้าง

  

(หมายเหตุ: เส้นขอบที่ฉันอ้างถึงไม่ใช่สีดำรอบขอบทั้งสี่ของภาพ แต่พื้นที่ที่รูปแบบกระดานหมากรุกหยุดทำซ้ำเป็นประจำ)

ในกรณีที่คุณสงสัยนี่คือเหตุผลที่ฉันนำเสนอการกรองแบบแอนไอโซทรอปิก มันเปลี่ยนรูปร่างของละแวกใกล้เคียงตัวอย่างตามมุมและสามารถทำให้มากกว่า 4 texels ที่จะใช้สำหรับการกรอง:

  http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg

ยิ่งคุณใช้ anisotropy มากเท่าไหร่คุณก็จะยิ่งมีแนวโน้มจัดการกับกลุ่มตัวอย่างที่มีมากกว่า 4 texels ขอบเท็กเซล 2 อันควรเพียงพอสำหรับสถานการณ์การกรองแบบแอนไอโซทรอปิกส่วนใหญ่


สุดท้าย แต่ไม่GL_CLAMP_TO_EDGEท้ายสุดนี่คือวิธีสร้างแผนที่พื้นผิวที่บรรจุซึ่งจะจำลองพฤติกรรมในการมีตัวกGL_LINEARรองพื้นผิว:

( ลบ 1 จาก X และ Y ในพิกัดสีดำฉันไม่ได้พิสูจน์อ่านภาพก่อนโพสต์ )   

เนื่องจากการจัดเก็บข้อมูลแบบขอบการจัดเก็บพื้นผิว 4 256x256 ในแผนที่นี้ต้องใช้พื้นผิวที่มีขนาด 516x516 เส้นขอบนั้นใช้รหัสสีตามวิธีที่คุณเติมข้อมูล texel ในระหว่างการสร้างแผนที่:

  • Red = แทนที่ด้วย texel โดยตรงด้านล่าง
  • สีเหลือง = แทนที่ด้วย texel ด้านบนโดยตรง
  • เขียว = แทนที่ด้วย texel ทางด้านซ้ายโดยตรง
  • Blue = แทนที่ด้วย texel โดยตรงไปทางขวา

อย่างมีประสิทธิภาพในตัวอย่างที่บรรจุนี้พื้นผิวแต่ละอย่างในแผนที่ใช้พื้นที่ 258x258 ของแผนที่ แต่คุณจะสร้างพิกัดพื้นผิวที่แมปไปยังพื้นที่ 256x256 ที่มองเห็นได้ เท็กซัสที่มีพรมแดนติดจะใช้เมื่อทำการกรองพื้นผิวที่ขอบของพื้นผิวในแผนที่และวิธีที่พวกเขาได้รับการออกแบบเลียนแบบGL_CLAMP_TO_EDGEพฤติกรรม

ในกรณีที่คุณสงสัยคุณสามารถใช้โหมดการห่ออื่น ๆ โดยใช้วิธีการที่คล้ายกัน - GL_REPEATสามารถนำไปใช้ได้โดยการแลกเปลี่ยนเท็กซัสเส้นขอบซ้าย / ขวาและบน / ล่างในแผนที่พื้นผิวและประสานงานคณิตศาสตร์พื้นผิวที่ฉลาดเล็กน้อยใน Shader มันซับซ้อนกว่านี้เล็กน้อยดังนั้นอย่ากังวลกับเรื่องนี้ในตอนนี้ เนื่องจากคุณกำลังจัดการแผ่นงานสไปรท์ จำกัด ตัวเองไว้ที่GL_CLAMP_TO_EDGE:)


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

@ user22241 แน่นอนวิธีการทำงานของเส้นขอบนี้คือการทำซ้ำ Texel ที่ขอบของพื้นผิว
Andon M. Coleman

@ user22241: ไม่ขอบนี้จะไม่ปรากฏในสถานการณ์ปกติ คุณจะถือว่าพื้นผิวที่บรรจุของคุณมีขนาดเดียวกันสำหรับการคำนวณพิกัดพื้นผิวคุณเพียงแค่ใช้การชดเชยกับพวกมันเพื่อข้ามผ่านเส้นขอบ จุดทั้งหมดของเส้นขอบคือเพื่อป้องกันการสุ่มตัวอย่างพื้นผิวเชิงเส้นจากการเข้าถึงและเท็กซัสการสุ่มตัวอย่างที่เป็นของภาพแยกต่างหากในแผ่นสไปรต์ของคุณ หากคุณใช้การสุ่มตัวอย่างเพื่อนบ้านที่ใกล้ที่สุดไม่จำเป็นต้องทำสิ่งนี้ แต่คุณจะได้รับสไปรต์ aliased ที่น่ารังเกียจ
Andon M. Coleman

คำตอบที่มีรายละเอียดยอดเยี่ยม - ขอบคุณ! สิ่งสุดท้ายถ้าฉันทำได้ ฉันจะหา 'ออฟเซ็ต' เพื่อเพิ่มลงในพิกัดพื้นผิวของฉันได้อย่างไร ฉันพูดถูกหรือเปล่าว่ามันจะเป็น 1 / widthOfTexture
BungleBonce

@ user22241: ใช่การเริ่มต้นของภาพพื้นผิวจะเป็น + 1 / widthOfTexture ในทิศทาง X และ + 1 / heightOfTexture ในทิศทาง Y คุณจะมีเส้นขอบที่ล้อมรอบแต่ละพื้นผิว ตามเวลาที่คุณต้องการคำนวณพิกัดพื้นผิวสำหรับพื้นผิวแนวนอนที่ 3 ตำแหน่งที่บรรจุสำหรับพื้นผิวนี้จะเป็นจริง +5 texels (+2 texels สำหรับเส้นขอบพื้นผิวแรก +2 สำหรับขอบพื้นผิวที่สองและ +1 สำหรับการเริ่มต้น ของพื้นผิวนี้) นอกเหนือจากความกว้างของพื้นผิวอีก 2 แบบ ดูเหมือนจะซับซ้อนเพียงแค่เขียนมัน ฉันสามารถวาดแผนภาพให้คุณได้ถ้าจำเป็น :)
Andon M. Coleman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.