2

フリータイプを使用してアプリケーションにテキストを表示しようとしています。最初は、この組み込み関数 (テキストを描画することを目的としたライブラリーにとっては非常に自然なことでしょう) だと思いました。ただ、記号を表示する機能しかなかったので、文字を1文字ずつテクスチャに取り込んでいくことにしました。しかし、ここでも私はがっかりしました: 1 つのテクスチャが 1 つの画像を使用するすべてのガイド (おそらく glTexSubImage2D が私を助けることができますか?) 今、テクスチャにシンボルを配置し、opengl 要素へのテクスチャを配置します。それがどのように機能するかを理解しようとしているだけです):

//init:

    if (FT_Init_FreeType(&ft)) {
        fprintf(stderr, "Could not init freetype library\n");
        return 0;
    }
    if (FT_New_Face(ft, fontfilename, 0, &face)) {
        fprintf(stderr, "Could not open font %s\n", fontfilename);
        return 0;
    }
    FT_Set_Pixel_Sizes(face, 0, 48);    FT_GlyphSlot g = face->glyph;

そしてdisplay()から:

 void display()
 {
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0 ,1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();//load identity matrix
std::string s = "QWERTYOG0l  ";

for(int i = 0; i < s.size(); i++){
    FT_Load_Char( face, s[i], FT_LOAD_RENDER );
    FT_GlyphSlot g = face->glyph;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    gluBuild2DMipmaps( GL_TEXTURE_2D, 
          GL_RED, 
          g->bitmap.width, 
          g->bitmap.rows, 
          GL_RED, 
          GL_UNSIGNED_BYTE, 
          g->bitmap.buffer );
    glBegin(GL_QUADS);
      glTexCoord2f(0.0f, 0.0f);glVertex3f(0.1f*i-0.1,0.07f,0.0f); //top left
      glTexCoord2f(0.0f, 1.0f);glVertex3f(0.1f*i,0.07f,0.0f); //top right
      glTexCoord2f(1.0f, 1.0f);glVertex3f(0.1f*i,-0.07f,0.0f); // bottom right
      glTexCoord2f(1.0f, 0.0f);glVertex3f(0.1f*i-0.1,-0.07f,0.0f); //bottom left
    glEnd();
}

コード結果

ご覧のとおり、「O」と「T」は正しいです (テクスチャの左下隅と右上隅を変更すると、完全に正しくなります)。しかし、他の記号はずれているように見えます (たとえば、「E」は上から下に左にずれています)。

完全なコード:

#include <math.h>
#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>

#include <ft2build.h>
#include FT_FREETYPE_H


FT_Library ft;
FT_Face face;
const char *fontfilename = "LucidaTypewriterBold.ttf";
GLuint      texture[10];  

GLint uniform_mytexture;
int setup() { 
    if (FT_Init_FreeType(&ft)) {
        fprintf(stderr, "Could not init freetype library\n");
        return 0;
    }
    if (FT_New_Face(ft, fontfilename, 0, &face)) {
        fprintf(stderr, "Could not open font %s\n", fontfilename);
        return 0;
    }
    FT_Set_Pixel_Sizes(face, 0, 48);
    FT_Load_Char( face, 'O', FT_LOAD_RENDER );
    FT_GlyphSlot g = face->glyph;

    glGenTextures(1, &texture[0]);    // Create The Texture
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    gluBuild2DMipmaps(GL_TEXTURE_2D,  GL_RGBA, g->bitmap.width, g->bitmap.rows,  GL_RED, GL_UNSIGNED_BYTE, g->bitmap.buffer);
    return 1;
 }
void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(1.0 ,1.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();//load identity matrix
    std::string s = "QWERTYOG0l  ";

    for(int i = 0; i < s.size(); i++){
        FT_Load_Char( face, s[i], FT_LOAD_RENDER );
        FT_GlyphSlot g = face->glyph;
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        gluBuild2DMipmaps( GL_TEXTURE_2D, 
              GL_RED, 
              g->bitmap.width, 
              g->bitmap.rows, 
              GL_RED, 
              GL_UNSIGNED_BYTE, 
              g->bitmap.buffer );
        glBegin(GL_QUADS);
          glTexCoord2f(0.0f, 0.0f);glVertex3f(0.1f*i-0.1,0.07f,0.0f); //top left
          glTexCoord2f(0.0f, 1.0f);glVertex3f(0.1f*i,0.07f,0.0f); //top right
          glTexCoord2f(1.0f, 1.0f);glVertex3f(0.1f*i,-0.07f,0.0f); // bottom right
          glTexCoord2f(1.0f, 0.0f);glVertex3f(0.1f*i-0.1,-0.07f,0.0f); //bottom left
        glEnd();
    }

    //glActiveTexture(GL_TEXTURE0);
    //glBindTexture(GL_TEXTURE_2D, texture[0]);               // Select Our Texture

 // glUniform1i(uniform_mytexture, /*GL_TEXTURE*/0);
    glutPostRedisplay();
    glutSwapBuffers();
}
void TimerFunction(int value)
{


}
int main(int argc, char *argv[])
{
       glutInit(&argc, argv);
       glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
       glutInitWindowSize(800,600);
       glutCreateWindow("Hello World");
        //glutTimerFunc(30, TimerFunction, 1);
       glewInit();
       glEnable (GL_TEXTURE_2D);

       setup();
       glutDisplayFunc(display);

       glutMainLoop();

       return 0;
}
4

2 に答える 2

3

私はこれを少し調べてきました。この答えは不完全かもしれませんが、理解するのに役立つかもしれません.

予備メモ

私が見つけたものにたどり着く前に、テクスチャ座標の問題を指摘する必要があります。あなたはこれを持っています:

glTexCoord2f(0.0f, 0.0f);glVertex3f(0.1f*i-0.1,0.07f,0.0f); //top left
glTexCoord2f(0.0f, 1.0f);glVertex3f(0.1f*i,0.07f,0.0f); //top right
glTexCoord2f(1.0f, 1.0f);glVertex3f(0.1f*i,-0.07f,0.0f); // bottom right
glTexCoord2f(1.0f, 0.0f);glVertex3f(0.1f*i-0.1,-0.07f,0.0f); //bottom left

次のようになります。

glTexCoord2f(0.0f, 0.0f);glVertex3f(0.1f*i-0.1,0.07f,0.0f); //top left
glTexCoord2f(1.0f, 0.0f);glVertex3f(0.1f*i,0.07f,0.0f); //top right
glTexCoord2f(1.0f, 1.0f);glVertex3f(0.1f*i,-0.07f,0.0f); // bottom right
glTexCoord2f(0.0f, 1.0f);glVertex3f(0.1f*i-0.1,-0.07f,0.0f); //bottom left

左上がテクスチャ座標の 0, 0 に対応し、1, 1 が右下に対応することに注意してください。これは、(推測のようなものですが) freetype puts が左上を原点として扱うためです。

役立つかもしれないもの

Freetype は、サイズが必ずしも 2 のべき乗であるビットマップを生成しません。これは、ミップマッピングでしばしば必要になります (参照: https://gamedev.stackexchange.com/a/7929 )。

したがって、これをテストしたい場合 (注: コードで実際にこれを使用しないでください。これは説明のためだけですgluBuild2DMipmaps)、呼び出しを次のように置き換えることができますdisplay(必ず#include <cstring>:

int pitch = g->bitmap.pitch;
if (pitch < 0) {
    pitch = -pitch;
}

unsigned char data[4096] = {0};
for (int row = 0; row < g->bitmap.rows; ++row) {
    std::memcpy(data + 64 * row, g->bitmap.buffer + pitch * row, pitch);
}

gluBuild2DMipmaps(
    GL_TEXTURE_2D, 
    GL_RGBA, 
    64, 
    64, 
    GL_RED, 
    GL_UNSIGNED_BYTE, 
    data
);

ビットマップ バッファを別の 64x64 バイト バッファの左上隅にコピーし、そこからミップマップを作成します。結果は次のとおりです。

結果

その他の注意事項

私のイラストレーション コードは、再描画のたびに各グリフのビットマップ データをコピーし、ビットマップ バッファーの実際のサイズ、またはピッチが 64 より大きいかどうかを考慮していないため、不適切です。 )再描画ごとにミップマップを生成することもできますが、単語を OpenGL に取り込む方法を学習しようとしているだけであれば、心配する必要はありません :)

編集:私はあなたのフォントを持っていないので、あなたとは別のフォントを使用しなければなりませんでした.

于 2013-02-10T21:23:30.627 に答える
0

tecu が言ったように、正しい解決策は 2 乗のサイズのテクスチャを使用することです。

また、その答えの前に、別の解決策を見つけました: glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );before gluBuild2DMipmaps. しかし、ここでは、テクスチャの周りの灰色の境界線などの問題がさらに発生します。

