วิธีที่มีประสิทธิภาพในการวาดโครงร่างรอบสไปรต์


21

ฉันใช้ XNA เพื่อเขียนโปรแกรมเกมและได้ทดลองวิธีการต่าง ๆ เพื่อให้ได้ผล 'ที่เลือก' บนสไปรต์ของฉัน ปัญหาที่ฉันมีอยู่ก็คือการคลิกแต่ละครั้งที่ถูกดึงลงไปใน Spritebatch นั้นถูกใช้มากกว่า Sprite เดียว (แต่ละวัตถุสามารถสร้างได้มากถึง 6 Sprite)

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

ขอบคุณล่วงหน้า,

  • เกร็ก

คำตอบ:


20

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

  • รุ่นปกติ
  • "อ้วน" รุ่นที่ไม่มีสี - โดยทั่วไปเป็นรุ่นสีขาวของสไปรต์ X-พิกเซลหลายตัวของคุณ "อ้วนขึ้น" กว่าเดิม

วาดวัตถุทั้งหมดของคุณโดยใช้รุ่น "อ้วน" แล้ววาดรุ่นปกติที่ด้านบน

ด้วยการทำให้รุ่น "อ้วน" ขาวคุณสามารถใช้ SprintBatch สีในตัวเพื่อเปลี่ยนสีการเลือกแบบไดนามิก

หากต้องการสร้างรูปแบบ "อ้วน" ของคุณฉันขอแนะนำให้เขียนส่วนขยายไปป์ไลน์เนื้อหาที่สามารถนำสไปรต์ดั้งเดิมของคุณไปอ่านช่องอัลฟ่าของพวกเขาสร้างช่องอัลฟาใหม่โดยสุ่มตัวอย่างช่องอัลฟาสูงสุดในภาพต้นฉบับ และการตั้งค่า RGB = (1,1,1)

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

หากคุณมีสไปรต์ไม่กี่ตัวคุณก็สามารถใช้โปรแกรมแก้ไขภาพที่ดี (GIMP, Photoshop) และทำมันเอง: ช่องอัลฟ่าเพื่อเลือกขยายขยายส่วนที่เลือกไปที่อัลฟาเติมช่องสีขาว


4

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


11
Shader แบบนี้น่ารำคาญอย่างมากที่เขียนฉันได้ยินมา (เราใช้มันในหนึ่งในเกมสามมิติของเราและยังคงทำงานเป็นเคสขอบที่ไม่น่าดู) สิ่งหนึ่งที่คุณอาจต้องการพิจารณาคือการเข้ารหัสโครงร่างลงในพื้นผิวสไปรต์โดยตรงด้วยสีเฉพาะเช่น (0, 255, 255, 0) และเพียงแค่ให้ shader เปลี่ยนสีนั้นเมื่อเลือกสไปรต์ จากนั้น shader จะเปลี่ยนสีเล็กน้อยและคุณมีระดับสูงของศิลปินในการควบคุมโครงร่างและรายละเอียดใด ๆ ที่คุณต้องการ

4

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

when selected:
   outline = new sprite canvas of appropriate size
   for sprite in object:
      # use larger numbers for thicker outlines
      for x in (-1, 0, 1) and y in (-1, 0, 1):
         render sprite mask into canvas at x,y with desired color

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


ใช่นี่คือสิ่งที่ฉันอยากจะแนะนำเช่นกัน สไปรต์ที่สวมหน้ากาก 1 พิกเซลไปทางซ้ายขวาบนและล่างของสไปรต์ดั้งเดิมภายใต้สไปรต์ที่มีอยู่ เกมจำนวนมากใช้วิธีนี้เพื่อจัดเค้าร่างข้อความที่แสดงผลหรือมีเพียง 2 ใน 4 ตำแหน่งเพื่อสร้างเงา
Kaj

1

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

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


