โครงร่างการเรนเดอร์ยกเว้นว่าคุณแสดงได้เพียงโหลทั้งหมดตัวอักษรจะยังคงเป็น "ไม่ไป" เนื่องจากจำนวนจุดยอดที่ต้องการต่ออักขระจนถึงความโค้งโดยประมาณ แม้ว่าจะมีวิธีการประเมิน bezier curves ใน pixel shader แทน แต่สิ่งเหล่านี้ก็ไม่ได้ถูกลดทอนอย่างง่าย ๆ ซึ่งเป็นการใช้รูปสี่เหลี่ยมพื้นผิวแผนที่ระยะทาง
การแลกเปลี่ยนที่ดีที่สุดระหว่าง "เร็ว" และ "คุณภาพ" ยังคงเป็นพื้นผิวล่ามที่มีพื้นผิวสนามระยะทางที่ลงนาม มันช้ากว่าการใช้รูปสี่เหลี่ยมพื้นผิวธรรมดาเล็กน้อยแต่ไม่มากนัก คุณภาพในทางกลับกันอยู่ใน ballpark ที่แตกต่างกันอย่างสิ้นเชิง ผลลัพธ์ที่ได้นั้นน่าทึ่งอย่างแท้จริงมันเร็วที่สุดเท่าที่คุณจะทำได้ นอกจากนี้เทคนิคยังสามารถลดระดับลงเป็นฮาร์ดแวร์รุ่นเก่าได้หากจำเป็น
ดูกระดาษ Valve ที่มีชื่อเสียงสำหรับเทคนิค
เทคนิคนี้คล้ายกับแนวคิดที่ว่าพื้นผิวโดยนัย (metaballs และอื่น ๆ ) ทำงานอย่างไรแม้ว่ามันจะไม่สร้างรูปหลายเหลี่ยม มันทำงานอย่างสมบูรณ์ในส่วนของ pixel shader และใช้ระยะทางที่สุ่มตัวอย่างจากพื้นผิวเป็นฟังก์ชันระยะทาง ทุกอย่างที่อยู่เหนือขีด จำกัด ที่เลือก (โดยปกติ 0.5) คือ "ใน" ทุกอย่างอื่นคือ "ออก" ในกรณีที่ง่ายที่สุดบนฮาร์ดแวร์ที่ไม่สามารถใช้งานร่วมกันได้ 10 ปีการตั้งค่าเกณฑ์การทดสอบอัลฟ่าเป็น 0.5 จะทำสิ่งนั้นอย่างแน่นอน (แม้ว่าจะไม่มีเอฟเฟกต์พิเศษและการลดรอยหยัก)
หากต้องการเพิ่มน้ำหนักให้กับฟอนต์เล็กน้อย (ตัวหนามารยาท) ขีด จำกัด ที่เล็กกว่าเล็กน้อยจะทำเคล็ดลับโดยไม่ต้องแก้ไขโค้ดบรรทัดเดียว (เพียงแค่เปลี่ยนชุด "font_weight" ของคุณ) สำหรับเอฟเฟกต์เรืองแสงเราจะพิจารณาทุกอย่างที่อยู่เหนือขีด จำกัด หนึ่งเป็น "ใน" และทุกอย่างที่อยู่เหนือขีด จำกัด (เล็กกว่า) อื่นเป็น "ออก แต่อยู่ในแสงส่องสว่าง" และ LERPs ระหว่างทั้งสอง การลดรอยหยักทำงานในทำนองเดียวกัน
ด้วยการใช้ค่าระยะทางที่เซ็นชื่อแบบ 8 บิตแทนที่จะเป็นบิตเดียวเทคนิคนี้จะเพิ่มความละเอียดที่มีประสิทธิภาพของแผนที่พื้นผิวของคุณ 16 เท่าในแต่ละมิติ (แทนที่จะเป็นสีขาวและดำใช้เฉดสีที่เป็นไปได้ทั้งหมด ข้อมูลโดยใช้ที่เก็บข้อมูลเดียวกัน) แต่แม้ว่าคุณจะขยายใหญ่เกิน 16x ผลลัพธ์ก็ยังดูน่ายอมรับ เส้นตรงที่ยาวจะกลายเป็นบิตเล็กน้อยในที่สุด แต่จะไม่มีสิ่งประดิษฐ์สุ่มแบบ "บล็อก" ทั่วไป
คุณสามารถใช้ตัวแบ่งรูปทรงเรขาคณิตเพื่อสร้างควอร์ตออกจากจุด (ลดแบนด์วิดท์บัส) แต่โดยแท้แล้วกำไรนั้นค่อนข้างน้อย เช่นเดียวกับการแสดงตัวละครแบบอินสแตนซ์ตามที่อธิบายไว้ใน GPG8 ค่าโสหุ้ยของ instancing จะถูกตัดจำหน่ายเฉพาะเมื่อคุณมีข้อความจำนวนมากที่จะวาด กำไรของฉันคือในความคิดของฉันไม่เกี่ยวข้องกับความซับซ้อนที่เพิ่มขึ้นและการไม่สามารถลดระดับได้ นอกจากนี้คุณยังถูก จำกัด ด้วยจำนวนของการลงทะเบียนคงที่หรือคุณต้องอ่านจากวัตถุบัฟเฟอร์พื้นผิวซึ่งไม่เหมาะสำหรับการเชื่อมโยงแคช (และความตั้งใจคือการเพิ่มประสิทธิภาพเริ่มต้นด้วย!)
จุดสุดยอดบัฟเฟอร์แบบธรรมดาที่เรียบง่ายนั้นเร็วมาก (อาจเร็วกว่านี้) หากคุณกำหนดเวลาการอัปโหลดล่วงหน้าเล็กน้อยและจะทำงานบนฮาร์ดแวร์ทุกตัวในช่วง 15 ปีที่ผ่านมา และไม่ จำกัด จำนวนอักขระใด ๆ ในแบบอักษรของคุณหรือจำนวนอักขระที่จะแสดง
หากคุณแน่ใจว่าคุณไม่มีอักขระเกิน 256 ตัวอักษรในแบบอักษรของคุณอาร์เรย์ของพื้นผิวอาจมีค่าควรพิจารณาในการตัดแบนด์วิธบัสในลักษณะเดียวกันกับการสร้างล่ามจากจุดในรูปทรงเรขาคณิต เมื่อใช้พื้นผิวอาร์เรย์พิกัดพื้นผิวของคณะสี่คนทั้งหมดจะมีค่าคงที่s
และt
พิกัดเท่ากันและแตกต่างกันในr
พิกัดซึ่งเท่ากับดัชนีอักขระที่จะแสดงผล
แต่เช่นเดียวกับเทคนิคอื่น ๆ ผลกำไรที่คาดหวังนั้นเป็นเพียงต้นทุนที่ไม่สอดคล้องกับฮาร์ดแวร์รุ่นก่อนหน้า
มีเครื่องมือที่มีประโยชน์โดย Jonathan Dummer สำหรับการสร้างพื้นผิวระยะทาง: หน้าคำอธิบาย
อัปเดต:
เมื่อไม่นานมานี้มีการดึงข้อมูลจุดยอดที่ตั้งโปรแกรมได้ (D. Rákos, "OpenGL Insights", pp. 239) ไม่มีความล่าช้าพิเศษหรือค่าใช้จ่ายเพิ่มเติมที่เกี่ยวข้องกับการดึงข้อมูลจุดสุดยอดทางโปรแกรมจาก shader บน GPU รุ่นใหม่ล่าสุด เมื่อเทียบกับการทำแบบเดียวกันโดยใช้ฟังก์ชั่นคงที่มาตรฐาน
นอกจากนี้ GPU รุ่นล่าสุดยังมีแคช L2 สำหรับใช้งานทั่วไปขนาดที่เหมาะสมมากขึ้น (เช่น 1536kiB บน nvidia Kepler) ดังนั้นหนึ่งอาจคาดหวังว่าปัญหาการเข้าถึงที่ไม่ต่อเนื่องกันเมื่อดึงค่าออฟเซ็ตแบบสุ่มสำหรับมุมสี่มุมจากพื้นผิวบัฟเฟอร์ ปัญหา.
สิ่งนี้ทำให้ความคิดในการดึงข้อมูลคงที่ (เช่นขนาดสี่เหลี่ยม) จากพื้นผิวบัฟเฟอร์น่าดึงดูดยิ่งขึ้น การดำเนินการตามสมมติฐานสามารถลดการถ่ายโอน PCIe และหน่วยความจำเช่นเดียวกับหน่วยความจำ GPU ให้น้อยที่สุดด้วยวิธีการเช่นนี้:
- อัปโหลดเฉพาะดัชนีอักขระ (หนึ่งตัวต่ออักขระที่จะแสดง) เป็นอินพุตเดียวไปยังจุดยอดที่ส่งผ่านดัชนีนี้และ
gl_VertexID
และขยายไปถึง 4 จุดในรูปร่างเรขาคณิตยังคงมีดัชนีอักขระและจุดยอด id (นี่ จะเป็น "gl_primitiveID ให้บริการใน shader ที่" เป็นคุณลักษณะ แต่เพียงผู้เดียวและจับสิ่งนี้ผ่านการตอบรับการแปลง
- สิ่งนี้จะเร็วเพราะมีเพียงสองแอ็ตทริบิวต์เอาต์พุต (คอขวดหลักใน GS) และอยู่ใกล้กับ "no-op" ไม่เช่นนั้นในทั้งสองขั้นตอน
- ผูกพื้นผิวบัฟเฟอร์ที่มีสำหรับตัวละครแต่ละตัวในแบบอักษรตำแหน่งจุดสุดยอดของรูปสี่เหลี่ยมพื้นผิวที่สัมพันธ์กับจุดฐาน ข้อมูลนี้สามารถบีบอัดได้ 4 ตัวเลขต่อหนึ่งสี่เหลี่ยมโดยจัดเก็บเฉพาะออฟเซ็ตของจุดสุดยอดด้านซ้ายล่างและเข้ารหัสความกว้างและความสูงของกล่องที่จัดแนวแกน แบบอักษร 256 ตัวอักษรทั่วไปสามารถประกอบเข้ากับแคช L1 2kiB ได้)
- ตั้งค่าเครื่องแบบสำหรับพื้นฐาน
- ผูกเนื้อบัฟเฟอร์ด้วยการชดเชยแนวนอน เหล่านี้อาจอาจจะได้รับการคำนวณบน GPU แต่มันเป็นเรื่องง่ายและมีประสิทธิภาพมากขึ้นกับชนิดของสิ่งบน CPU ที่เป็นมันคือการดำเนินการตามลำดับอย่างเคร่งครัดและไม่ได้ทั้งหมดที่น่ารำคาญ (คิดว่าการจัดช่องไฟ) นอกจากนี้มันจะต้องผ่านการตอบรับอีกซึ่งจะเป็นจุดซิงค์อีก
- ทำให้ข้อมูลที่สร้างไว้ก่อนหน้านี้จากบัฟเฟอร์ความคิดเห็นเวอร์เท็กซ์ shader ดึงออฟเซ็ตแนวนอนของจุดฐานและออฟเซ็ตของจุดยอดมุมจากวัตถุบัฟเฟอร์ (โดยใช้ id ดั้งเดิมและดัชนีอักขระ) ID จุดยอดดั้งเดิมของจุดยอดที่ส่งมาคือ "รหัสดั้งเดิม" ของเรา (โปรดจำไว้ว่า GS เปลี่ยนจุดยอดให้เป็นสี่คน)
เช่นนี้เราสามารถลดแบนด์วิดท์ที่ต้องการได้ด้วย 75% (ตัดจำหน่าย) แม้ว่ามันจะสามารถสร้างบรรทัดเดียวได้ หากต้องการให้สามารถแสดงหลายบรรทัดในการเรียกแบบดึงครั้งเดียวจะต้องเพิ่มพื้นฐานไปยังพื้นผิวบัฟเฟอร์แทนที่จะใช้เครื่องแบบ (ทำให้แบนด์วิดท์เล็กลง)
อย่างไรก็ตามแม้จะสมมติว่าลดลง 75% - เนื่องจากข้อมูลจุดสุดยอดที่จะแสดงจำนวนข้อความที่ "สมเหตุสมผล" นั้นอยู่ที่ประมาณ 50-100kiB เท่านั้น (ซึ่งเป็นศูนย์จริงสำหรับ GPU หรือ PCIe bus) - ฉันยังสงสัยว่าความซับซ้อนที่เพิ่มขึ้นและการสูญเสียความสามารถในการใช้งานร่วมกันได้นั้นคุ้มค่ากับปัญหา การลดศูนย์ลง 75% ยังคงเป็นศูนย์เท่านั้น ฉันยอมรับว่าไม่ได้ลองวิธีการข้างต้นและจำเป็นต้องมีการวิจัยเพิ่มเติมเพื่อสร้างข้อความรับรองที่มีคุณภาพอย่างแท้จริง แต่ถึงกระนั้นถ้าไม่มีใครสามารถแสดงให้เห็นถึงความแตกต่างของประสิทธิภาพที่น่าทึ่งอย่างแท้จริง (โดยใช้จำนวนข้อความ "ปกติ" ไม่ใช่ตัวอักษรนับพันล้าน!) มุมมองของฉันยังคงอยู่ที่ข้อมูลจุดสุดยอด ได้รับการพิจารณาเป็นส่วนหนึ่งของ "วิธีการแก้ปัญหาที่ทันสมัย" เรียบง่ายและตรงไปตรงมาใช้งานได้และทำงานได้ดี
เมื่ออ้างอิงถึง " OpenGL Insights " ข้างต้นแล้วมันก็คุ้มค่าที่จะชี้ให้เห็นบท"2D Shape Rendering by Distance Fields"โดย Stefan Gustavson ซึ่งจะอธิบายการเรนเดอร์ระยะทางอย่างละเอียด
อัปเดตปี 2559:
ในขณะเดียวกันมีเทคนิคเพิ่มเติมอยู่หลายประการซึ่งมีจุดมุ่งหมายเพื่อลบมุมการปัดเศษของสิ่งประดิษฐ์ซึ่งกลายเป็นสิ่งรบกวนเมื่อกำลังขยายสูง
วิธีการหนึ่งใช้สนามระยะไกลหลอกแทนเขตข้อมูลระยะทาง (ความแตกต่างคือว่าระยะทางเป็นระยะทางที่สั้นที่สุดไม่ได้กับเค้าร่างจริง แต่กับร่างหรือเส้นจินตนาการที่ยื่นออกมาเหนือขอบ) สิ่งนี้ค่อนข้างดีกว่าและทำงานด้วยความเร็วเท่ากัน (shader ที่เหมือนกัน) โดยใช้หน่วยความจำพื้นผิวจำนวนเท่ากัน
อีกวิธีหนึ่งที่ใช้ค่ามัธยฐานของสามในสามช่องทางรายละเอียดพื้นผิวและการดำเนินงานที่มีอยู่ใน GitHub สิ่งนี้มีวัตถุประสงค์เพื่อปรับปรุงและหรือแฮ็กที่ใช้ก่อนหน้านี้เพื่อแก้ไขปัญหา คุณภาพดีเล็กน้อยแทบไม่สังเกตเห็นได้ช้าลง แต่ใช้หน่วยความจำพื้นผิวมากถึงสามเท่า นอกจากนี้เอฟเฟกต์พิเศษ (เช่นเรืองแสง) ก็ยากที่จะทำให้ถูกต้อง
สุดท้ายการจัดเก็บเส้นโค้ง bezier ที่เกิดขึ้นจริงในการสร้างตัวละครและการประเมินพวกเขาในส่วนที่แตกได้กลายเป็นจริงที่มีประสิทธิภาพการทำงานที่ด้อยกว่าเล็กน้อย (แต่ไม่มากว่ามันเป็นปัญหา) และผลลัพธ์ที่น่าทึ่งแม้กำลังขยายสูงสุด
WebGL สาธิตการแสดงผลในรูปแบบ PDF ขนาดใหญ่ที่มีเทคนิคนี้ในเวลาจริงที่มีอยู่ที่นี่