OpenGL 程式設計/現代 OpenGL 教程文字渲染 03
你已經閱讀了其他兩個文字渲染教程,但仍然不滿意。你想要全部:對 Unicode 和現代文字整形提供全面支援,在原生 OpenGL 中使用,而無需使用像 Pango 這樣的高階庫帶來的開銷和控制權的損失。10 年前,由於封閉標準和固定功能流水線,你將無能為力。今天,這已經觸手可及。
在上一個教程中,我們使用了一個帶有簡單行填充演算法的紋理圖集。通常我們有一個正方形紋理,例如 2048x2048,所以你應該新增一個簡單的檢查,當行已滿時換行。我們可以使用更復雜的填充演算法,但這將是昂貴的計算,我們必須提前知道我們將使用哪些字型和字形。在遊戲中,這很容易;我們可以建立多個紋理包,每個包對應一個支援的語言,並在需要時切換它們。
但是,如果你有一個大型字元集,例如阿拉伯語或中文,紋理圖集可能會變得有問題。如果你有大量字型,例如在文件處理系統或網頁瀏覽器中,這也是一個問題。網頁尤其傾向於使用許多不同的字型和字形,甚至可以使用 WebFonts 動態下載字型。隨著字型載入和解除安裝,不斷打包和重新打包我們的字形只會導致更多開銷,或者在最壞的情況下,由於我們無法丟棄舊的字形,會導致記憶體不足錯誤。
由你決定快取什麼。現在,我們回到第一個教程的簡單世界,渲染所有內容,沒有任何快取。
在我們舊的示例中,我們使用了一個簡單的計算來進行佈局;新增 x 和 y 前進值來獲取新的位置。但這根本沒有處理連字或非從左到右語言的複雜性。這就是 Harfbuzz 的作用。但是,Harfbuzz 仍然沒有處理指令碼檢測或 Unicode 控制序列;你需要 FriBiDi 或 libraqm 來完成這些操作。但即使是 libraqm 也不處理斷行;如果你想要漂亮的換行文字,你將不得不將 minikin 從 Android 的其餘部分中分離出來。
無論你使用哪種方法,最終你將獲得一個字形列表,以及它們在 x 和 y 座標上的位置。
字型可以被認為是一堆佈局資訊加上一系列字形。佈局資訊由 Harfbuzz 和其他庫讀取,所以在這裡並不特別重要。但是字形很重要。每個字形都是一系列貝塞爾曲線、線段和移動指令。但然後是提示;在典型的字型大小下,大多數字形實際上不會直接繪製輪廓,而是使用專為在低 dpi 下看起來更好的“提示”變體。隨著高解析度“視網膜”顯示器的出現,這不再像以前那樣是一個問題,但舊顯示器仍然存在。
接下來,字形必須被光柵化。你可以用大量的短線段來近似曲線,並直接用 OpenGL 繪製這些線,但這相當昂貴。一個更巧妙的方法是使用 OpenGL 著色器來繪製曲線,但這當然也很棘手,因為它仍然需要三角剖分和細分。幸運的是,這已經在 Glyphy 庫中實現了。
最簡單的方法是直接在 CPU 上光柵化,透過呼叫 Freetype 的內建光柵化器。但這很慢,所以無論你使用哪種演算法,都需要一個快取。尤其是陰影,非常昂貴。