1 คะแนน โดย GN⁺ 2024-11-21 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • jaggies และ pixel crawling ที่เกิดจากการ rasterization จะเห็นได้ชัดกว่าในภาพเคลื่อนไหวมากกว่าภาพนิ่ง และบทความนี้เปรียบเทียบวิธี anti-aliasing หลายแบบด้วยเดโมวงกลมใน WebGL
  • SSAA, MSAA และ FXAA ต่างมีข้อจำกัดคนละแบบ ได้แก่ ต้นทุนของการ downsample, การพึ่งพาฮาร์ดแวร์ และการบิดเบือนรูปทรงจาก post-processing
  • Analytical Anti-Aliasing เมื่อรู้ขอบเขตเชิงคณิตศาสตร์ของรูปทรง จะใช้ signed distance field เพื่อหาระยะถึงขอบ แล้วทำ alpha fade บริเวณขอบกว้าง 1 พิกเซล
  • ขนาดพิกเซลใน 2D สามารถคำนวณได้โดยตรงจากขนาดวัตถุและขนาดเรนเดอร์ แต่ถ้ามี perspective ใน 3D จะต้องใช้ Screen Space derivatives เช่น dFdx, dFdy, fwidth
  • สามารถใช้งานได้แม้บน WebGL 1.0/OpenGLES 2.0 โดยไม่ต้องมีบัฟเฟอร์เพิ่มเติมหรือฮาร์ดแวร์พิเศษ แต่ต้องมี SDF ของรูปทรงทั้งชิ้น และมีข้อจำกัดกับรูปทรงความถี่สูงที่เล็กกว่า 1 พิกเซล

ดู anti-aliasing ผ่านเดโมวงกลม WebGL

  • เป้าหมายของบทความคือการสำรวจเทคนิค Anti-Aliasing หลายแบบเพื่อลด jaggies ที่เกิดใน rasterization แล้วปิดท้ายด้วยการแนะนำการใช้งาน Analytical Anti-Aliasing
  • สิ่งที่นำมาเปรียบเทียบเรียงจาก SSAA, MSAA, FXAA, กลุ่ม MLAA/SMAA ไปจนถึง AAA
  • เดโมวาดวงกลมเคลื่อนที่บน WebGL canvas และตั้งอยู่บนสมมติฐานว่า anti-aliasing ควรทำความเข้าใจผ่าน การเคลื่อนไหว มากกว่าภาพนิ่ง
  • canvas ตัวอย่างเรนเดอร์ที่ความละเอียด native ของอุปกรณ์ และกล่องสีแดงให้มุมมองซูม 4 เท่า
  • สำหรับหน้าจอความละเอียดสูงที่อาจมอง aliasing ได้ไม่ชัด มีตัวเลือกสลับความละเอียดเรนเดอร์ Native, 1/2, 1/4, 1/8 และใช้ integer scaling

ปัญหาที่เกิดจากการเรนเดอร์วงกลมพื้นฐาน

  • วิธีเรนเดอร์วงกลมที่ง่ายที่สุดคือให้ fragment shader ส่งออกสีเมื่อ length(uv) < 1.0 และถ้าไม่ใช่ก็ discard
  • วงกลมไม่ได้ขึ้นกับความละเอียดของ geometry จริง แต่ shader จะตัดสินว่าจุดใดอยู่ด้านในหรือด้านนอกวงกลมบน quad ที่สร้างจาก vertex 4 จุด
  • varying vec2 uv ถูก interpolate ในแต่ละ fragment และให้พิกัดที่มีศูนย์กลางเป็น 0 ช่วงตั้งแต่ -1 ถึง +1
  • วิธีนี้จัดเป็น Alpha testing และค่า length(uv) จะเชื่อมโยงกับ signed distance field ที่ใช้ใน AAA ภายหลัง
  • ที่ความละเอียดต่ำ วงกลมจะดูเป็นบล็อก และเมื่อเคลื่อนไหวจะเห็น pixel crawling ที่แถวพิกเซลโผล่ขึ้นมาแล้วหายไป รวมถึงการส่ายของรูปทรงอย่างชัดเจน
  • ความละเอียด 1/4 และ 1/8 ไม่ได้เป็นเพียงการขยายภาพธรรมดา แต่ยังใช้เป็นกรณีแทนองค์ประกอบใน 3D ที่มีขนาดเล็กหรืออยู่ไกลด้วย

SSAA: downsampling ที่เรียบง่ายแต่แพง

  • SSAA ย่อมาจาก Super Sampling Anti-Aliasing เป็นวิธีวาดที่ความละเอียดสูงกว่าแล้ว downsample ให้เล็กลง
  • การใช้งานในตัวอย่างวาดวงกลมลงใน texture ขนาด (canvas.width / resDiv) * 2, (canvas.height / resDiv) * 2 จากนั้น downsample ไปยัง framebuffer ความละเอียดมาตรฐาน แล้ว blit ขึ้นหน้าจอ
  • การเรนเดอร์ที่ความละเอียด 2 เท่าใช้พิกเซลขาเข้า 4 พิกเซลต่อพิกเซลขาออก 1 พิกเซล จึงทำให้หน่วยความจำและปริมาณการคำนวณเพิ่มเป็น 4 เท่า
  • ในตัวอย่างจริงเกิด anti-aliasing ขึ้น แต่ดูอ่อนกว่าที่คาดไว้
    • ควรมีระดับความโปร่งใส 4 ระดับ แต่จากการสังเกตมีบางช่วงที่เห็นเพียง 2 ระดับ
    • ที่ความละเอียดต่ำ ความโปร่งใส 4 ระดับมักปรากฏใกล้เส้นทแยงมุม 45 องศา
    • ในส่วนล่างที่จัดแนวตามแกน เห็นเพียงทึบสนิทกับโปร่งใส 50% โดยไม่มีระดับ 25% และ 75%
  • สาเหตุคือไม่ได้ sample รูปทรงวงกลมเองที่ความละเอียด 2 เท่า แต่กลับ sample ผลลัพธ์วงกลมที่ถูก quantize ไปแล้วอีกครั้ง
  • ตัวอย่างนี้ใช้ texture ความละเอียด 2x และ linear interpolation ดังนั้นในทางปฏิบัติใช้ VRAM เป็น 5 เท่า
  • SSAA ที่ถูกต้องจะ sample scene หลายครั้งโดยไม่มี buffer กลาง แล้วรวมผลลัพธ์เข้าด้วยกัน จึงต้องบูรณาการกับ rendering pipeline อย่างลึกซึ้ง

