กราฟิก 2D - ทำไมต้องใช้ spritesheets


62

ฉันได้เห็นตัวอย่างมากมายเกี่ยวกับวิธีแสดงสไปรต์จาก spritesheet แต่ฉันไม่เข้าใจเลยว่าทำไมมันเป็นวิธีที่พบได้บ่อยที่สุดในการจัดการกับสไปรต์ในเกม 2d

ฉันเริ่มด้วยการเรนเดอร์เรนเดอร์แบบ 2d ในแอปพลิเคชั่นตัวอย่างไม่กี่ตัวที่ฉันทำโดยจัดการกับเฟรมภาพเคลื่อนไหวแต่ละประเภทสำหรับสไปรต์ประเภทใดก็ตามที่เป็นพื้นผิวของตัวเอง - และ ดูเหมือนว่าจะเหมาะกับฉันและเหมาะสมกับขั้นตอนการทำงานของฉันเพราะฉันมักจะทำแอนิเมชั่นเป็นไฟล์ gif / mng แล้วแยกเฟรมไปที่ pngs แต่ละอัน

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

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

ฉันสงสัยว่ามีเหตุผลที่ดีมากที่นักพัฒนาเกม 2d ส่วนใหญ่ดูเหมือนจะใช้พวกเขาฉันไม่เข้าใจว่าทำไม


ไม่มันไม่สำคัญมากนักสำหรับสไปรท์แปลก ๆ 50 ของคุณ แต่จะเสียอะไร
The Duck Communist

คำตอบ:


69

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

นอกจากนี้ให้พิจารณาว่าขนาดพื้นผิวมักเป็นกำลัง 2 ดังนั้นหากคุณมี Sprite 50x100px คุณจะจัดสรรพื้นผิวด้วยขนาด 64x128px หรือในกรณีที่แย่กว่านั้นคือ 128x128px นั่นเป็นเพียงการสูญเสียหน่วยความจำกราฟิก ดีกว่าแพ็คสไปรต์ทั้งหมดลงในพื้นผิว 1024x1024px ซึ่งจะอนุญาตให้สไปรต์ 20x10 และคุณจะเสีย 24 พิกเซลในแนวนอนและแนวตั้ง บางครั้งแม้แต่สไปรต์ที่มีขนาดต่างกันก็รวมกันเป็นสไปรต์แผ่นใหญ่เพื่อใช้พื้นผิวที่มีประสิทธิภาพที่สุด

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


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

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

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

5
จุดที่ดี แต่สิ่งที่สำคัญที่สุดคือลดการวางท่อโดยทำให้การเรียกการนับถอยหลังลดลง GPU ต้องการงานขนาดใหญ่จำนวนน้อยมากกว่างานขนาดเล็กที่มีจำนวนมาก การใส่สไปรต์ทั้งหมดของคุณลงในแผ่นกระดาษขนาดใหญ่จำนวนมากหมายความว่าคุณสามารถตั้งเวที textue ขึ้นหนึ่งครั้งและดึง spites จำนวนมากพร้อมกันในชุด Spritebatch ทำสิ่งนี้เพื่อคุณ หากคุณมีมากกว่าหนึ่ง sprites แผ่นให้แน่ใจว่าได้บอก spritebatch เพื่อจัดเรียงตามพื้นผิว
Cubed2D

การเพิ่มการบีบอัดพื้นผิวจะทำให้พื้นที่ที่หย่อนลงเป็นค่าใช้จ่ายเล็ก ๆ น้อย ๆ เหนือสิ่งอื่นใด
Joe Plante

36

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

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


2
+1 สัมผัสเมื่อมีการดึงสาย (สิ่งที่ฉันไม่เห็นในคำตอบที่ยอมรับ)
Michael Coleman

11

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


2
มันยังสำคัญอยู่ ฮาร์ดแวร์กราฟิกได้รับการปรับให้เหมาะสมเพื่อผลักดันรูปหลายเหลี่ยมจำนวนมากสำหรับแบบจำลองที่มีรายละเอียดจำนวนเล็กน้อย (เช่นตัวอักษร) เนื่องจากเกมส่วนใหญ่มีแนวโน้มในทิศทางนั้น ผลที่ได้คือคุณต้องกดรูปหลายเหลี่ยมให้ได้มากที่สุดเท่าที่จะทำได้ในแต่ละครั้ง เอ็นจิ้นเกมที่แสดงฉากขนาดใหญ่เช่นเมืองมักจะรวมพื้นผิวหลาย ๆ แบบไว้ในที่เดียวเพื่อลดการเรียกสาย
jhocking

ฉันสงสัยว่าถ้าพื้นผิวคุณ, แมป v ในฮาร์ดแวร์ 3 มิติจำนวนมากบวกกับการดำเนินการบิตบลิสต์ได้รับประโยชน์จากแผ่นสไปรต์
Joe Plante

7

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