同様の目標を求めている人のために、私の経験を共有したいと思います。

透明な背景を黒くする:

GLfloat swizzleMask[] = { 0,0,0, GL_RED}; 
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);

UPDには、OpenGL拡張機能を使用した、よりシンプルで明白なソリューションがあります。 gluBuild2DMipmaps( GL_TEXTURE_2D, GL_ALPHA, g->bitmap.width, g->bitmap.rows, GL_RGBA, GL_UNSIGNED_BYTE, g->bitmap.buffer )

1 つのテクスチャですべての文字を接続します。

これはパフォーマンスに優れていると思いますが、正しい方法で変更できるかどうかはわかりません。

    if(text[i] == ' ') left += 20; else
    for (int row = 0; row < g->bitmap.rows; ++row) {
        std::memcpy(data + left + 64*(strSize*(row + 64 -  g->bitmap_top))
            , g->bitmap.buffer + pitch * row, pitch);
    }
    left += g->advance.x >> 6;

データ配列に接続する前に、幅と高さを計算 (および 2 の累乗に丸め) するとより効果的です。

カーニングが必要な場合は、 memcpy の独自の遅い実装を作成する必要があります。ここで、値を追加し (完全には変更しません)、 の超過をチェックしUCHAR_MAXます。

私の最終結果:ここに画像の説明を入力

于 2013-02-14T23:18:51.787 に答える