MSAA: ข้อดีข้อเสียของการ sample ด้วยฮาร์ดแวร์

  • MSAA เป็นรูปแบบหนึ่งของ supersampling แต่โดยมากใช้กับ silhouette ของโมเดล, geometry ที่ซ้อนทับกัน และขอบ texture เมื่อเปิดใช้ Alpha to Coverage
  • การใช้งานพึ่งพาฮาร์ดแวร์ GPU และผู้ผลิตกราฟิก ระดับการรองรับจึงแตกต่างกันไปตามฮาร์ดแวร์และไดรเวอร์
  • WebGL 1 ไม่รองรับ MSAA ตัวอย่างจึงใช้ WebGL 2 context
  • UI ของตัวอย่างเปรียบเทียบ No MSAA, 2x, 4x, 8x, 16x, 32x, 64x กับความละเอียดเรนเดอร์ Native, 1/2, 1/4, 1/8
  • อ่านจำนวน sample สูงสุดที่รองรับด้วย gl.MAX_SAMPLES และเปิดใช้งานเฉพาะตัวเลือกที่เลือกได้
  • บน GPU มือถือ การเรียก renderbufferStorageMultisample() อาจถูกบังคับเป็น 4x MSAA จริง ๆ
    • Android แม้จะอนุญาตให้เลือก 2x แต่ไดรเวอร์จะบังคับเป็น 4x
    • iPhone และ iPad เมื่อเลือก 2x จะกลายเป็น 4x และค่าความโปร่งใสจะถูกปัดให้ใกล้เคียงกับค่าคูณของ 50% ทำให้เกิดขอบซ้อนในตัวอย่าง
  • MSAA เป็นวิธีฝากให้ฮาร์ดแวร์จัดการ ดังนั้นอุปกรณ์ของผู้ใช้อาจไม่รองรับฟีเจอร์ที่ต้องการ
  • รูปแบบการ sample อาจให้ผลต่างจากที่คาด และระดับความโปร่งใสที่ขอบวงกลมอาจดู “เรียงผิดลำดับ” ได้ ขึ้นอยู่กับฮาร์ดแวร์
  • ในเงื่อนไขบางอย่างยังคงทรงพลัง
    • forward rendering
    • geometry ที่ไม่หนาแน่นเกินไป
    • GPU ที่มี tile-based rendering architecture
  • Rahul Prasad อธิบายว่า MSAA บนมือถือไม่ได้แพงเท่าบนเดสก์ท็อป และใน GPU มือถือบางรุ่น 4x MSAA อาจแทบไม่มีต้นทุน
  • มีการกล่าวถึงเอกสารเพิ่มเติม MSAA color resolve deep-dive ของ KhronosGroup Vulkan-Samples

กระแส post-processing ที่ต่อเนื่องไปสู่ MLAA, SMAA, FXAA

-论文ของ Alexander Reshetov ในปี 2009 เสนอแนวทางค้นหาขอบในภาพ aliasing แบบบล็อก แล้วลดขอบบล็อกด้วยกฎการฟิลเตอร์ตามรูปแบบพิกเซล

  • แนวทางที่อิง morphology นี้พัฒนาไปเป็น MLAA และต่อมาถูกปรับปรุงเป็น SMAA ซึ่งเน้นการกำจัด sub-pixel artifact มากขึ้น
  • ผู้ใช้บางส่วนมองว่ากลุ่ม MLAA/SMAA เบลอเกินไป จึงเกิดคำเปรียบเปรยว่า “vaseline on the screen”
  • post-processing anti-aliasing แสดงให้เห็นกระแสที่ AA ย้ายมาเป็น shader-based เพื่อหลุดจากการรองรับฮาร์ดแวร์ที่ไม่แน่นอน

FXAA 3.11: โครงสร้างและข้อจำกัดของ post-processing AA ที่รวดเร็ว

  • FXAA คืออัลกอริทึม Fast approximate anti-aliasing ของ Timothy Lottes และเป็นวิธีที่ได้รับแรงบันดาลใจจาก MLAA
  • เวอร์ชันสุดท้ายที่เผยแพร่คือ FXAA 3.11 และเดโมอิงจากเวอร์ชันที่ปล่อยเมื่อวันที่ 12 สิงหาคม 2011
  • เดโมเปรียบเทียบฉากวงกลมที่ความละเอียด Native, 1/2, 1/4, 1/8
  • ค่าตั้งต้นใช้ FXAA_PC 1, FXAA_QUALITY_PRESET 12, fxaaQualitySubpix 0.75, fxaaQualityEdgeThreshold 0.166, fxaaQualityEdgeThresholdMin 0.0833
  • FXAA จะ sample luminance ของพิกเซลกลางและพิกเซลบนล่างซ้ายขวาก่อน และถ้า local contrast ต่ำกว่า threshold ก็คืนค่าพิกเซลเดิม
  • หากไม่เข้าเงื่อนไข early exit จะ sample luminance ตามแนวทแยงเพิ่มเติม คำนวณทิศทาง edge แนวนอนและแนวตั้ง จากนั้นค้นหาสองทิศทางเพื่อหาปลายของ edge
  • สุดท้ายจะเลื่อนพิกัดพิกเซลแล้ว sample ด้วย texture2D โดยตาม whitepaper อย่างเป็นทางการแล้วไม่ใช่วิธีที่เพียง blur edge อย่างง่าย ๆ
  • ในเดโมวงกลม ขอบในสภาวะหยุดนิ่งดูเรียบ แต่เมื่อวงกลมเคลื่อนไหว รูปทรงจะบิดเบี้ยว
    • ในส่วนบนและล่างที่จัดแนวตามแกน จะมีส่วนยื่นเล็ก ๆ โผล่ขึ้นมาแล้วหายไป
    • ที่ความละเอียดต่ำ วงกลมจะเสียรูปทรงกลมและสั่นเหมือนกราฟิก PlayStation 1
  • เพราะพิจารณาเพียงบริเวณรอบข้าง 3x3 ต่อหนึ่งพิกเซล จึงไม่สามารถรู้ได้ว่าบริเวณนั้นเป็นส่วนหนึ่งของวงกลมขนาดใหญ่
  • FXAA ถูกสร้างขึ้นเพื่อทำ anti-aliasing ให้ฉากที่ซับซ้อนกว่า และมีการตั้งค่าและ preset หลายแบบ
  • full demo ที่ใช้ฉาก NeoTokyo° คำนวณ luminance channel จาก aliased output แล้วใช้ FXAA พร้อมให้ปรับ preset และ setting ได้ทั้งหมด

