Kết xuất văn bản sắc nét trên GPU
(osor.io)- Cách làm Multi-Channel SDF trước đây vẫn có giới hạn với nét mảnh, atlas lớn, thu nhỏ·phóng to và chuyển động mượt, nên đã được triển khai lại bằng raster hóa runtime trên GPU
- Pipeline mới chỉ gửi dữ liệu đường cong Bézier của các glyph đang hiển thị lên GPU, vẽ vào atlas lúc runtime rồi lấy mẫu trên màn hình
- Nếu glyph vẫn còn trên màn hình thì giữ cache atlas và tích lũy mẫu để nâng chất lượng, bắt đầu từ 8 samples-per-pixel ở khung hình đầu tiên và tinh chỉnh dần tới tối đa 512 samples
- Khóa cache bao gồm font, glyph_index, kích thước pixel và độ lệch subpixel, dùng fixed-point 8 bit để gộp các vị trí và kích thước gần nhau về cùng một giá trị nhằm tăng khả năng tái sử dụng
- Nếu mô hình hóa cấu trúc subpixel RGB theo từng màn hình thành vùng lấy mẫu, có thể giảm lem màu ngay cả trên các bố cục không chuẩn như OLED G9, và demo văn bản toàn màn hình 4K cho thấy chi phí đỉnh khoảng 0.1ms trên Radeon 9070
Vì sao chọn raster hóa vector runtime thay vì SDF
- Triển khai trước đây dùng Multi-Channel Signed Distance Fields và nhìn chung hoạt động tốt, nhưng trong sử dụng thực tế vẫn còn vài ràng buộc
- Chất lượng: ở các font có nét mảnh hoặc nhiều chi tiết, đặc trưng có thể bị mất hoặc xuất hiện artifact, và đôi khi cần SDF độ phân giải cao hơn
- Kích thước atlas: SDF được tạo offline rồi lưu vào atlas, nên với các font tiếng Nhật·tiếng Trung có nhiều glyph thì rất khó bake vào một atlas duy nhất
- Tính linh hoạt: khó áp dụng các ý tưởng mới như xử lý thu nhỏ·phóng to hay subpixel anti-aliasing, và cũng không phù hợp với ảnh vector có thể tạo·chỉnh sửa lúc runtime
- Tính đơn giản: bước chuyển các đường cong glyph gốc sang texture trung gian làm tăng độ phức tạp của hệ thống
- Ngay cả font Latin như Miama cũng cần atlas
4096×1152với vùng64×64cho mỗi glyph, và nếu dùng nhiều font lúc runtime thì chi phí bộ nhớ và băng thông streaming sẽ tăng mạnh - Mục tiêu của cách tiếp cận mới là dùng trực tiếp hơn các đường cong Bézier do người tạo glyph thiết kế, giảm số bước chuyển đổi từ dữ liệu gốc tới pixel cuối cùng
Toàn bộ pipeline
- Cốt lõi là thay vì bake sẵn mọi glyph offline, chỉ gửi các đường cong của glyph đang hiển thị lên GPU và raster hóa đúng lúc cần
- Luồng xử lý khá đơn giản
- Tải dữ liệu đường cong glyph từ font
- GPU raster hóa glyph vào atlas ở runtime
- Khi xuất ra màn hình thì lấy mẫu từ atlas đó
- Nếu cùng một glyph tiếp tục được dùng ở các khung hình sau, nó sẽ được giữ lại trong atlas và tích lũy thêm mẫu để tinh chỉnh tới mức subpixel anti-aliasing chất lượng cao
- Vì render trực tiếp biểu diễn vector nên dễ thích ứng với thay đổi độ phân giải, đồng thời có thể tính không chỉ độ phủ toàn pixel mà còn cả độ phủ của từng phần tử subpixel
Xử lý đường cong glyph
- Việc nạp font dùng FreeType như một lớp trung gian trong công cụ offline để đọc các định dạng được hỗ trợ, duyệt qua đường cong của từng glyph rồi lưu thành định dạng asset riêng
- Đường cong glyph có thể gồm đường thẳng, Bézier bậc hai và Bézier bậc ba, và để shader đơn giản hơn thì tất cả đều được chuyển sang Bézier bậc hai
- Đường thẳng được biến thành Bézier bậc hai bằng cách thêm một điểm điều khiển ở giữa hai điểm
- Bézier bậc ba được tách thành hai Bézier bậc hai, đây là phép biến đổi có mất mát khi hạ bậc
- Cách tách Bézier bậc ba thành hai Bézier bậc hai hoạt động tốt với hầu hết các font đã thử, nhưng cũng có thể dùng các phương pháp tinh vi hơn để giảm sai số thêm nữa
- Nếu cần chuyển đổi chất lượng cao hơn, có thể dùng công cụ offline để đổi sang định dạng chỉ có Bézier bậc hai như TrueType
.ttf, từ đó tránh luôn bước chuyển đổi này - Có thể so sánh hình dạng của Bézier bậc ba đầu vào và hai Bézier bậc hai đầu ra trong đồ thị Desmos
Tính độ phủ và tối ưu truy cập đường cong
- Độ phủ được tính theo từng pixel bằng cách bắn một tia ngang từ trái sang phải, kiểm tra giao điểm với các đường cong và cộng dồn winding number
- Có thể tham khảo nền tảng toán học và cách triển khai trong GPU Font Rendering của GreenLightning và video Rendering Text của Sebastian Lague
- Sai số trong tính giao điểm có thể xuất hiện ở một số mẫu tại độ cao nhất định, nhưng khi tích lũy hàng trăm mẫu thì một hai lỗi gần như không còn thấy được sau khi lấy trung bình
- Khi tích lũy tối đa 512 mẫu, nếu một mẫu sai thì thay vì
0sẽ thành1/512=0.00195, hoặc thay vì1sẽ thành511/512=0.99804 - Cũng có thể đặt ngưỡng để clamp khi độ phủ tiến gần các giá trị cực trị
- Khi tích lũy tối đa 512 mẫu, nếu một mẫu sai thì thay vì
- Phân bố vị trí mẫu dùng $R_2$ sequence của Martin Roberts, và có thể xem phân bố theo thời gian trong ví dụ Shadertoy
- Để giảm chi phí truy cập đường cong, glyph được chia thành nhiều dải ngang, và chỉ các đường cong chạm tới từng dải mới được lưu bằng bitset
- Vì chỉ truy vết tia ngang nên có thể giảm mạnh tập đường cong mà mỗi pixel phải kiểm tra
- Nếu để các wave truy cập cùng phạm vi dải, có thể scalar hóa việc lặp và đọc đường cong
- Khi raster hóa vào atlas bằng compute shader, các thread được đóng gói ngang theo row-major để giảm tối đa phạm vi dải mà wave chạm tới
Đóng gói atlas và khóa cache
- Ban đầu glyph được raster hóa trực tiếp lên màn hình, nhưng chi phí tính anti-aliasing chất lượng cao ở mọi khung hình là khá lớn
- Phần lớn văn bản giữ nguyên cùng kích thước và vị trí trong nhiều khung hình, và cùng một glyph cũng lặp lại ở cùng kích thước, nên atlas và tích lũy theo thời gian là phù hợp
- Atlas sẽ cấp phát chỗ và bắt đầu raster hóa nếu chưa có glyph cần thiết, còn nếu đã có thì dùng lại kết quả cũ
- Trong mỗi khung hình, các glyph trong atlas được kiểm tra để quyết định tiếp tục giữ lại, lấy mẫu thêm hay giải phóng chỗ vì không còn dùng nữa
- Khóa atlas gồm các thành phần sau
fontglyph_indexquantized_size_in_pixels_x,quantized_size_in_pixels_yquantized_subpixel_offset_x,quantized_subpixel_offset_y
- Độ lệch subpixel tương ứng với
frac(pixel_position), cần thiết để tạo kết quả anti-aliasing khớp vị trí khi glyph không nằm đúng trên lưới pixel hoặc khi cuộn mượt - Nếu dùng trực tiếp giá trị floating-point làm khóa thì những giá trị đáng ra phải giống nhau về mặt toán học vẫn có thể khác nhau ở cấp bit, nên hệ thống dùng fixed-point với phần thập phân 8 bit để gộp các vị trí và kích thước gần nhau thành cùng một giá trị
- Nếu là trình soạn thảo văn bản có nhiều nội dung tĩnh và dùng font monospace, có thể canh khoảng cách ký tự và vị trí dòng theo biên pixel để tăng tỷ lệ cache hit của atlas cho cùng một glyph
Bố trí atlas dựa trên Z-Order
- Việc bố trí glyph lúc runtime dùng Z-Order Packing và bitset các ô trống
- Z-Order dựa trên Morton code cho phép xử lý các ô 2D như một mảng 1D dài, và nếu cấp phát số ô liên tiếp là lũy thừa của 2 thì trong atlas 2D chúng sẽ tạo thành một vùng vuông
- Ô cơ sở là
16×16texel, còn kích thước glyph được làm tròn lên lũy thừa của 2 tiếp theo- Ví dụ glyph
25×29sẽ được cấp một khối32×32 - Khi đó cần 4 ô
16×16, nên hệ thống sẽ tìm 4 bit liên tiếp đã căn chỉnh để sử dụng
- Ví dụ glyph
- Các glyph Latin dài và mảnh thường có xu hướng dọc, nên dùng transposed Z-Order sẽ giúp các glyph như
l,j,i,1chỉ tốn một nửa không gian - Ngược lại, với các glyph dài và mảnh theo chiều ngang như trong tiếng Ả Rập thì Z-Order chuẩn phù hợp hơn
Cách nâng chất lượng bằng tích lũy theo thời gian
- Nếu glyph còn ở lại trong atlas thì có thể cộng thêm một ít mẫu ở mỗi khung hình để tinh chỉnh dần kết quả
- Lịch mặc định là ở khung hình đầu tiên glyph xuất hiện sẽ dùng 8 samples-per-pixel, khung tiếp theo là 4, rồi 2, sau đó thêm 1 mẫu mỗi khung hình cho tới khi tích lũy đủ tổng cộng 512 mẫu
- Lý do đặt chất lượng khung đầu tiên cao là vì các glyph di chuyển mượt hoặc thay đổi kích thước về thực chất giống như bị khởi tạo lại ở mỗi khung hình
- Chất lượng và hiệu năng có thể điều chỉnh theo nhiều cách
- Số mẫu·số tia thêm vào mỗi khung hình
- Có tăng số mẫu trong vài khung hình đầu của glyph hay không
- Giới hạn tổng số mẫu mỗi khung hình
- time-slicing, tức cập nhật glyph cũ theo chu kỳ vài khung hình thay vì mỗi khung hình
- Cách giới hạn chi phí kiểm tra giao điểm theo số lượng đường cong của glyph
- Trong triển khai này, hiệu năng không phải vấn đề lớn; phần mở đầu với văn bản toàn màn hình cho thấy mức đỉnh khoảng 0.1ms ở 4K trên Radeon 9070, và khi glyph đạt tới số mẫu tối đa thì chi phí nhanh chóng về gần 0
Subpixel anti-aliasing và lem màu
- Subpixel anti-aliasing render bằng cách coi từng thành phần đỏ·xanh lá·xanh dương trong một pixel màn hình là các vùng lấy mẫu riêng biệt
- Với cấu trúc sọc dọc của màn hình LCD RGB truyền thống, độ phân giải ngang trên thực tế được tăng gấp 3, tức ở 4K có thể xử lý
3840×2160như3840×6480 - Vấn đề là các màn hình như OLED G9 có cấu trúc subpixel không chuẩn khác với sọc dọc RGB tiêu chuẩn
- Nếu giả định cấu trúc chữ nhật dọc RGB cơ bản thì sẽ thấy lem màu xanh lá ở phía trên và magenta ở phía dưới
- Nếu đặt vị trí lấy mẫu khớp với cấu trúc subpixel thực của màn hình thì gần như không còn lem màu và kết quả mượt hơn
- Subpixel Zoo cho thấy nhiều ví dụ về cấu trúc subpixel khác nhau, còn cấu trúc red-white-blue-green của LG WOLED là một ví dụ có thứ tự khác chuẩn
- Kết quả chính xác hơn thu được khi coi các phần tử subpixel lớn hơn kích thước vật lý thực và để chúng chồng lấn lên nhau
- Ánh sáng của subpixel vốn tự nhiên hòa trộn và khuếch tán nhẹ, nên vùng lấy mẫu hoạt động như thể lớn hơn subpixel vật lý
- Vùng lấy mẫu cũng cần lan ra ngoài pixel và trộn với ánh sáng subpixel của các pixel lân cận
- Easy Scalable Text Rendering của Evan Wallace cho rằng sau subpixel anti-aliasing cần có làm mờ ngang, và điều này về thực chất tạo ra hiệu ứng tương đương với việc xem các phần tử subpixel lớn hơn và chồng lấn hơn
Phần mềm cần biết thông tin subpixel của màn hình
- Nếu có thể truy cập cấu trúc subpixel tùy ý của màn hình, phần mềm có thể cải thiện cả subpixel anti-aliasing nói chung lẫn chất lượng render văn bản
- Nếu thông tin này được cung cấp qua các giao thức hiển thị phổ biến, ngay cả màn hình có bố cục chuẩn cũng có thể được render tinh chỉnh hơn theo từng phần cứng
- Nhà sản xuất màn hình sẽ không cần tránh thử nghiệm các cấu trúc subpixel tốt hơn chỉ vì vấn đề render văn bản
- Samsung đã thay đổi cấu trúc subpixel trên QD-OLED từ G8 sang G9 để giảm các vấn đề này, còn trên LG WOLED và Samsung QD-OLED thì hiện tượng lem màu thường xuyên bị nhắc tới
- Đây là vấn đề còn nhiều dư địa để xử lý bằng hiệu chỉnh phần mềm thay vì phải thay phần cứng
Giá trị thực tiễn của render glyph thời gian thực
- Chất lượng UI và văn bản tốt có thể nâng cảm nhận chất lượng tổng thể của sản phẩm
- Trong game, các thành phần như hộp thoại, menu, tiêu đề hay thông báo thường là nơi người dùng tập trung ánh nhìn, nên chất lượng văn bản kém có thể ảnh hưởng trải nghiệm không kém gì một cảnh 3D render tệ
- Loạt Persona, Metaphor: ReFantazio và Nier: Automata là những ví dụ tốt về UI và cách thể hiện văn bản
- Những nỗ lực cải thiện chất lượng render glyph thời gian thực có giá trị thực tiễn cho cả UI lẫn render trong game
1 bình luận
Ý kiến trên Hacker News
Chuyện gì đã xảy ra với dấu chấm của chữ j in nghiêng trong video đầu tiên vậy?
Kết xuất phông chữ subpixel rất quan trọng đối với khả năng đọc, nhưng như bài viết chỉ ra, thật đáng tiếc là không thể lấy được đặc tả bố trí pixel từ các tiêu chuẩn màn hình hiện có
Thế giới ngày càng chuyển sang màn hình cấp Retina, nơi hầu như không còn lý do để dùng kết xuất subpixel
Có nhiều phiền toái như ảnh chụp màn hình bị ràng buộc với một bố trí subpixel cụ thể, và việc phóng to/thu nhỏ bitmap cũng khó khăn
Nó từng là một cải tiến tạm thời trong kỷ nguyên LCD giữa CRT và Retina, còn giờ gần như là công nghệ nhìn về quá khứ. Apple đã loại bỏ nó khỏi macOS vài năm trước là có lý do
Tôi tò mò liệu các nhà sản xuất màn hình có không triển khai hay không. Dù sao, với các mẫu màn hình phổ biến nhất, đây là thông tin có thể dễ dàng suy luận và lưu trong cơ sở dữ liệu thông tin phần cứng
Bài viết rất hay, và còn liên kết tới “subpixel zoo” cho thấy nhiều trường hợp khác nhau: https://geometrian.com/resources/subpixelzoo/
Ngay cả trong trường hợp không thể tránh khi màn hình báo sai bố trí, cách này vẫn cần thiết
Chỉ riêng phông bitmap không khử răng cưa hoặc phông vector có hinting cũng đã cho khả năng đọc rất tốt
Nó chỉ trở nên quan trọng với các ngôn ngữ có ký tự chứa chi tiết rất phức tạp như tiếng Trung hoặc tiếng Nhật
GTK4 đã từ bỏ kết xuất subpixel RGB khi chuyển kết xuất sang GPU
Tôi từng nghe rằng các quyết định xoay quanh GPU khiến việc tiếp tục kết xuất subpixel RGB trở nên khó khăn, nhưng bài viết cho thấy là có thể làm được
Vậy thì lý do của GTK có thể nằm ở chỗ khác, hoặc giải pháp được đưa ra có nhược điểm, hoặc nó không tích hợp tốt với stack hiện có
Nếu bạn quan tâm đến cách triển khai SDF và MSDF trong WebGL / WebGPU, có thể xem tutorial tôi tự viết: https://infinitecanvas.cc/guide/lesson-015#msdf
Tôi từng thử chuyển các ví dụ JavaScript sang Rust; không thể chỉ copy/paste, nhưng API đủ giống để port dễ dàng, nên rất lý tưởng để học
Nó cũng giúp làm quen với việc dùng tài liệu WGPU
Tôi thích làm tutorial liên quan đến GPU và muốn cấu trúc theo kiểu này; không biết đây là template có sẵn hay là một phần của khóa học nào đó
Thư viện Slug là middleware thương mại triển khai kiểu GPU glyph rasterizer này
[1]: https://sluglibrary.com/
Sẽ rất thú vị nếu dùng phần phân tích phông chữ và layout của cosmic-text để tạo một phiên bản wgpu mã nguồn mở, nhưng sẽ chẳng vui chút nào nếu cuối cùng bị Slug kiện
GPU trông như thể có khả năng vẽ đỉnh/pixel gần như vô hạn, nên tôi vẫn chưa hiểu vì sao phải kết xuất văn bản offline rồi lưu vào atlas, thậm chí dùng các thủ thuật như SDF
Bài viết cũng nói rằng họ ghi các đường cong glyph vào atlas, nhưng tôi tự hỏi vì sao shader không thể kết xuất văn bản trực tiếp
Hẳn phải có cách chuyển Bézier thành mesh tam giác. Tôi đang chuẩn bị bắt đầu làm GPU text renderer cho ứng dụng CAD, nên hy vọng sẽ sớm hiểu lý do
GPU nhanh, nhưng không nhanh vô hạn, và nó rất mạnh ở việc sample texture đã được kết xuất sẵn
Đây không chỉ là vấn đề tốc độ mà còn là vấn đề điện năng tiêu thụ. Nếu đã đạt tần số quét của màn hình, hiệu năng tăng thêm sẽ không cải thiện độ phản hồi, nhưng có thể kéo dài thời lượng pin
Trong kết xuất không có khái niệm “đủ nhanh”; nhanh hơn luôn có lợi
Tất cả kiến trúc GPU hiện đại đều không xử lý tốt hình học mật độ cao. Trong trường hợp này, cách đơn giản là đẩy tam giác vào GPU kém hiệu quả hơn rất nhiều so với atlas hoặc các kỹ thuật khác
Phần lớn GPU dispatch pixel shader theo nhóm 4. Nếu mọi tam giác đều chỉ cỡ 1 pixel, thì 3 luồng shader sẽ không đóng góp gì cho đầu ra thị giác
Điều này được gọi là quad overdraw. Hơn nữa, bạn còn tốn nhiều thời gian xử lý đỉnh mà không có lý do thực sự
Có thể làm được, nhưng bạn sẽ đánh đổi một phần frame budget và tăng mức tiêu thụ điện năng mà gần như chẳng được lợi gì
Tác giả dùng atlas vì họ supersampling đường cong Bézier tới tối đa 512 mẫu mỗi pixel, việc này rất đắt
Thay vào đó, nếu tính tích phân giao giữa vùng đường cong Bézier và vùng subpixel thì có thể nhanh hơn nhiều, chạy thời gian thực không cần atlas và có vẻ còn chính xác hơn supersampling
Và hầu như lúc nào bạn cũng sẽ muốn dùng thời gian đó vào việc khác
Càng cần nhiều thời gian GPU, yêu cầu phần cứng tối thiểu càng phải tăng nhanh hơn. Văn bản thì đẹp và quan trọng, nhưng có thể không quan trọng đến mức đáng đánh mất người dùng hoặc khách hàng
Trông còn tệ hơn mức “các OLED mới nhìn thì đẹp nhưng có vấn đề lem màu do cấu trúc subpixel không chuẩn”
Theo tôi hiểu thì không chỉ là không chuẩn, mà trên OLED có nhiều cách bố trí subpixel không tương thích với nhau
Vì vậy FreeType chưa triển khai render subpixel cho OLED, và đó trở thành lý do nên tránh OLED nếu cần làm việc với văn bản
Đây cũng không chỉ là vấn đề của riêng FreeType; các GUI toolkit như Qt, GTK cũng phải được điều chỉnh đồng bộ. Tôi không rõ việc giải quyết đã tiến triển đến đâu
Sẽ rất tốt nếu có thể truy cập cấu trúc subpixel của một màn hình bất kỳ, và có lẽ thông tin kiểu này nên được truyền qua EDID
Ví dụ laptop của tôi dùng bố trí BGR theo chiều dọc, và FreeType cùng KDE hỗ trợ tốt
Tôi nghĩ các bố trí kỳ lạ thường xuất hiện vì trên màn hình HDR, để một số màu, đặc biệt là xanh lam, không bị cháy quá nhanh, người ta phải dùng kích thước khác nhau cho từng màu
Đây là một công trình rất ấn tượng
Nói thêm cho những ai chưa quen với lĩnh vực này: Valve đã tạo ra render văn bản SDF cho game và công bố một bài báo mang tính đột phá về chủ đề này vào năm 2007
Đến nay đây vẫn là kỹ thuật được dùng rất rộng rãi trong video game, gần như không thay đổi nhiều
Năm 2012, Behdad Esfahbod đã tạo Glyphy, một triển khai SDF chạy trên GPU bằng OpenGL ES; nó được đánh giá cao nhờ hiệu năng và các khả năng mới như biến đổi văn bản nhanh, nhưng không được dùng rộng rãi
Các hệ điều hành và trình duyệt web hiện đại lại có xu hướng ưu tiên dựa vào raster hóa TrueType kiểu thập niên 1990 thay vì những kỹ thuật như vậy
Đây là cách tiếp cận nhẹ và hiệu quả, nhưng như bài viết cho thấy, nó không thể căn chỉnh subpixel hay hỗ trợ bố trí subpixel tùy ý; phóng to/thu nhỏ có chi phí hiệu năng lớn; và các biến đổi phức tạp như nghiêng, xoay, biến đổi 3D cũng không thể thực hiện bên trong engine render văn bản
Nếu cần văn bản bị xoay hoặc biến dạng, phải resample bitmap, điều này phá hỏng mọi đặc điểm nhỏ tạo nên tính dễ đọc và khiến kết quả trông không đẹp
Lý do tiến triển chậm có thể là vì khối lượng công việc và rủi ro quá lớn so với lợi ích. Thử tưởng tượng viết lại một engine trình duyệt web hiện đại để render văn bản tăng tốc bằng GPU thì sẽ thấy không hề đơn giản
Render glyph chỉ là một phần, còn xử lý xuống dòng lại là vấn đề khác. Có thể cần nhiều giao tiếp giữa CPU và GPU nên sẽ chậm, và việc tích hợp sâu giữa phần mềm với GPU cũng khó
Cách này có hiệu năng tốt hơn nhiều so với việc cố nhét vào pipeline render 3D phần cứng như SDF
Safari có lẽ cũng thế, nhưng tôi không thể khẳng định vì chưa tự kiểm chứng
Ý nghĩ rằng trình độ kỹ thuật hiện tại hay các triển khai được phân phối tới người dùng không có tiến bộ là không đúng
SDF mã hóa khoảng cách cục bộ (Distance) từ một pixel nhất định đến cạnh chữ vào một trường (Field) là mảng dữ liệu hai chiều, và dùng bit dấu (Sign) để biểu thị khoảng cách đó nằm bên trong hay bên ngoài chữ
Mỗi ký tự có một bản đồ dữ liệu nhỏ; chúng được đóng gói cùng nhau dưới dạng file ảnh thân thiện với GPU, rồi shader render SDF sử dụng kèm một file mô tả cho biết cần tìm ảnh con của từng ký tự ở đâu
Định nghĩa ký tự kiểu này rất bền với nội suy tuyến tính giữa các giá trị trong field, nên ngay cả bản đồ độ phân giải tương đối thấp cũng có thể phóng to gần như hoàn hảo. GPU cũng rất giỏi nội suy giá trị pixel của bản đồ
Nhưng điểm quan trọng là trong quá trình phát triển, cần tiền xử lý các bản đồ này cho mọi ký tự muốn render từ hệ thống phông chữ hiện có. Cần làm cho từng ký tự mà phông chữ hỗ trợ
Dữ liệu ít hơn nhiều so với việc render mọi ký tự bằng phông bitmap độ phân giải cao, nhưng vẫn nhiều hơn hẳn so với chính định nghĩa đường viền glyph của phông chữ
Những hệ thống muốn hỗ trợ mọi văn bản có thể có trên toàn thế giới, như hệ điều hành hay trình duyệt, không thể dùng SDF làm hệ thống render văn bản. Khi đó sẽ cần bản đồ SDF cho toàn bộ tập ký tự Unicode, quá lớn
Game thì phù hợp hơn vì nhìn chung không cần bản địa hóa đủ tốt, hoặc không cần hiển thị văn bản hoàn toàn tùy ý
SDF nguyên bản cũng không thể hỗ trợ emoji, vì nó chỉ mã hóa khoảng cách tới cạnh glyph chứ không chứa thông tin màu bên trong glyph
Có một phiên bản cải tiến hỗ trợ nhiều màu là Multichannel SDF, nhưng vẫn có giới hạn về tổng số màu
Trên thực tế, nếu quan sát kỹ một game dùng SDF cho văn bản trong game nhưng cũng có hệ thống chat nơi cộng đồng toàn cầu tương tác, rất có thể render văn bản trong game và render văn bản của hệ thống chat là khác nhau
Theo https://keithclark.co.uk/articles/gpu-text-rendering-in-webk... (2014), “trong phiên bản hiện tại của Chrome, Safari hoặc Opera, khi một phần tử được nâng lên GPU, nó sẽ mất khử răng cưa subpixel và văn bản được render theo kiểu grayscale”
Vậy tôi tò mò là còn thiếu gì. Nếu đúng như câu đó, ít nhất một phần của bước đi từ chuỗi UTF-8 đến bitmap có thể được thực hiện trên GPU, không phải sao?
Đây là một công trình ấn tượng
Tuy nhiên, cá nhân tôi thấy khử răng cưa subpixel không có nhiều ý nghĩa. Vào những năm 2000, khi còn dùng màn hình 72dpi, đó là một mẹo khá hay, nhưng trên màn hình Retina hiện đại thì khó nhận ra, và ta phải đánh đổi nhiều nhược điểm chỉ để lấy một cải thiện rất nhỏ
Nó chỉ hoạt động trên nền mờ đục, không thể áp dụng các hiệu ứng như thay đổi kích thước, lật gương hay làm mờ lên kết quả đã rasterize, và ảnh chụp màn hình sẽ trông tệ hơn khi xem trên màn hình khác
Theo khảo sát phần cứng của Firefox [1], 16% người dùng đang sử dụng màn hình độ phân giải 1366x768
Đây không chỉ là vấn đề của phần cứng cũ đơn thuần; màn hình và laptop 96dpi hiện nay vẫn đang được sản xuất
[1]: https://data.firefox.com/dashboard/hardware
Các lập luận khác không mấy quan trọng so với kết quả tốt hơn mà subpixel rendering mang lại ở những nơi có thể áp dụng
Điểm quan trọng là SDF tính khoảng cách tính bằng pixel đến cạnh gần nhất, còn các trình render phông chữ truyền thống tính coverage của pixel
Coverage của pixel là tối ưu. Với phông chữ nhỏ, SDF có thể trông xấu ở những chỗ các cạnh gặp nhau
Trên màn hình PPI cao thì có lẽ ít thành vấn đề hơn. Tôi từng tự triển khai một SDF renderer và nó trông tệ hơn FreeType
Tuy nhiên, nhận xét rằng distance field gây vấn đề tại các giao điểm, hay nói chung là ở các góc sắc, là đúng
Có thể giảm nhẹ phần nào bằng cách dùng nhiều distance field và render phần giao của chúng. Ví dụ có https://github.com/Chlumsky/msdfgen