ฉันคิดว่าส่วนหนึ่งของปัญหาคือ OP บอกว่าแต่ละวัตถุสามารถทำสไปรต์ได้หลายตัว ดังนั้นฉันเดาว่าโครงร่างต้องเป็นโครงร่างของวัตถุที่รวมกันแทนที่จะมีโครงร่างแยกกันรอบ ๆ ส่วนประกอบแต่ละส่วน
Chris Howe

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

1

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


2
ทำไมไม่เพียงแค่วาดร่างสไปรต์ก่อนแล้ววาดสไปรต์ปกติเหนือพวกเขา?
Chris Howe

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

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

1
ความคิดของคริสมีคุณค่า นอกเหนือจากการมีไฟล์อัพเดตของศิลปิน 2 (หรือแม้กระทั่งเนื้อหาเดียวกัน) สามารถหลีกเลี่ยงได้หากคุณสร้างเครื่องมือเพื่อสร้างอัลฟาสำหรับสไปรต์ร่างที่ทำงานเป็นส่วนหนึ่งของเนื้อหา / เนื้อหาของคุณ หน่วยความจำของพื้นผิวอาจมีหรือไม่มีปัญหา แต่ sprite เค้าร่างแยกต่างหากควรมีความสามารถในการบีบอัด DXT สูง อาจมีขนาด 1 / 6th ของพื้นผิวดั้งเดิมในหน่วยความจำวิดีโอและไม่มีการสูญเสียความเที่ยงตรง
jpaver

1

โซลูชันที่แตกต่างกันสองสามอย่างที่มีการแลกเปลี่ยนต่างกัน

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

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

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


0

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

แก้ไข: อย่างไรก็ตามอย่างที่คุณเห็นจากความคิดเห็นนี่ไม่ใช่ความคิดที่ดี


1
เพียงแค่ปรับขึ้นเทพดาไม่ให้ร่างที่แท้จริง
Iain

2
ฉันไม่คิดว่ามันจะ แต่มันจะง่าย
The Duck คอมมิวนิสต์

2
สิ่งต่าง ๆ มากมายนั้นง่าย แต่ไม่ได้แก้ปัญหา สำหรับสไปรต์ที่มีรูปเงาดำที่น่าสนใจใด ๆ การขยายขนาดจะทำให้ขยะสมบูรณ์

การขยายขนาดจะดูดีสำหรับวัตถุทรงสี่เหลี่ยมหรือทรงกลมเท่านั้น ถ้ารูปร่างกว้างหรือสูงจริงหรือมีช่องว่างมันจะดูแย่มาก
AttackHobo

3
การขยายขนาดจะให้ผลลัพธ์ที่ดีกว่าการไม่ทำอะไรเลยและจะเป็นขั้นตอนที่มีประโยชน์ตามเส้นทางสู่ "ความสมบูรณ์แบบ" ในขณะที่ผลลัพธ์กราฟิกจะไม่สมบูรณ์แบบหากเป็นเครื่องมือภายในก็อาจดีพอ
dash-tom-bang

0

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

  • เช่น spriteOutline.Scale = spriteOriginal.Scale * 0.1f; spriteOutline.Color = new Color (255, 0, 0, 255);

0

เปลี่ยนสีของสไปรต์ดั้งเดิมด้วยสีโครงร่าง (หรือแต้มสีได้ถ้าต้องการ) แสดงสไปรต์แบบแรเงาหรือโทนสีนี้สี่ครั้งด้วยการชดเชย 1 พิกเซล: ที่ x, y = (- 1, -1), จากนั้น (+ 1, -1), จากนั้น (-1, + 1) จากนั้น (+1 , +1) ทำซ้ำสำหรับ sprites ทั้งหมดที่ประกอบขึ้นเป็นวัตถุ

หลังจากนั้นให้สไปรต์ต้นฉบับตามลำดับที่เหมาะสมอยู่ด้านบนที่ (0,0)

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