อินพุตและเงื่อนไขพารามิเตอร์ของ FXAA

  • เมื่อตั้งค่า FXAA_GREEN_AS_LUMA เป็น 1 จะใช้ช่องสีเขียวแทน luma และในกรณีนี้อินพุต RGB ต้องอยู่ในปริภูมิสีแบบไม่เชิงเส้น
  • RGB อินพุตของ FXAA ต้องเป็น LDR โดยเฉพาะควรใช้ FXAA หลังจาก tonemapping แล้ว
  • หากไม่ใช้ FXAA_GREEN_AS_LUMA ต้องเก็บ luma ใน perceptual space ไว้ในช่อง alpha ก่อนรัน FXAA
  • ต้องคำนวณ luma ให้ถูกต้อง FXAA จึงจะทำงานได้อย่างเหมาะสม
  • FXAA_QUALITY_PRESET เป็นการตั้งค่าที่แลกเปลี่ยนระหว่างประสิทธิภาพกับคุณภาพ
    • 12 คือค่า default
    • 15 และ 29 คือ highest quality
    • 39 คือ EXTREME QUALITY
  • fxaaQualitySubpix ปรับปริมาณการกำจัด sub-pixel aliasing
    • ค่าเริ่มต้นคือ 0.75
    • 1.00 จะนุ่มกว่า ส่วน 0.50 จะคมกว่า แต่กำจัด sub-pixel aliasing ได้น้อยกว่า
    • 0.00 คือสถานะปิด
  • fxaaQualityEdgeThreshold กำหนด local contrast ขั้นต่ำที่จำเป็นต่อการใช้อัลกอริทึม
  • fxaaQualityEdgeThresholdMin ตัดบริเวณมืดออกจากเป้าหมายการประมวลผล
  • FXAA อาจมีต้นทุนด้านประสิทธิภาพต่ำ หากมีไปป์ไลน์ post-processing อยู่แล้วหรือใช้ deferred shading
  • ในกราฟิกบนมือถือ การเข้าถึงหน่วยความจำมีราคาแพง ดังนั้นหากต้องสร้างคอนฟิก render-to-texture ใหม่เพื่อใช้ FXAA ข้อได้เปรียบด้านต้นทุนก็จะลดลง

แก่นของ Analytical Anti-Aliasing

  • Analytical Anti-Aliasing คือวิธีวาดพิกเซลให้อยู่ในรูปที่ผ่านการทำ anti-aliasing แล้ว โดยรู้อยู่แล้วว่ารูปทรงที่ต้องการคืออะไร
  • เมื่อวาดรูปทรง 2D หรือ 3D จะ เฟด ขอบของรูปทรงอย่างแม่นยำเป็นระยะ 1 พิกเซล
  • ตัวอย่างเปรียบเทียบวงกลมที่ความละเอียด Native, 1/2, 1/4 และ 1/8 โดยแสดงให้เห็นการทำ edge smoothing และการรักษารูปทรงแม้ที่ความละเอียดต่ำ
  • circle-analytical.fs คำนวณ signed distance field ของวงกลมด้วย dist = length(uv)
  • เพื่อเฟดพิกเซลใกล้ขอบวงกลมด้วยความกว้าง 1 พิกเซล ใช้ alpha = (1.0 - dist) / pixelSizeAdjusted
  • วิธีนี้ให้ผลลัพธ์ที่เรียบเนียนโดยไม่มี artifact สามารถปรับปริมาณ filtering ได้ และไม่ต้องใช้ buffer เพิ่มหรือข้อกำหนดฮาร์ดแวร์เพิ่มเติม
  • ทำงานได้แม้บน WebGL 1.0 หรือ OpenGLES 2.0 พื้นฐานโดยไม่ต้องใช้ extension
  • การ smoothing 1 พิกเซลให้ความคมชัด แต่ขึ้นอยู่กับการผสมกันของความละเอียดหน้าจอ ขนาด และตำแหน่งของวงกลม ด้านข้างแนว 90 องศาที่จัดแนวกับแกนอาจยังถูกรับรู้ว่าแบนอยู่
  • หากทำ filtering โดยอิงขนาดพิกเซลแนวทแยง √2 px = 1.4142... จะลดความรู้สึกแบนได้ แต่รูปทรงจะพร่ามัวขึ้นเล็กน้อยมาก