นอกจากนี้ฉันใช้รหัสใน AS3 และไฟล์ภาพแต่ละไฟล์ต้องมีคำแนะนำการฝังแยกต่างหาก ฉันควรจะฝังสไปรต์ทั้งหมดแผ่นเดียวมากกว่า 24 เฟรมสำหรับเฟรมทั้งหมดแม้ว่าฉันจะใช้คลาสทรัพยากรแยกต่างหาก


1
+1 แม้ว่า OP ไม่ได้ใช้ Flash แต่การฝังหรือการโหลดนั้นเป็นจุดสำคัญของ spritesheets นอกจากนี้ยังเกี่ยวข้องเมื่อโหลดเนื้อหาจากเว็บเซิร์ฟเวอร์ที่ต้องการ 1 คำขอมากกว่าคำขอหลายร้อยรายการ (สำหรับ "เฟรม" แต่ละรายการ)
bummzack

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

7

อีกเหตุผลหนึ่งที่ใช้ spritesheets กับ XNA คือการที่มีการพัฒนา Xbox360 มีปัญหาที่ทราบกันดีว่าเวลาในการปรับใช้ / โหลดช้าเกี่ยวข้องกับจำนวนไฟล์ที่คุณมีในโครงการของคุณ ดังนั้นการรวมไฟล์ภาพขนาดเล็กจำนวนมากไว้ในไฟล์ภาพเดียวจะช่วยต่อสู้กับปัญหาดังกล่าว


5

ฉันจะไม่พูดถึงหน่วยความจำ / GPU ที่นี่เนื่องจากมีคำตอบอย่างนั้น

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

และจากนั้นก็ยังสะอาดขึ้น (จากมุมมองของการจัดระเบียบ) เพื่อให้มีตัวละคร. png และศัตรู. png ข้ามตัวละครทางเดินที่ 1 ถึงตัวละครทางเดิน 10 จากนั้นก็ตัวละครที่ 01 ไปยังตัวละครที่ 05


4

หน่วยความจำกราฟิกไม่มีการจัดการหน่วยความจำแบบ bloat up เช่นระบบไฟล์บนดิสก์ ตรงข้ามเป็นกรณี: มันจะถูกเก็บไว้ที่เรียบง่ายและรวดเร็ว

การจัดการหน่วยความจำที่เรียบง่ายและรวดเร็วเช่นนั้นอาจเป็นเหมือนผียักษ์ตัวเดียว 4096x4096 ตัวหนึ่งที่ถูกสไปรท์ขนาดเล็กหลาย ๆ อันโดยแบ่งครึ่งความกว้างและ / หรือความสูง (มีเทคนิคการจัดการหน่วยความจำ 1 มิติที่คล้ายกันอยู่ แต่ฉันลืมชื่อ) ในที่สุดการจัดเรียงข้อมูลจะต้องดำเนินการ

หากต้องการข้ามการจัดการหน่วยความจำแบบรันไทม์นักพัฒนาจะเติม sprite ขนาดใหญ่เดี่ยวด้วย sprites ขนาดเล็กหลาย ๆ ตัวโดยอัตโนมัติในเวลาคอมไพล์หรือแม้กระทั่งในขณะที่อยู่ระหว่างการออกแบบกราฟิก


3

นอกจากนี้อย่าลืมการดำเนินการ I / O ซึ่งอาจช่วยคุณในระหว่างการเริ่มต้น หากคุณกำลังโหลดจากไดรฟ์ซีดีแต่ละไฟล์เป็นการโทร I / O พิเศษและอาจต้องใช้เวลาสักครู่ในการค้นหา (HDD ที่ทันสมัยอยู่ที่ประมาณ 15 ms ต่อไฟล์อาจเป็นซีดีประมาณ 50-100ms) วิธีนี้ช่วยให้คุณประหยัดเวลาในการเริ่มต้นได้มากเนื่องจากต้องดึงข้อมูลไฟล์เดียวเท่านั้น นอกจากนี้ยังช่วยให้ระบบปฏิบัติการของคุณแคชการดำเนินการ I / O เหล่านี้ในกรณีที่แอปพลิเคชันของคุณกำลังทำอย่างอื่น (เช่นรอ GPU)


1
ในอีกด้านหนึ่งถ้าคุณต้องการแก้ปัญหาการค้นหาไฟล์คุณสามารถรวบรวม sprites ทั้งหมดของคุณไว้ในไฟล์เดียวโดยใช้รูปแบบที่กำหนดเอง เกมส่วนใหญ่ทำเช่นนั้น
tigrou

0

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

ในความคิดของฉันมันง่ายกว่าในการเขียนโค้ด ฉันมีวัตถุหลายอย่างเช่น:

sheet = {
    img: (the actual image),
    rects: [
        {x:0, y:0, w:32, h:32},
        {x:32, y:0, w:32, h:32},
        {x:64, y:0, w:32, h:32}
    ]
};

sheets.push(sheet);

จากนั้นสำหรับแต่ละรายการฉันให้สองค่าคือแผ่นงานและ rect แผ่นจะเป็นดัชนีในอาร์เรย์ของวัตถุและ rect จะเป็นดัชนีในอาร์เรย์ของแผ่นงานนั้น

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