CGプログラマーとして、日々記録!

日々得た情報、学んだことを書き留めておくブログです。

FreeTypeを使ったOpenGLでのテキスト描画

OpenGLでテキストを描画する方法はいろいろありますが、FreeTypeを使ったテキスト描画を試したのでメモしておきます。

FreeType

 まずFreeTypeとは、フォントデータのインターフェースを提供するフォント関連のライブラリ。TrueType、Type1フォント、OpenTypeなどのフォント形式をサポートしている。またGNU GPLに似たライセンスとのことで、商用か否かに関わらず利用可能。(Wiki参照)
FreeTypeを利用することで、PCにインストールされているフォントファイルからフォントのデータにアクセスできる。フォントのラスタライズもできビットマップも得られるので、これをテクスチャとして使って文字を描画することができる。

FTGL

 すでにFreeTypeを使ったOpenGL用ライブラリFTGLがあるが、自作シェーダと合わせて使うことが厳しいようなので断念。固定シェーダで使う場合にはおすすめ。
情報メディア実験 このサイトで詳しく説明してくれています。

FreeTypeのインストール

 基本的なことは以下のサイトが大変参考になった。
FreeTypeでテキスト描画 - I CAN ’CAUSE I THINK I CAN!
個人的にインストールでつまづいた点は、FreeTypeのlibファイルをコンパイルするときにVisualStudio2010のままおこなってしまったことで、VisualStudio2015でそのlibファイルを使用したら_sprintf関連のエラーが出た。FreeTypeのインストールフォルダにはVisualStudio2010までのファイルしかないが、そのソリューションファイルをVisualStudio2015で開いて変換処理をしてビルドしたlibファイルを使用すれば、2015でも問題なく動いた。

FreeTypeの使用

 使用したFreeType関連のクラスや関数をキーワード的に並べると以下の通り。
#include "ft2build.h" #include FT_FREETYPE_H
FT_Library  FT_Face  FT_GlyphSlot  FT_Bitmap 
FT_Init_FreeType() FT_New_Face() FT_Set_Pixel_Sizes() FT_Load_Glyph() FT_Get_Char_Index()


 以下のサイトではOpenGLFreeTypeを使った方法を紹介しています。
OpenGL Programming/Modern OpenGL Tutorial Text Rendering 02 - Wikibooks, open books for an open world

FreeTypeの初期化

#include "ft2build.h"
#include FT_FREETYPE_H

FT_Library library;
FT_Face face;
FT_GlyphSlot slot;

FT_Init_FreeType(&library);
FT_New_Face(library, "C:\\Windows\\Fonts\\meiryo.ttc", 0, &face);
FT_Set_Pixel_Sizes(face, 0, 48);
slot = face->glyph;

 FreeTypeの初期化処理はだいたいこのような形。FT_New_Face()関数でフォントファイルを読み込み、faceにフォントデータが格納される。FT_Set_Pixel_Sizesでビットマップフォントのサイズ(幅と高さ)を指定するが、ひとつ注意というか迷う点は、第2引数(幅)、第3引数(高さ)のどちらかが0のときはもう一方の値と同じになる点。上の例だと、幅も高さも48になる。(こういう仕様は戸惑うだけだから、正直やめてほしい。実際戸惑った。)

文字のビットマップ化

const char16_t * text;
for (int i = 0; text[i] != '\0'; i++) {
    FT_Load_Glyph(face, FT_Get_Char_Index(face, text[i]), FT_LOAD_RENDER);
    const FT_Bitmap &bitmap = face->glyph->bitmap;
        ・
        ・
        ・
}

 文字列からビットマップを得る処理はこのような形で一文字ずつビットマップ化していく。
FreeTypeUnicodeに対応しているようでUTF-16を使うのがいいようなのでchar16_tで文字列を構成する。(FTGL まとめ - m107の日記 そのあたりの話はこのサイトが考察してくれています。)
これでビットマップ画像が得られるので、これをOpenGLのglTexImage2D()でテクスチャとして登録する。

 FT_Bitmapには以下のメンバ変数があり、これをglTexImage2D()に渡せばいい。
buffer:ビットマップ画像データ
width:ビットマップ画像の幅
rows:ビットマップ画像の高さ



 これらの基本的な使い方を踏まえて、自作クラスを作成してFreeTypeを使ったOpenGLでのテキスト描画を試した。
満たした機能としては、シングルトンでクラスを作成し、文字のテクスチャをアトラステクスチャとして1枚のテクスチャにまとめるようにした。
 アトラステクスチャとは簡単に言うと複数のテクスチャを並べて配置し一つにまとめたテクスチャ。UV座標を指定して特定のテクスチャを取り出して使用する。
 文字を描画する関数で、まだ使用していない新たな文字が入力されたら、アトラステクスチャに新たな文字を追加し更新する。このとき、テクスチャのサイズを変更するが、glTexImage2D()をもう一度呼べば可能。glTexSubImage2D()は既にあるテクスチャの一部を変更する関数で、テクスチャのサイズ自体は変更できない(おそらく)。


f:id:blendgimper:20160101071723j:plain
上の文字がアトラステクスチャとして文字を1枚の画像にまとめたもので、下の文字がそこから参照して文字を描いたもの。

以下いろいろメモ

・glTexImage2Dでテクスチャのサイズは更新できる。
・テクスチャのサイズが奇数の時画像が乱れたがglTexImage2Dを呼ぶ前にglPixelStorei(GL_UNPACK_ALIGNMENT, 1)を呼べば回避できた。