ความหมายของ “Analytical” และการใช้งานแบบอิง SDF

  • ในการเขียนโปรแกรมกราฟิก “Analytical” หมายถึงเอฟเฟกต์ที่สร้างด้วยการคำนวณจากนิยามทางคณิตศาสตร์ของ shape ที่ต้องการ โดยรู้โครงสร้างของ shape นั้นล่วงหน้า
  • คำนี้ถูกใช้ใน computer graphics อย่างค่อนข้างยืดหยุ่น และอาจมีหลายความหมายตามบริบท
  • การใช้งานอิงกับ signed distance field และตั้งสมมติฐานว่ารู้ระยะจากทุก point ที่ sampling ไปยัง shape ที่ต้องการ
  • ข้อมูลนี้อาจ bake ลงใน texture เหมือน SDF text rendering หรือในกรณี shape ง่าย ๆ ก็อาจหาแบบ per-pixel จากสูตรคณิตศาสตร์ได้
  • เฟดขอบ shape ออกตาม signed distance และเมื่อกำหนดระยะเฟดเป็นขนาด 1 พิกเซล ก็จะได้ smooth edge
  • คำถามสำคัญของการใช้งานคือ shader รู้ขนาดพิกเซลได้อย่างไร และ blend ตาม distance อย่างไร
  • แนวทางนี้ให้ motion-stable pixel-perfection แต่ไม่สอดคล้องกับ traditional rasterization และต้องมี signed distance field ของทั้ง shape

การคำนวณขนาดพิกเซล: คำนวณล่วงหน้า, dFdx/dFdy, fwidth

  • หากตั้งความกว้างการเฟดขอบเป็นค่าคงที่ เช่น 95% ของรัศมีวงกลม อาจดูดีในบางขนาดและบางความละเอียด แต่เมื่อขนาดเปลี่ยนไปก็อาจนุ่มเกินไปหรือเกิด aliasing
  • ขนาดพิกเซลเป็นหนึ่งในปัญหาที่ Screen Space derivatives ช่วยแก้ได้
  • dFdx, dFdy, fwidth ช่วยหาว่าค่าหนึ่ง ๆ เปลี่ยนแปลงไปเท่าใดในหน่วยพิกเซลของหน้าจอ
  • ในตัวอย่าง หาปริมาณการเปลี่ยนแปลงของระยะด้วย pixelSize = fwidth(dist) หรือ pixelSize = length(vec2(dFdx(dist), dFdy(dist)))
  • Screen Space derivatives สะท้อนการแปลงรวมถึง perspective 3D ได้อย่างถูกต้อง แต่ไม่ได้รวมอยู่ในมาตรฐาน WebGL 1 จึงต้องใช้ extension GL_OES_standard_derivatives หรือ WebGL 2
  • วิธี length() หาความยาวเวกเตอร์ที่ dFdx และ dFdy สร้างขึ้น ส่วน fwidth() ใช้ค่าประมาณ abs(dFdx()) + abs(dFdy())
  • ค่าประมาณของ fwidth() จะถูกสเกลใหญ่เกินไปในทิศทางทแยง ทำให้การเฟดอาจถูกใช้มากกว่าในแนวทแยง
  • ส่วนขยาย Unity Shapes เรียก AAA ที่อิง fwidth() ว่า “Fast Local Anti-Aliasing” และเรียกวิธีที่อิง length() ว่า “Corrected Local Anti-Aliasing”
  • ใน 2D เนื่องจากรู้ขนาดการเรนเดอร์ของ context และขนาดของ quad จึงสามารถคำนวณขนาดพิกเซลโดยตรงสำหรับแต่ละอ็อบเจกต์ได้
  • ตัวอย่างส่งขนาดพิกเซลที่อิงความสูงด้วย gl.uniform1f(pixelSizeCircle, (2.0 / (canvas.height / resDiv))) และวิธีนี้ทำงานได้แม้บนฮาร์ดแวร์เก่าโดยไม่ต้องใช้ WebGL 2 หรือ extension

การเลือก alpha blending และฟังก์ชัน step

  • หลังจากหาความกว้างของการเฟดแล้ว ต้องปรับค่าความทึบ
  • ใน 2D Alpha blending เป็นตัวเลือกที่เรียบง่าย
  • อีกตัวเลือกคือใช้ MSAA ร่วมกับ Alpha to Coverage ซึ่งอาจใช้เมื่อจำเป็นต้องเขียน depth-buffer เพื่อให้ blending ถูกต้องในฉาก 3D
  • alpha ต้องเฟดตามระยะ และโดยทั่วไปใช้ฟังก์ชัน step ที่ interpolate ระหว่าง start กับ end
  • ในการใช้งาน anti-aliasing ด้วย GLSL มักใช้ smoothstep() แต่ในบริบทนี้เป็นฟังก์ชันภายในช่วง 1–2 พิกเซล จึงแทบไม่มีเส้นโค้งให้สังเกตได้
  • หากนำ Hermite interpolation ออกจาก smoothstep() ก็จะกลายเป็น linearstep() ซึ่งเป็นการ interpolate เชิงเส้นที่ถูก clamp
  • ในกรณีที่มีรูปทรงเดียวบน quad หนึ่งอัน ก็สามารถเอา clamp ออกได้ด้วย
  • alpha สุดท้ายสามารถคำนวณด้วยการหารง่าย ๆ เช่น float alpha = (1.0 - dist) / (pixelSize * smoothingAmount);
  • ส่วนที่แพงด้านประสิทธิภาพยังคงเป็นการหารที่ทำทุกพิกเซล ขณะที่ GPU สมัยใหม่สามารถปรับการคูณและการบวกของ Hermite interpolation ให้เหมาะสมด้วย Fused Multiply-Add ได้

ขอบเขตของ quad, MSAA, การชดเชย 0.5 พิกเซล

  • ระหว่าง MSAA + Alpha to Coverage กับ rasterizer มีปฏิสัมพันธ์ที่ปรากฏเฉพาะบนฮาร์ดแวร์บางตัว
  • เมื่อใช้ MSAA + Alpha to Coverage อาจเกิดกรณีที่ด้านหนึ่งของ quad หายไปพอดี 0.5 พิกเซล โดยไม่ขึ้นกับจำนวน sample
  • ตัวอย่างเพิ่มระยะเผื่อ 0.5 พิกเซลเข้าไปใน SDF ในรูปแบบ dist += pixelSizeAdjusted * 0.5 เพื่อรับมือกับเรื่องนี้
  • ใน 2D สามารถทำสิ่งที่คล้ายกับ NV_conservative_raster_dilate ได้โดยตรง
    • ขยาย quad ขึ้น 0.5 พิกเซลใน vertex shader
    • ลด signed distance field ลง 0.5 พิกเซลใน fragment shader
  • เดโม 2D บนหน้านี้ทำงานด้วยวิธีนี้ และ vertex *= size + pixelSize ทำหน้าที่ดังกล่าว
  • ปัญหา gamma และ premultiplied alpha ก็สำคัญใน AA ทุกรูปแบบเช่นกัน แต่ไม่ได้กล่าวถึงเพื่อโฟกัสที่ AAA

