AAA – เทคนิคแอนติเอเลียซิงเชิงวิเคราะห์
(blog.frost.kiwi)- 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คือค่า default15และ29คือ highest quality39คือ 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 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ผมเป็นคนเขียนเอง ถ้ามีคำถามก็ถามมาได้เลย
มีข้ออ้างว่าควรทำแอนติอะไลอะซิงในปริภูมิ 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...
ใน WebGL2 ก็ยังไม่มี ออบเจ็กต์เท็กซ์เจอร์ MSAA มีแค่ MSAA render buffer จึงอ่าน sample แต่ละตัวโดยตรงจาก shader ไม่ได้ ฟีเจอร์นี้มีประโยชน์กับ render pass สำหรับ custom resolve แต่ทำได้เฉพาะใน WebGPU
ดังนั้นตอนนี้ความคิดผมเปลี่ยนจาก “TAA == เบลอ” ไปเป็น “ถ้าใช้ TAA + machine learning อย่างถูกต้อง นี่คือแอนติอะไลอะซิงที่ดีที่สุดเท่าที่เกม 3D ปัจจุบันทำได้” แล้ว อยากรู้ว่าคุณมองเรื่องนี้อย่างไร
[1] https://youtu.be/WG8w9Yg5B3g
ผมเองก็เคยเขียนบล็อกโพสต์ที่อิงกับ visualization แบบเรียลไทม์อยู่สองสามครั้ง ใช้เวลานานมากจริง ๆ แต่ก็คิดว่านั่นเป็นทิศทางที่ถูกต้อง ในยุคที่คอนเทนต์ล้นทะลัก ผมว่าการสร้างคอนเทนต์ให้น้อยลงแต่มี คุณภาพสูง ขึ้น แม้จะใช้เวลามากขึ้น ก็เป็นประโยชน์กับทุกคน
ปัญหารอบ ๆ แอนติอะไลอะซิงใหญ่กว่าตัวแอนติอะไลอะซิงเองเสียอีก ในการตั้งค่าเกม มีตัวย่อหลายแบบให้เลือก แต่แทบไม่อธิบายเลยว่าแต่ละแบบต่างกันอย่างไร และครึ่งหนึ่งในนั้นผมไม่รู้จักเลย
แน่นอนว่าค้นหาเองได้ แต่ถ้าคำนึงถึงความเป็นมิตรต่อผู้ใช้สักหน่อยก็คงดี บทความนี้น่าจะช่วยเป็นแหล่งอ้างอิงต่อไปได้
ในเชิงเมตา ช่วงหลังรู้สึกว่าเห็นบรรยากาศต่อต้านตัวย่อบ่อยขึ้น ผมคิดว่าไม่เคยมีช่วงไหนที่ค้นหาได้ง่ายเท่าตอนนี้แล้ว แน่นอนว่ามีตัวย่อในระดับที่ขัดขวางการเรียนรู้หรือทำหน้าที่เหมือนการกีดกันคนใหม่ ๆ อยู่บ้าง แต่เราต้องตั้งชื่อแนวคิดให้อยู่ในระดับที่ใช้งานได้ถึงจะทำงานกันได้ ดังนั้น ตัวย่อในการตั้งค่ากราฟิก ของเกมจึงถือว่าค่อนข้างสมเหตุสมผล
วิธีวิเคราะห์การเขียนโปรแกรมกราฟิกด้วยตัวอย่าง WebGL นี่อัจฉริยะมาก เป็นไฮเปอร์เท็กซ์ที่ใช้จุดแข็งของสื่อได้อย่างเต็มที่ ทำให้นึกถึงบทความแบบที่เห็นได้ใน https://pudding.cool/ แต่ลงลึกกว่ามาก
ผมใช้ MSAAx4 ใน rendering engine มาพักใหญ่ และช่วงหลังคิดอยู่ว่าจะเปลี่ยนไปใช้การ implement FXAA/TAA ดีไหม แต่ตอนนี้ก็ไม่แน่ใจแล้วว่าจะเปลี่ยนจริงหรือเปล่า ได้เรียนรู้อะไรจากตรงนี้เยอะมาก และคิดว่าน่าจะลองใช้แนวทางเชิงวิเคราะห์กับองค์ประกอบ UI บทความเกี่ยวกับการเขียนโปรแกรมกราฟิกไม่ได้ขึ้น HN บ่อยนัก ถ้าใครสนใจมากขึ้น ขอแนะนำแหล่งรวมบทความวิเคราะห์เฟรมนี้:
https://www.adriancourreges.com/blog/
บทความที่ชอบเป็นพิเศษคือ https://acko.net/blog/how-to-fold-a-julia-fractal/ ผมไม่เคยเห็นแหล่งข้อมูลไหนช่วยให้เข้าใจความสัมพันธ์ระหว่างตรีโกณมิติกับจำนวนเชิงซ้อนได้ดีเท่านี้มาก่อน
เฟรมที่มีวงกลมกับส่วนขยายสื่อสารสารได้ยอดเยี่ยมมาก ทั้งบทความอ่านลื่นมาก
SDF หรือ mSDF ไม่ใช่อนาคต แต่เป็น ของคลาสสิกที่ดีพอแล้ว
ส่วนที่ว่า “ต้องแก้เซกเมนต์เส้นโค้งเบซิเยร์ทุกเส้นในทุกพิกเซล ทำให้ประสิทธิภาพตกลงมาก” กลับมองได้ว่าเป็นอนาคตหรือปัจจุบันเสียมากกว่า เพราะ Slug กับ DirectWrite ก็ใช้งานด้วยประสิทธิภาพที่ดีอยู่แล้ว
https://sluglibrary.com/
https://learn.microsoft.com/en-us/windows/win32/directwrite/...
[0]: https://www.microsoft.com/en-us/research/wp-content/uploads/...
[1]: https://patents.google.com/patent/US20070097123A1/en
ต้องลงแรงเยอะมากเพื่อทำให้ถึงระดับใช้งานจริงในโปรดักชัน การ tessellation แบบอิง Voronoi ในเปเปอร์นั้นแย่มากแบบผิดปกติกับตัวอักษรเอเชียจำนวนมาก
เลื่อนอ่านบทความแล้ว ภาพหน้าจอ NeoTokyo ก็เตะตาทันที ผมวิ่งผ่านโถงทางเดินนั้นมาหลายพันครั้ง เคยเปิดเซิร์ฟเวอร์ mod นั้นอยู่หลายปี และสนุกมากกับชุมชนเล็ก ๆ แต่ฝีมือดีและนิสัยดี
ในฐานะคนที่เคยเขียนทั้งเอนจินเรนเดอร์ 2D และ 3D ขอเสริมบริบทเล็กน้อยว่า ทั้งสองอย่างต่างกันจริง ๆ ไม่ใช่แค่มีมิติเพิ่มขึ้นอีกหนึ่งมิติ แต่เป้าหมาย กรณีใช้งาน และความคาดหวังต่างกันโดยสิ้นเชิง
ดังนั้นแทนที่จะบอกว่า “ทุกอย่างที่พูดถึงตรงนี้ขยายไปใช้กับ 3D ได้ด้วย” ผมอยากบอกว่าบทความนี้ทั้งชิ้นส่วนใหญ่เป็นเรื่องของ การเรนเดอร์ 3D มากกว่าการเรนเดอร์ 2D บทความดี ๆ ที่พูดหัวข้อนี้จากมุมมองการเรนเดอร์ 2D คือ https://ciechanow.ski/alpha-compositing/
เกณฑ์ของ anti-aliasing ที่ไม่มีใครสนใจใน 3D แต่สำคัญมากใน 2D คือ ความถูกต้องและ bias เช่น AAA มี bias สูงจึงไม่แม่นยำ ถ้าวาดรูปร่างเดียวกันในตำแหน่งเดียวกันหลายครั้ง มันจะทึบขึ้นหรือมืดขึ้น ใน MSAA เรื่องเดียวกันนี้ไม่เกิดขึ้น ข้อผิดพลาดถูกจำกัด และไม่มี bias
การวาดเส้นหนาน่าสนใจเป็นพิเศษ เพราะมันยาก [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...
วิธีแก้ที่เสนออาศัย 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