AAA – Kỹ thuật khử răng cưa phân tích
(blog.frost.kiwi)- Jaggies và pixel crawling phát sinh từ quá trình rasterization dễ lộ rõ hơn khi có chuyển động so với ảnh tĩnh; bài viết dùng demo hình tròn trên WebGL để so sánh nhiều phương pháp anti-aliasing
- SSAA, MSAA và FXAA mỗi phương pháp đều có những ràng buộc khác nhau: chi phí downsample, phụ thuộc phần cứng và méo hình do hậu xử lý
- Analytical Anti-Aliasing khi biết biên toán học của hình sẽ dùng signed distance field để tính khoảng cách tới biên, rồi làm alpha fade vùng mép với độ rộng 1 pixel
- Kích thước pixel trong 2D có thể tính trực tiếp từ kích thước đối tượng và kích thước render, còn nếu có phối cảnh 3D thì cần Screen Space derivatives như
dFdx,dFdy,fwidth - Có thể triển khai ngay cả trên WebGL 1.0/OpenGLES 2.0 mà không cần buffer bổ sung hay phần cứng đặc biệt, nhưng cần SDF của toàn bộ hình và có giới hạn với các dạng tần số cao nhỏ hơn 1 pixel
Anti-aliasing qua demo hình tròn WebGL
- Mục tiêu của bài là xem qua nhiều kỹ thuật Anti-Aliasing để giảm jaggies xuất hiện trong rasterization, rồi cuối cùng giới thiệu cách triển khai Analytical Anti-Aliasing
- Các phương pháp được đem ra so sánh lần lượt là SSAA, MSAA, FXAA, dòng MLAA/SMAA và AAA
- Demo vẽ một hình tròn chuyển động trên canvas WebGL, được xây dựng với tiền đề rằng anti-aliasing cần được hiểu trong chuyển động hơn là chỉ qua ảnh tĩnh
- Canvas ví dụ render ở độ phân giải gốc của thiết bị, và khung màu đỏ cung cấp góc nhìn phóng đại 4 lần
- Để hỗ trợ các màn hình độ phân giải cao nơi aliasing khó thấy rõ, demo cho phép chuyển giữa các độ phân giải render Native, 1/2, 1/4, 1/8 và dùng integer scaling
Các vấn đề do cách render hình tròn cơ bản tạo ra
- Cách render hình tròn đơn giản nhất là trong fragment shader, nếu
length(uv) < 1.0thì xuất màu, nếu không thìdiscard - Hình tròn không phụ thuộc vào độ phân giải geometry thực tế, mà shader quyết định bên trong hay bên ngoài hình tròn trên một quad tạo từ 4 vertex
varying vec2 uvđược nội suy cho mỗi fragment, cung cấp tọa độ có tâm tại 0 và phạm vi từ -1 đến +1- Cách này tương ứng với Alpha testing, và giá trị
length(uv)cũng liên hệ với signed distance field sẽ được dùng sau này trong AAA - Ở độ phân giải thấp, hình tròn trông bị blocky; khi chuyển động, hiện tượng pixel crawling và wobble với các hàng pixel xuất hiện rồi biến mất lộ ra rất rõ
- Độ phân giải 1/4 và 1/8 không chỉ là phóng to đơn giản mà còn đại diện cho trường hợp các phần tử trong 3D nhỏ hoặc ở xa
SSAA: đơn giản nhưng tốn kém vì downsampling
- SSAA là viết tắt của Super Sampling Anti-Aliasing, tức render ở độ phân giải lớn hơn rồi downsample xuống nhỏ hơn
- Cách triển khai trong ví dụ là vẽ hình tròn vào texture kích thước
(canvas.width / resDiv) * 2,(canvas.height / resDiv) * 2, sau đó downsample sang framebuffer độ phân giải chuẩn rồi blit ra màn hình - Render ở độ phân giải gấp 2 dùng 4 pixel đầu vào cho mỗi 1 pixel đầu ra, nên bộ nhớ và lượng tính toán tăng gấp 4
- Trong ví dụ thực tế, anti-aliasing có xảy ra nhưng yếu hơn kỳ vọng
- Lẽ ra phải có 4 mức độ trong suốt, nhưng quan sát thấy có đoạn chỉ hiện 2 mức
- Ở độ phân giải thấp, 4 mức trong suốt chủ yếu xuất hiện gần các đường chéo 45 độ
- Ở phần đáy thẳng hàng theo trục chỉ thấy hoàn toàn đục và 50% trong suốt, thiếu các mức 25% và 75%
- Nguyên nhân là hình tròn không được lấy mẫu ở chính độ phân giải gấp đôi, mà kết quả hình tròn đã bị lượng tử hóa lại tiếp tục bị lấy mẫu lần nữa
- Cách triển khai ví dụ dùng texture độ phân giải 2x và linear interpolation nên thực tế tiêu tốn VRAM gấp 5 lần
- SSAA đúng nghĩa là lấy mẫu scene nhiều lần rồi gộp kết quả mà không cần buffer trung gian, nên đòi hỏi tích hợp sâu với pipeline render
MSAA: ưu và nhược điểm của lấy mẫu dựa trên phần cứng
- MSAA là một dạng supersampling, nhưng chủ yếu áp dụng cho silhouette của mô hình, geometry chồng lấp và mép texture khi bật Alpha to Coverage
- Việc triển khai phụ thuộc vào phần cứng GPU và nhà cung cấp đồ họa, mức hỗ trợ thay đổi theo phần cứng và driver
- WebGL 1 không hỗ trợ MSAA nên ví dụ dùng context WebGL 2
- Giao diện ví dụ cho phép so sánh No MSAA, 2x, 4x, 8x, 16x, 32x, 64x cùng các độ phân giải render Native, 1/2, 1/4, 1/8
- Dùng
gl.MAX_SAMPLESđể đọc số lượng sample tối đa được hỗ trợ và chỉ bật những tùy chọn có thể chọn - Trên GPU di động, lời gọi
renderbufferStorageMultisample()thực tế có thể bị ép thành 4x MSAA- Android dù cho phép chọn 2x thì driver vẫn ép lên 4x
- iPhone và iPad khi chọn 2x sẽ thành 4x, và độ trong suốt bị làm tròn về các giá trị gần bội số 50%, tạo ra viền kép trong ví dụ
- MSAA giao việc này cho phần cứng nên thiết bị của người dùng có thể không hỗ trợ tính năng cần thiết
- Mẫu lấy sample cũng có thể tạo ra kết quả khác mong đợi, và tùy phần cứng mà các mức trong suốt ở mép hình tròn có thể trông như xuất hiện theo “thứ tự sai”
- Trong một số điều kiện nhất định, nó vẫn rất mạnh
- forward rendering
- geometry không quá dày đặc
- GPU có tile-based rendering architecture
- Rahul Prasad giải thích rằng trên di động, MSAA không đắt như trên desktop, và trên một số GPU di động thì 4x MSAA có thể là miễn phí
- Tài liệu bổ sung được nhắc đến là MSAA color resolve deep-dive từ KhronosGroup Vulkan-Samples
Luồng hậu xử lý dẫn tới MLAA, SMAA và FXAA
- Bài báo năm 2009 của Alexander Reshetov đưa ra cách tiếp cận tìm các cạnh trong ảnh aliasing dạng blocky, rồi dùng các quy tắc lọc theo hình dạng pixel để giảm mép răng cưa kiểu khối
- Cách tiếp cận dựa trên morphology này dẫn tới MLAA, sau đó được cải tiến thành SMAA với trọng tâm lớn hơn vào việc loại bỏ artifact ở mức sub-pixel
- Một số người dùng cho rằng dòng MLAA/SMAA quá mờ, từ đó xuất hiện cách ví von “vaseline on the screen”
- Anti-aliasing hậu xử lý cho thấy xu hướng AA chuyển sang nền tảng shader để thoát khỏi sự hỗ trợ phần cứng thiếu ổn định
FXAA 3.11: cấu trúc và giới hạn của AA hậu xử lý tốc độ cao
- FXAA là thuật toán Fast approximate anti-aliasing của Timothy Lottes, lấy cảm hứng từ MLAA
- Phiên bản cuối cùng được công bố là FXAA 3.11, và demo dựa trên bản phát hành ngày 12 tháng 8 năm 2011
- Demo so sánh cảnh hình tròn ở các độ phân giải Native, 1/2, 1/4, 1/8
- Thiết lập mặc định dùng
FXAA_PC 1,FXAA_QUALITY_PRESET 12,fxaaQualitySubpix 0.75,fxaaQualityEdgeThreshold 0.166,fxaaQualityEdgeThresholdMin 0.0833 - FXAA trước tiên lấy mẫu độ chói của pixel trung tâm và bốn hướng trên dưới trái phải; nếu local contrast thấp hơn ngưỡng thì trả về pixel gốc
- Nếu không early exit, nó tiếp tục lấy mẫu độ chói theo đường chéo, tính hướng cạnh ngang/dọc, rồi dò theo hai phía để tìm điểm kết thúc của cạnh
- Cuối cùng nó dịch tọa độ pixel và lấy mẫu bằng
texture2D; theo whitepaper chính thức thì đây không đơn thuần là làm mờ cạnh - Trong demo hình tròn, mép hình ở trạng thái tĩnh trông mượt hơn, nhưng khi hình tròn chuyển động thì hình dạng bị méo
- Ở phần trên và dưới thẳng hàng theo trục, các chỗ lồi nhỏ xuất hiện rồi biến mất
- Ở độ phân giải thấp, hình tròn mất dáng tròn và rung lắc như đồ họa PlayStation 1
- Vì mỗi pixel chỉ xét vùng lân cận 3x3 nên thuật toán không thể biết vùng đó thực ra là một phần của hình tròn lớn
- FXAA được tạo ra để anti-alias cho các cảnh phức tạp hơn và cung cấp nhiều thiết lập cùng preset
- Full demo dùng cảnh NeoTokyo° tính luminance channel từ đầu ra bị aliasing rồi áp dụng FXAA, đồng thời cho phép điều chỉnh mọi preset và setting
Điều kiện đầu vào và tham số của FXAA
- Nếu đặt
FXAA_GREEN_AS_LUMAthành 1 thì sẽ dùng kênh xanh lá thay cho luma, và khi đó đầu vào RGB phải ở không gian màu phi tuyến - RGB đầu vào của FXAA phải là LDR, cụ thể là cần áp dụng FXAA sau tonemapping
- Nếu không dùng
FXAA_GREEN_AS_LUMA, cần lưu luma trong perceptual space vào kênh alpha trước khi chạy FXAA - Cần tính luma chính xác thì FXAA mới hoạt động đúng
FXAA_QUALITY_PRESETlà thiết lập đánh đổi giữa hiệu năng và chất lượng12là mặc định15và29là chất lượng cao nhất39là EXTREME QUALITY
fxaaQualitySubpixđiều chỉnh mức loại bỏ sub-pixel aliasing- Giá trị mặc định là
0.75 1.00mượt hơn, còn0.50sắc nét hơn nhưng loại bỏ sub-pixel aliasing ít hơn0.00là trạng thái tắt
- Giá trị mặc định là
fxaaQualityEdgeThresholdxác định độ tương phản cục bộ tối thiểu cần có để áp dụng thuật toánfxaaQualityEdgeThresholdMinloại các vùng tối khỏi đối tượng xử lý- FXAA có thể có chi phí hiệu năng thấp nếu đã có pipeline hậu xử lý hoặc đang dùng deferred shading
- Trong đồ họa di động, truy cập bộ nhớ có chi phí cao, nên nếu phải tạo mới cấu hình render-to-texture chỉ để dùng FXAA thì lợi thế về chi phí sẽ giảm đi
Cốt lõi của Analytical Anti-Aliasing
- Analytical Anti-Aliasing là cách vẽ pixel ở trạng thái đã được khử răng cưa sẵn khi biết trước hình dạng cần thiết
- Khi vẽ hình 2D hoặc 3D, biên của hình được fade chính xác 1 pixel
- Ví dụ so sánh hình tròn ở độ phân giải Native, 1/2, 1/4, 1/8 và cho thấy edge smoothing cùng khả năng giữ nguyên hình dạng ngay cả ở độ phân giải thấp
circle-analytical.fstính signed distance field của hình tròn bằngdist = length(uv)- Để fade các pixel gần biên hình tròn với độ rộng 1 pixel, dùng
alpha = (1.0 - dist) / pixelSizeAdjusted - Cách này mượt mà không tạo artifact, có thể điều chỉnh lượng filtering, và không cần buffer bổ sung hay yêu cầu phần cứng bổ sung
- Chạy được cả trên WebGL 1.0 hoặc OpenGLES 2.0 cơ bản mà không cần extension
- Smoothing 1 pixel cho hình ảnh sắc nét, nhưng tùy theo tổ hợp độ phân giải màn hình, kích thước và vị trí của hình tròn, các mặt 90 độ thẳng trục vẫn có thể bị cảm nhận là phẳng
- Nếu filtering theo kích thước pixel đường chéo
√2 px = 1.4142...thì có thể giảm cảm giác phẳng đó, nhưng hình sẽ mờ hơn một chút
Ý nghĩa của “Analytical” và triển khai dựa trên SDF
- Trong lập trình đồ họa, “Analytical” chỉ hiệu ứng được tạo ra bằng cách biết trước cấu trúc của shape dự định và tính toán dựa trên định nghĩa toán học của nó
- Thuật ngữ này được dùng khá lỏng trong computer graphics và tùy ngữ cảnh mà có thể mang nhiều nghĩa khác nhau
- Việc triển khai dựa trên signed distance field và giả định rằng ở mọi point được lấy mẫu đều biết khoảng cách tới shape mong muốn
- Thông tin này có thể được bake vào texture như trong SDF text rendering, hoặc với các shape đơn giản thì có thể suy ra theo từng pixel bằng công thức toán học
- Tùy theo signed distance mà fade out phần viền của shape, và nếu đặt khoảng fade bằng 1 pixel thì sẽ thu được edge mượt
- Câu hỏi triển khai cốt lõi là shader biết kích thước pixel bằng cách nào, và blend dựa trên distance như thế nào
- Cách tiếp cận này mang lại motion-stable pixel-perfection nhưng không phù hợp với rasterization truyền thống, đồng thời cần signed distance field cho toàn bộ shape
Tính kích thước pixel: tính trước, dFdx/dFdy, fwidth
- Nếu đặt độ rộng fade ở biên là một giá trị cố định như 95% bán kính hình tròn thì có thể trông đẹp ở một kích thước và độ phân giải nhất định, nhưng khi kích thước thay đổi sẽ trở nên quá mượt hoặc xuất hiện aliasing
- Kích thước pixel là một trong những vấn đề mà Screen Space derivatives giải quyết
dFdx,dFdy,fwidthcho phép xác định một giá trị thay đổi bao nhiêu theo đơn vị pixel trên màn hình- Trong ví dụ, độ biến thiên khoảng cách được tính bằng
pixelSize = fwidth(dist)hoặcpixelSize = length(vec2(dFdx(dist), dFdy(dist))) - Screen Space derivatives phản ánh đúng cả các phép biến đổi có phối cảnh 3D, nhưng không nằm trong chuẩn WebGL 1 nên cần extension
GL_OES_standard_derivativeshoặc WebGL 2 - Cách
length()lấy độ dài vector tạo bởi dFdx và dFdy, cònfwidth()dùng giá trị gần đúngabs(dFdx()) + abs(dFdy()) - Giá trị gần đúng của
fwidth()có thể bị scale quá lớn ở hướng chéo, khiến fade được áp dụng nhiều hơn theo đường chéo - Extension Unity Shapes gọi AAA dựa trên
fwidth()là “Fast Local Anti-Aliasing”, còn cách dựa trênlength()là “Corrected Local Anti-Aliasing” - Trong 2D, do biết kích thước render của context và kích thước quad nên có thể tự tính trực tiếp kích thước pixel cho từng object
- Ví dụ truyền kích thước pixel dựa trên chiều cao bằng
gl.uniform1f(pixelSizeCircle, (2.0 / (canvas.height / resDiv))), và cách này hoạt động trên cả phần cứng cũ mà không cần WebGL 2 hay extension
Alpha blending và lựa chọn hàm step
- Sau khi xác định được độ rộng fade, bước tiếp theo là điều chỉnh độ đục
- Trong 2D, Alpha blending là lựa chọn đơn giản
- Một lựa chọn khác là dùng MSAA cùng Alpha to Coverage, có thể được dùng khi cần ghi depth-buffer để blend đúng trong cảnh 3D
- Alpha cần được fade dựa trên khoảng cách, và thông thường sẽ dùng một hàm step để nội suy giữa điểm bắt đầu và kết thúc
- Trong các triển khai anti-aliasing bằng GLSL,
smoothstep()thường được dùng, nhưng trong ngữ cảnh này nó là một hàm trong phạm vi 1~2 pixel nên hầu như không có đường cong nào đủ rõ để quan sát - Nếu bỏ Hermite interpolation khỏi
smoothstep()thì sẽ thànhlinearstep(), tức nội suy tuyến tính có clamp - Nếu trên một quad chỉ có một shape thì thậm chí có thể bỏ cả clamp
- Alpha cuối cùng có thể được tính bằng phép chia đơn giản như
float alpha = (1.0 - dist) / (pixelSize * smoothingAmount); - Phần vẫn tốn kém về hiệu năng là phép chia thực hiện trên từng pixel, còn GPU hiện đại có thể tối ưu các phép nhân và cộng của Hermite interpolation bằng Fused Multiply-Add
Biên quad, MSAA, hiệu chỉnh 0.5 pixel
- Có một số tương tác giữa MSAA + Alpha to Coverage và rasterizer chỉ xuất hiện trên một số phần cứng nhất định
- Khi dùng MSAA + Alpha to Coverage, có thể xảy ra trường hợp đúng 0.5 pixel bị mất ở một phía của quad bất kể số lượng sample
- Để xử lý việc này, ví dụ cộng thêm khoảng đệm 0.5 pixel vào SDF dưới dạng
dist += pixelSizeAdjusted * 0.5 - Trong 2D, có thể tự triển khai cách xử lý tương tự
NV_conservative_raster_dilate- Trong vertex shader, tăng quad thêm 0.5 pixel
- Trong fragment shader, giảm signed distance field đi 0.5 pixel
- Các demo 2D trên trang hoạt động theo cách này, và
vertex *= size + pixelSizeđảm nhiệm vai trò đó - Các vấn đề về gamma và premultiplied alpha cũng quan trọng với mọi dạng AA, nhưng không được đề cập ở đây để tập trung vào AAA
Nhiều hình dạng và mở rộng sang 3D
- Có thể vẽ nhiều hình trong một quad và khử răng cưa cho từng hình
- Khi có nhiều hình, cần đánh giá cả hai hình trên từng pixel rồi clamp·weight·sum kết quả thì mới giữ được khử răng cưa cả ở điểm giao nhau
- So với việc vẽ color overlay bằng một pass riêng, tô màu ngay trong lần xuất hình dạng cần thiết sẽ có chi phí thấp hơn
- Ví dụ 3D sử dụng một rounded square 2D đặt trong camera chuyển động và phối cảnh
- Fragment shader 3D tính rounded box SDF bằng
roundedBoxSDF, rồi lấy kích thước pixel bằnglength(vec2(dFdx(dist), dFdy(dist))) - Khi có phép nhân ma trận camera và phối cảnh, dùng Screen Space derivatives để lấy kích thước pixel là cách đáng tin cậy
- Về mặt lý thuyết, có thể nhân tọa độ fragment với ma trận nghịch đảo phối cảnh trên từng pixel mà không cần derivatives, nhưng chi phí hiệu năng lớn
- Nếu đặt fade ở giữa biên, có thể giảm biến dạng hình khi kích thước nhỏ hoặc phối cảnh mạnh, nhưng mép có thể vượt ra ngoài quad và tạo hard edge hoặc clipping
- NVIDIA đã giới thiệu tiện ích mở rộng
NV_conservative_raster_dilateđể cung cấp thêm pixel ở biên, nhưng không dùng được trên WebGL và bị giới hạn ở phần cứng NVIDIA
Các trường hợp triển khai thực tế
- Tiện ích mở rộng Unity Shapes của Freya Holmér được xem là một trong những triển khai hoàn thiện nhất về mặt chức năng của cách tiếp cận này
- Khử răng cưa SDF bằng MSAA hoặc blend theo cách AAA
- Bao gồm motion blur, color gradient bám theo hình dạng, và khả năng làm mờ opacity cho các đường mảnh dưới 1 pixel
- Kỹ thuật cho các đường dưới 1 pixel được gọi là Line Thinness Fading
- Valve Software đã đưa signed distance field rendering vào Source engine trên diện rộng trong quá trình phát triển Orange Box
- Nó được dùng nổi bật trong HUD của Team Fortress 2 để tạo ra các phần tử UI mượt nhưng vẫn sắc nét
- Họ phát triển một line art shader system cho phép hình ảnh độ phân giải cố định khi phóng lớn lên độ phân giải cao vẫn giữ được silhouette mượt
- Hệ thống cũng xử lý outline và drop-shadow, đồng thời có thể áp dụng cho các world element như bảng hiệu trong không gian 3D
- Valve đã công bố triển khai này trong bài báo SIGGRAPH 2007, và bài báo cũng bao gồm các trường hợp trong thế giới game 3D
- “Shape Decomposition for Multi-channel Distance Fields” của Viktor Chlumský là một ví dụ phát triển thêm kỹ thuật trong phần chú thích của bài báo Valve
- Các công trình liên quan gồm
msdfgenvàmsdf-atlas-gen
- Các công trình liên quan gồm
- Cách làm multi-channel distance field dùng RGB và median term để tạo văn bản sắc nét, còn alpha channel chứa SDF cổ điển để xử lý các hiệu ứng như glow và drop shadow
- Ký tự CJK cần texture lớn hơn do chi tiết nhỏ, và khi thu nhỏ texture lớn lại có thể phát sinh artifact riêng
- Người dùng Hacker News aappleby cho biết Google Maps dùng AAA dựa trên capsule shape cho các đoạn đường
- aappleby nói rằng khoảng 10 năm trước chính anh đã viết nó
- Anh giải thích rằng khi kiểm tra bằng Spector.js WebGL debugger, shader code của draw call cho streets dường như thể hiện blended alpha phụ thuộc vào hình dạng
Giới hạn của cách làm SDF và thảo luận về TAA
- Yakov Galka chỉ ra rằng cách tiếp cận SDF lấy mẫu SDF tại một số điểm nhất định, nên nếu SDF có thành phần tần số cao thì vẫn có thể sinh aliasing
- Khi rasterize một hình tròn nhỏ hơn 1 pixel, chỉ riêng cách tiếp cận trong bài này có thể không loại bỏ hoàn toàn aliasing
- Yakov Galka nhắc đến Wavelet Rasterization của J. Manson và S. Schaefer như một phương pháp phân tích thực sự để anti-alias rồi rasterize các hình polygonal và bezier
- Sau khi bài viết được đăng, phần bình luận có phản hồi rằng lời chỉ trích TAA khá mạnh, và tác giả thừa nhận đã chưa đề cập đầy đủ đến những vấn đề TAA đang cố giải quyết cũng như những vấn đề khó giải quyết bằng kỹ thuật khác
- Timothy Lottes xem TAA là một bước tiến kỹ thuật rõ ràng, nhưng cũng nói rằng nó có giới hạn về motion clarity
- FXAA 4 là bộ trộn 2 frame và về cơ bản khác với TXAA; TXAA không có MLAA và dựa trên MSAA
- Tài liệu được khuyến nghị để hiểu đúng hơn về TAA là bài nói chuyện GDC Temporal Reprojection Anti-Aliasing in INSIDE của nhà phát triển INSIDE, Lasse Jon Fuglsang Pedersen
- AAA được đánh giá là một kỹ thuật có thể vẽ các hình ở nhiều kích thước tại độ phân giải gốc theo cách mượt, sắc nét và ổn định khi chuyển động
1 bình luận
Các ý kiến trên Hacker News
Tôi là tác giả bài viết, nếu có câu hỏi thì tôi sẽ trả lời
Có lập luận rằng anti-aliasing nên được thực hiện trong không gian RGB tuyến tính chứ không phải không gian sRGB [1] [2], nhưng cũng có lập luận rằng vì suốt nhiều thập kỷ người ta không làm vậy nên font đã được hiệu chỉnh theo cách đó, khiến đôi khi sRGB lại tốt hơn [3] [4]. Tôi muốn hỏi có lời khuyên nào về anti-aliasing trong không gian tuyến tính vs sRGB không
[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 hiện vẫn chưa có đối tượng texture MSAA, chỉ hỗ trợ render buffer MSAA, nên không thể đọc trực tiếp từng sample trong shader. Đây là tính năng hữu ích cho các render pass resolve tùy chỉnh, nhưng chỉ WebGPU mới làm được
Vì vậy giờ tôi không còn nghĩ “TAA == mờ” nữa, mà nghiêng sang “nếu dùng TAA + machine learning đúng cách thì đó là anti-aliasing tốt nhất hiện có cho game 3D”. Không biết bạn nhìn nhận thế nào
[1] https://youtu.be/WG8w9Yg5B3g
Tôi cũng từng viết vài bài blog dựa trên trực quan hóa thời gian thực và nó cực kỳ tốn thời gian. Dù vậy tôi nghĩ đó là hướng đi đúng. Trong thời đại nội dung tràn ngập, dù mất nhiều thời gian hơn, việc tạo ra ít nội dung hơn nhưng chất lượng cao sẽ có lợi cho tất cả mọi người
Vấn đề xung quanh anti-aliasing còn lớn hơn bản thân anti-aliasing. Trong phần cài đặt game, có nhiều chữ viết tắt để lựa chọn nhưng hầu như không giải thích chúng khác nhau thế nào, và một nửa trong số đó là những thứ tôi hoàn toàn không biết
Tất nhiên có thể tra cứu, nhưng sẽ tốt hơn nếu chú ý thêm một chút đến tính thân thiện với người dùng. Bài viết này có vẻ sẽ hữu ích để tham khảo về sau
Nhìn ở tầng meta, gần đây tôi có cảm giác thường thấy thái độ phản đối chữ viết tắt. Tôi nghĩ chưa bao giờ việc tra cứu lại dễ như bây giờ. Chắc chắn có những mức độ viết tắt gây cản trở học tập hoặc đóng vai trò như một kiểu gác cổng, nhưng để làm việc thì cần đặt tên cho khái niệm ở mức hữu dụng, nên tôi nghĩ các chữ viết tắt trong cài đặt đồ họa của game là khá hợp lý
Cách phân tích lập trình đồ họa bằng ví dụ WebGL thật thiên tài. Đây là hypertext tận dụng đúng thế mạnh của phương tiện. Nó gợi nhớ đến kiểu bài có thể thấy ở https://pudding.cool/, nhưng đi sâu hơn nhiều
Tôi đã dùng MSAAx4 trong engine render một thời gian, gần đây đang cân nhắc chuyển sang triển khai FXAA/TAA, nhưng giờ thì không chắc có thực sự nên đổi không. Tôi học được nhiều từ bài này, và có lẽ sẽ thử cách tiếp cận phân tích cho các phần tử UI. Bài viết về lập trình đồ họa không thường xuất hiện trên HN; với ai quan tâm hơn, tôi đề xuất tài nguyên này, một tuyển tập các bài phân tích frame:
https://www.adriancourreges.com/blog/
Bài tôi đặc biệt thích là https://acko.net/blog/how-to-fold-a-julia-fractal/. Tôi chưa từng thấy tài liệu nào giúp hiểu mối quan hệ giữa lượng giác và số phức tốt đến vậy
Những frame có vòng tròn và phần phóng to truyền tải thông điệp rất xuất sắc. Toàn bộ bài viết đọc rất mạch lạc
SDF hoặc mSDF không phải là tương lai, mà đã là một kinh điển đủ tốt rồi
Phần nói rằng “phải giải mọi đoạn đường cong Bézier cho từng pixel nên hiệu năng giảm mạnh” mới là thứ tôi cho là tương lai, hoặc hiện tại. Slug và DirectWrite đã được dùng với hiệu năng tốt rồi
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
Để đưa nó lên mức production phải làm cực kỳ nhiều việc. Tessellation dựa trên Voronoi trong bài báo đó trở nên tệ một cách bệnh lý với nhiều ký tự châu Á
Đang cuộn bài viết thì ảnh chụp màn hình NeoTokyo đập ngay vào mắt tôi. Tôi đã chạy qua cái hành lang đó hàng nghìn lần. Trong nhiều năm tôi đã vận hành server của mod đó, và đã có khoảng thời gian thật sự vui với một cộng đồng nhỏ nhưng giỏi và tốt bụng
Từ góc nhìn của người đã viết cả engine kết xuất 2D lẫn 3D, xin thêm một gợi ý nhỏ: hai thứ này thật sự khác nhau. Không chỉ là thêm một chiều, mà mục tiêu, trường hợp sử dụng và kỳ vọng đều hoàn toàn khác
Vì vậy, thay vì nói “mọi thứ được bàn ở đây cũng mở rộng sang 3D”, tôi muốn nói rằng toàn bộ bài này phần lớn là về kết xuất 3D, chứ không phải kết xuất 2D. Một bài hay bàn chủ đề này từ góc nhìn kết xuất 2D là https://ciechanow.ski/alpha-compositing/
Một tiêu chí khử răng cưa mà trong 3D chẳng ai quan tâm nhưng trong 2D lại rất quan trọng là độ chính xác và độ lệch. Ví dụ AAA bị lệch mạnh nên không chính xác. Nếu vẽ cùng một hình ở cùng một vị trí nhiều lần, nó sẽ trở nên đục hơn hoặc tối hơn. Với MSAA điều tương tự không xảy ra, sai số bị giới hạn và không có độ lệch
Việc vẽ đường nét dày đặc biệt thú vị, vì nó khó [1]. Gần đây tôi cũng thấy cái này [2], và bắt đầu tự hỏi liệu có thể chuyển mọi hình thành các đoạn đường cong Bézier bậc hai rồi dùng kỹ thuật đó không. Không biết bạn có xem đây là một hướng đáng theo đuổi không
[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...
Giải pháp được đề xuất dựa vào trường khoảng cách có dấu, nhưng lại lướt qua phần quan trọng: “khoảng cách tới cái gì?”. Trong 2D thì rõ ràng, chỉ cần đo khoảng cách tới ranh giới giữa vật thể và nền, tức silhouette
Trong 3D, mọi thứ phức tạp hơn vì vật thể có thể tự che khuất khi xoay. Vậy sẽ đo SDF theo chuẩn nào? Silhouette 2D của phép chiếu một vật thể 3D thay đổi liên tục và không thể đơn giản tính trước
Rất vui khi thấy liên kết Captain Disillusion. Tôi không biết người này trước đó, nhưng tác phẩm của anh ấy thật ấn tượng. Liên kết trực tiếp cho những ai quan tâm đến hiệu ứng video: https://www.youtube.com/@CaptainDisillusion
Bài viết được tổ chức tốt, nhưng tôi nghĩ phần công kích TAA có thể gây nhầm lẫn. Khử răng cưa bằng SDF không phải là phương án thay thế TAA theo bất kỳ cách nào
TAA xử lý mọi loại aliasing, còn ở đây chỉ bàn đến aliasing ở biên. Nhiều game hiện đại dùng các cách tiếp cận dựa trên Monte Carlo cho chiếu sáng gián tiếp và các hiệu ứng khác, và trên thực tế điều đó cần TAA
Phần “chip di động hỗ trợ đúng MSAAx4 và tình hình khá kỳ lạ. Trên Android có thể chọn 2x nhưng driver dù sao cũng ép thành 4x” khiến tôi hơi thắc mắc
Trên điện thoại Android của tôi, khác biệt giữa 2x và 4x thấy rất rõ, nhưng nó không trông “tròn” như phía iPhone