รูปทรงหลายแบบและการขยายไปสู่ 3D

  • สามารถวาดรูปทรงหลายแบบภายใน quad เดียว และทำแอนติเอเลียซิงให้แต่ละรูปทรงได้
  • เมื่อมีรูปทรงหลายแบบ ต้องประเมินรูปทรงทั้งสองในทุกพิกเซล แล้วทำ clamp·weight·sum กับผลลัพธ์ จึงจะยังคงแอนติเอเลียซิงไว้ได้แม้บริเวณจุดตัด
  • การลงสีในเอาต์พุตรูปทรงที่ต้องการในครั้งเดียวมีต้นทุนน้อยกว่าการวาด color overlay เป็น pass แยกต่างหาก
  • ตัวอย่าง 3D ใช้กล้องที่เคลื่อนที่และ 2D rounded square ที่อยู่ภายใต้ perspective
  • 3D fragment shader คำนวณ rounded box SDF ด้วย roundedBoxSDF และหาขนาดพิกเซลด้วย length(vec2(dFdx(dist), dFdy(dist)))
  • เมื่อมีการคูณเมทริกซ์กล้องและ perspective การใช้ Screen Space derivatives เพื่อหาขนาดพิกเซลถือว่าเชื่อถือได้
  • ตามทฤษฎีสามารถคูณ inverse perspective matrix กับ fragment coordinates ทีละพิกเซลโดยไม่ใช้ derivatives ได้ แต่มีต้นทุนด้านประสิทธิภาพสูง
  • หากวาง fade ไว้ที่กึ่งกลางขอบเขต จะช่วยลดการบิดเบี้ยวของรูปทรงเมื่อมีขนาดเล็กหรือมี perspective แรงได้ แต่ขอบอาจเลยออกนอก quad จนเกิด hard edge หรือ clipping
  • NVIDIA ได้เปิดตัวส่วนขยาย NV_conservative_raster_dilate ที่ให้พิกเซลเพิ่มเติมบริเวณขอบเขต แต่ไม่สามารถใช้ใน WebGL ได้ และจำกัดอยู่กับฮาร์ดแวร์ NVIDIA

กรณีการใช้งานจริง

  • ส่วนขยาย Unity ของ Freya Holmér ชื่อ Shapes ได้รับการประเมินว่าเป็นการใช้งานแนวทางนี้ที่สมบูรณ์ที่สุดในเชิงฟังก์ชัน
    • ทำแอนติเอเลียซิง SDF ด้วย MSAA หรือ blending แบบ AAA
    • มีฟังก์ชัน motion blur, shape-respecting color gradients และการทำ opacity fade ให้เส้นที่เล็กกว่า 1 พิกเซล
    • เทคนิคสำหรับเส้นที่เล็กกว่า 1 พิกเซลเรียกว่า Line Thinness Fading
  • Valve Software ได้นำ signed distance field rendering มาใช้อย่างกว้างขวางใน Source engine ระหว่างการพัฒนา Orange Box
    • ถูกใช้อย่างโดดเด่นในการสร้างองค์ประกอบ UI ใน HUD ของ Team Fortress 2 ให้เรียบเนียนแต่คมชัด
    • พัฒนา line art shader system ที่ให้ซิลูเอตเรียบเนียนแม้ภาพความละเอียดคงที่ถูกขยายไปยังความละเอียดสูง
    • ยังจัดการ outline และ drop-shadow ได้ และสามารถนำไปใช้กับ world element เช่นป้ายในพื้นที่ 3D ได้ด้วย
  • Valve เผยแพร่การใช้งานนี้ใน论文 SIGGRAPH 2007 และใน论文ยังมีกรณีตัวอย่างจากโลกเกม 3D ด้วย
  • “Shape Decomposition for Multi-channel Distance Fields” ของ Viktor Chlumský เป็นกรณีที่พัฒนาต่อยอดเทคนิคในเชิงอรรถของ论文 Valve
    • งานที่เกี่ยวข้องรวมถึง msdfgen และ msdf-atlas-gen
  • วิธี multi-channel distance field ใช้ RGB และ median term เพื่อสร้างข้อความที่คมชัด และใส่ SDF แบบคลาสสิกไว้ใน alpha channel เพื่อจัดการเอฟเฟกต์อย่าง glow และ drop shadow
  • อักขระ CJK ต้องใช้ texture ที่ใหญ่กว่าเนื่องจากมีรายละเอียดละเอียดมาก และเมื่อย่อ texture ขนาดใหญ่ลงก็อาจเกิด artifact ของตัวเองได้
  • ผู้ใช้ Hacker News ชื่อ aappleby ระบุว่า Google Maps ใช้ AAA ที่อิง capsule shape กับ segment ของถนน
    • aappleby กล่าวว่าเขาเป็นคนเขียนไว้เมื่อประมาณ 10 ปีก่อน
    • เขาอธิบายว่าเมื่อตรวจสอบด้วย Spector.js WebGL debugger พบว่า shader code ของ streets draw call ดูเหมือนจะแสดง blended alpha ที่ขึ้นกับรูปทรง

ข้อจำกัดของวิธี SDF และการอภิปรายเรื่อง TAA

  • Yakov Galka ชี้ว่าแนวทาง SDF ทำการ sample SDF ที่จุดเฉพาะ ดังนั้นหาก SDF มีองค์ประกอบความถี่สูง ก็อาจเกิด aliasing ได้
  • หาก rasterize วงกลมที่เล็กกว่า 1 พิกเซล แนวทางในบทความนี้เพียงอย่างเดียวอาจไม่สามารถกำจัด aliasing ได้ทั้งหมด
  • Yakov Galka กล่าวถึง Wavelet Rasterization ของ J. Manson และ S. Schaefer ว่าเป็นวิธีเชิงวิเคราะห์อย่างแท้จริงในการ rasterize รูปทรง polygonal และ bezier พร้อมแอนติเอเลียซิง
  • หลังบทความเผยแพร่ มีฟีดแบ็กในคอมเมนต์ว่าการวิจารณ์ TAA ค่อนข้างรุนแรง และผู้เขียนยอมรับว่าไม่ได้กล่าวถึงปัญหาที่ TAA พยายามแก้ รวมถึงปัญหาที่แก้ได้ยากด้วยเทคนิคอื่นอย่างเพียงพอ
  • Timothy Lottes มอง TAA ว่าเป็นวิวัฒนาการทางเทคนิคที่ชัดเจน แต่ก็กล่าวว่ามีข้อจำกัดด้าน motion clarity
  • FXAA 4 เป็น 2-frame blender และแตกต่างจาก TXAA โดยพื้นฐาน ส่วน TXAA ไม่มี MLAA และอิง MSAA
  • แนะนำให้ดูงานนำเสนอ GDC ของ Lasse Jon Fuglsang Pedersen ผู้พัฒนา Inside เรื่อง Temporal Reprojection Anti-Aliasing in INSIDE เพื่อทำความเข้าใจ TAA ให้ถูกต้องยิ่งขึ้น
  • AAA ถูกประเมินว่าเป็นเทคนิคที่สามารถวาดรูปทรงหลายขนาดที่ความละเอียดเนทีฟได้อย่างเรียบเนียน คมชัด และ motion-stable

1 ความคิดเห็น

 
GN⁺ 2024-11-21
ความคิดเห็นจาก Hacker News
  • ผมเป็นคนเขียนเอง ถ้ามีคำถามก็ถามมาได้เลย

    • Google Maps ใช้ AAA รูปทรงแคปซูล กับทุกช่วงถนน ผมเป็นคนเขียนไว้เมื่อประมาณ 10 ปีก่อน :D
    • เป็นบทความที่ยอดเยี่ยม ผมไปดูเพราะพยายามทำความเข้าใจการทำแอนติอะไลอะซิงของ ฟอนต์ MSDF แล้วเจอข้ออ้างอยู่สองสามแบบ
      มีข้ออ้างว่าควรทำแอนติอะไลอะซิงในปริภูมิ RGB แบบเชิงเส้น ไม่ใช่ปริภูมิ sRGB [1] [2] แต่ก็มีข้ออ้างว่าเพราะหลายสิบปีที่ผ่านมาไม่ได้ทำแบบนั้น ฟอนต์จึงถูกปรับชดเชยมาเรื่อย ๆ และบางครั้ง sRGB จึงดีกว่า [3] [4] เลยอยากรู้ว่ามีคำแนะนำเกี่ยวกับการทำแอนติอะไลอะซิงในปริภูมิแบบเชิงเส้นเทียบกับ sRGB ไหม
      [1] https://www.puredevsoftware.com/blog/2019/01/22/sub-pixel-ga...
      [2] http://hikogui.org/2022/10/24/the-trouble-with-anti-aliasing...
      [3] https://news.ycombinator.com/item?id=12023985
      [4] http://hikogui.org/2022/10/24/the-trouble-with-anti-aliasing...
    • ขอแก้ไขเล็กน้อยคือ WebGL รองรับ MSAA มาตั้งแต่ WebGL1 แล้ว เพียงแต่ใน WebGL1 ทำได้เฉพาะบนแคนวาส ควบคุมจำนวน sample ไม่ได้ และทำได้แค่ประมาณเปิดหรือปิดแอนติอะไลอะซิงเท่านั้น
      ใน WebGL2 ก็ยังไม่มี ออบเจ็กต์เท็กซ์เจอร์ MSAA มีแค่ MSAA render buffer จึงอ่าน sample แต่ละตัวโดยตรงจาก shader ไม่ได้ ฟีเจอร์นี้มีประโยชน์กับ render pass สำหรับ custom resolve แต่ทำได้เฉพาะใน WebGPU
    • เห็นด้วยว่ากระแสช่วงหลังที่พึ่งพา upscaler มากเกินไปทำให้เกม AAA จำนวนมากได้ผลลัพธ์ที่เบลอและเต็มไปด้วย artifact แต่หลังจากดูบทวิเคราะห์เชิงลึกของ Digital Foundry ชิ้นนี้ [1] แล้ว เหตุผลที่ว่าเฉพาะ เทคโนโลยีอย่าง DLSS เท่านั้นที่ให้ความนิ่งขณะเคลื่อนไหวและความคมชัดในระดับที่ได้ และอาจดีกว่า SSAA ด้วยซ้ำ ก็ค่อนข้างน่าเชื่อ
      ดังนั้นตอนนี้ความคิดผมเปลี่ยนจาก “TAA == เบลอ” ไปเป็น “ถ้าใช้ TAA + machine learning อย่างถูกต้อง นี่คือแอนติอะไลอะซิงที่ดีที่สุดเท่าที่เกม 3D ปัจจุบันทำได้” แล้ว อยากรู้ว่าคุณมองเรื่องนี้อย่างไร
      [1] https://youtu.be/WG8w9Yg5B3g
    • อยากรู้ว่าใช้เวลาเขียนบทความนี้นานแค่ไหน
      ผมเองก็เคยเขียนบล็อกโพสต์ที่อิงกับ visualization แบบเรียลไทม์อยู่สองสามครั้ง ใช้เวลานานมากจริง ๆ แต่ก็คิดว่านั่นเป็นทิศทางที่ถูกต้อง ในยุคที่คอนเทนต์ล้นทะลัก ผมว่าการสร้างคอนเทนต์ให้น้อยลงแต่มี คุณภาพสูง ขึ้น แม้จะใช้เวลามากขึ้น ก็เป็นประโยชน์กับทุกคน
  • ปัญหารอบ ๆ แอนติอะไลอะซิงใหญ่กว่าตัวแอนติอะไลอะซิงเองเสียอีก ในการตั้งค่าเกม มีตัวย่อหลายแบบให้เลือก แต่แทบไม่อธิบายเลยว่าแต่ละแบบต่างกันอย่างไร และครึ่งหนึ่งในนั้นผมไม่รู้จักเลย
    แน่นอนว่าค้นหาเองได้ แต่ถ้าคำนึงถึงความเป็นมิตรต่อผู้ใช้สักหน่อยก็คงดี บทความนี้น่าจะช่วยเป็นแหล่งอ้างอิงต่อไปได้

    • เกม/กราฟิกเป็นสาขาที่มี ศัพท์เฉพาะทาง เยอะจริง ๆ ถ้าไม่อยากเป็นพ่อมด ก็แค่ลองปรับแล้วดูผลลัพธ์ก็พอ ผมชอบแนวทางแบบ Dolphin ที่ใส่ tooltip ละเอียดไว้ใน settings แต่สุดท้ายก็ยังต้องมี tacit knowledge เหลืออยู่บ้างเสมอ
      ในเชิงเมตา ช่วงหลังรู้สึกว่าเห็นบรรยากาศต่อต้านตัวย่อบ่อยขึ้น ผมคิดว่าไม่เคยมีช่วงไหนที่ค้นหาได้ง่ายเท่าตอนนี้แล้ว แน่นอนว่ามีตัวย่อในระดับที่ขัดขวางการเรียนรู้หรือทำหน้าที่เหมือนการกีดกันคนใหม่ ๆ อยู่บ้าง แต่เราต้องตั้งชื่อแนวคิดให้อยู่ในระดับที่ใช้งานได้ถึงจะทำงานกันได้ ดังนั้น ตัวย่อในการตั้งค่ากราฟิก ของเกมจึงถือว่าค่อนข้างสมเหตุสมผล
  • วิธีวิเคราะห์การเขียนโปรแกรมกราฟิกด้วยตัวอย่าง WebGL นี่อัจฉริยะมาก เป็นไฮเปอร์เท็กซ์ที่ใช้จุดแข็งของสื่อได้อย่างเต็มที่ ทำให้นึกถึงบทความแบบที่เห็นได้ใน https://pudding.cool/ แต่ลงลึกกว่ามาก
    ผมใช้ MSAAx4 ใน rendering engine มาพักใหญ่ และช่วงหลังคิดอยู่ว่าจะเปลี่ยนไปใช้การ implement FXAA/TAA ดีไหม แต่ตอนนี้ก็ไม่แน่ใจแล้วว่าจะเปลี่ยนจริงหรือเปล่า ได้เรียนรู้อะไรจากตรงนี้เยอะมาก และคิดว่าน่าจะลองใช้แนวทางเชิงวิเคราะห์กับองค์ประกอบ UI บทความเกี่ยวกับการเขียนโปรแกรมกราฟิกไม่ได้ขึ้น HN บ่อยนัก ถ้าใครสนใจมากขึ้น ขอแนะนำแหล่งรวมบทความวิเคราะห์เฟรมนี้:
    https://www.adriancourreges.com/blog/

    • Steve Wittens ก็เขียนบทความทำนองนี้ที่ผสม WebGL กับภาพประกอบทางคณิตศาสตร์ไว้เยอะที่ https://acko.net/
      บทความที่ชอบเป็นพิเศษคือ https://acko.net/blog/how-to-fold-a-julia-fractal/ ผมไม่เคยเห็นแหล่งข้อมูลไหนช่วยให้เข้าใจความสัมพันธ์ระหว่างตรีโกณมิติกับจำนวนเชิงซ้อนได้ดีเท่านี้มาก่อน
    • ผมเกลียด TAA จริง ๆ โดยเฉพาะที่เฟรมเรตต่ำ ghosting หนักมาก หลายครั้งผมจงใจเปลี่ยนไปใช้อัลกอริทึมที่ช้ากว่าเพื่อหลีกเลี่ยง ghosting
  • เฟรมที่มีวงกลมกับส่วนขยายสื่อสารสารได้ยอดเยี่ยมมาก ทั้งบทความอ่านลื่นมาก

  • SDF หรือ mSDF ไม่ใช่อนาคต แต่เป็น ของคลาสสิกที่ดีพอแล้ว
    ส่วนที่ว่า “ต้องแก้เซกเมนต์เส้นโค้งเบซิเยร์ทุกเส้นในทุกพิกเซล ทำให้ประสิทธิภาพตกลงมาก” กลับมองได้ว่าเป็นอนาคตหรือปัจจุบันเสียมากกว่า เพราะ Slug กับ DirectWrite ก็ใช้งานด้วยประสิทธิภาพที่ดีอยู่แล้ว
    https://sluglibrary.com/
    https://learn.microsoft.com/en-us/windows/win32/directwrite/...

    • ต้องไม่ลืม การเรนเดอร์เส้นโค้งแบบ implicit ด้วย [0] สิทธิบัตรก็กำลังจะหมดอายุเร็ว ๆ นี้ [1]
      [0]: https://www.microsoft.com/en-us/research/wp-content/uploads/...
      [1]: https://patents.google.com/patent/US20070097123A1/en
    • เมื่อราว 20 ปีก่อน เคยเขียน implementation ของ เปเปอร์ Loop/Blinn สำหรับ Microsoft Game Studios เลยสงสัยว่ายังใช้อยู่หรือเปล่า
      ต้องลงแรงเยอะมากเพื่อทำให้ถึงระดับใช้งานจริงในโปรดักชัน การ tessellation แบบอิง Voronoi ในเปเปอร์นั้นแย่มากแบบผิดปกติกับตัวอักษรเอเชียจำนวนมาก
    • ความทรงจำผมอาจผิดไปโดยสิ้นเชิงก็ได้ แต่ algorithm ที่ Slug ใช้นี่ไม่ได้ติด สิทธิบัตร อยู่หรือ?
  • เลื่อนอ่านบทความแล้ว ภาพหน้าจอ NeoTokyo ก็เตะตาทันที ผมวิ่งผ่านโถงทางเดินนั้นมาหลายพันครั้ง เคยเปิดเซิร์ฟเวอร์ mod นั้นอยู่หลายปี และสนุกมากกับชุมชนเล็ก ๆ แต่ฝีมือดีและนิสัยดี

    • ที่น่าทึ่งกว่าคือยังมีคนเล่นกันคึกคักอยู่ ทุกคืนวันศุกร์จะมีเซิร์ฟเวอร์หนึ่งเต็ม และบางครั้งวันเสาร์/อาทิตย์ก็เป็นแบบนั้นด้วย มีฐานแฟนที่ทุ่มเทพอสมควร และผมไม่เคยเห็นความทุ่มเทแบบนี้ในเกมมัลติเพลเยอร์ที่เก่าขนาดนี้มาก่อน
  • ในฐานะคนที่เคยเขียนทั้งเอนจินเรนเดอร์ 2D และ 3D ขอเสริมบริบทเล็กน้อยว่า ทั้งสองอย่างต่างกันจริง ๆ ไม่ใช่แค่มีมิติเพิ่มขึ้นอีกหนึ่งมิติ แต่เป้าหมาย กรณีใช้งาน และความคาดหวังต่างกันโดยสิ้นเชิง
    ดังนั้นแทนที่จะบอกว่า “ทุกอย่างที่พูดถึงตรงนี้ขยายไปใช้กับ 3D ได้ด้วย” ผมอยากบอกว่าบทความนี้ทั้งชิ้นส่วนใหญ่เป็นเรื่องของ การเรนเดอร์ 3D มากกว่าการเรนเดอร์ 2D บทความดี ๆ ที่พูดหัวข้อนี้จากมุมมองการเรนเดอร์ 2D คือ https://ciechanow.ski/alpha-compositing/
    เกณฑ์ของ anti-aliasing ที่ไม่มีใครสนใจใน 3D แต่สำคัญมากใน 2D คือ ความถูกต้องและ bias เช่น AAA มี bias สูงจึงไม่แม่นยำ ถ้าวาดรูปร่างเดียวกันในตำแหน่งเดียวกันหลายครั้ง มันจะทึบขึ้นหรือมืดขึ้น ใน MSAA เรื่องเดียวกันนี้ไม่เกิดขึ้น ข้อผิดพลาดถูกจำกัด และไม่มี bias

    • ตอนกำลังคิดทำ 3D vector renderer บน WebGPU ใน JS/TS เมื่อวานก็เห็นโปรเจกต์ของคุณ [0]
      การวาดเส้นหนาน่าสนใจเป็นพิเศษ เพราะมันยาก [1] ช่วงหลังยังได้เห็นอันนี้ [2] ด้วย และเริ่มสงสัยว่าจะสามารถแปลงรูปทรงทั้งหมดเป็นเซกเมนต์เส้นโค้งเบซิเยร์กำลังสองแล้วใช้เทคนิคนั้นได้ไหม อยากรู้ว่าคุณมองว่าเป็นแนวทางที่น่าตามต่อหรือเปล่า
      [0] https://github.com/Lichtso/contrast_renderer
      [1] https://mattdesl.svbtle.com/drawing-lines-is-hard
      [2] https://scribe.rip/@evanwallace/easy-scalable-text-rendering...
    • คงยากที่จะบอกว่าบทความนี้ generalize ไปใช้กับ 3D ได้ตรง ๆ
      วิธีแก้ที่เสนออาศัย signed distance field แต่กลับข้ามส่วนสำคัญอย่าง “ระยะห่างถึงอะไร?” ไปแบบคร่าว ๆ ใน 2D เรื่องนี้ชัดเจน เพราะวัดระยะถึงขอบเขตระหว่างวัตถุกับพื้นหลัง หรือก็คือ silhouette
      ใน 3D เรื่องซับซ้อนขึ้น เพราะเมื่อวัตถุหมุนก็อาจเกิดการบังตัวเอง จะวัด SDF โดยอ้างอิงจากอะไร? silhouette แบบ 2D projection ของวัตถุ 3D เปลี่ยนอยู่ตลอด และไม่สามารถคำนวณล่วงหน้าแบบง่าย ๆ ได้
  • ดีใจที่เห็นลิงก์ Captain Disillusion ผมไม่เคยรู้จักเขามาก่อน แต่งานของเขาสุดยอดมาก ลิงก์ตรงสำหรับคนที่สนใจ visual effects: https://www.youtube.com/@CaptainDisillusion

  • บทความจัดโครงสร้างได้ดี แต่ผมคิดว่า ส่วนที่โจมตี TAA อาจทำให้สับสนได้ SDF anti-aliasing ไม่ใช่ทางเลือกแทน TAA ไม่ว่าในแง่ใด
    TAA จัดการ aliasing ได้ทุกชนิด แต่ในที่นี้พูดถึงแค่ edge aliasing เท่านั้น เกมสมัยใหม่จำนวนมากใช้วิธีแบบ Monte Carlo กับ indirect lighting และเอฟเฟกต์อื่น ๆ ซึ่งโดยข้อเท็จจริงแล้วจำเป็นต้องใช้ TAA

  • ส่วนที่ว่า “ชิปมือถือรองรับ MSAAx4 พอดี และสถานการณ์ก็แปลก บน Android เลือก 2x ได้ แต่ไดรเวอร์ก็บังคับเป็น 4x อยู่ดี” นั้นผมค่อนข้างสงสัย
    บนโทรศัพท์ Android ของผม เห็นความต่างระหว่าง 2x กับ 4x ชัดเจน แต่ไม่ได้ดู “มน” แบบฝั่ง iPhone