web-dev-qa-db-ja.com

OpenGLメソッドのみを使用してテキストを描画する方法は?

使用するオプションはありませんが、OpenGLメソッド(つまり、glxxx()メソッド)があります。 glメソッドのみを使用してテキストを描画する必要があります。赤い本を読んだ後、それはglBitmap()メソッドを通してのみ可能であることを理解しています。これが唯一の可能な方法である場合、すべての文字のピクセル配列情報を手伝ってください。テキストを描画する他の方法はありますか?

36
sathish v

理論

なぜ難しいのか

TrueTypeOpenType などの一般的なフォント形式はベクトルアウトライン形式です: Bezier曲線 文字の境界を定義します。

画像ソース

これらの形式をピクセルの配列に変換(ラスタライズ)するのはあまりにも具体的で、OpenGLの範囲外です。特にOpenGlには非直線プリミティブがないためです(例: OpenGLに円または楕円プリミティブがないのはなぜですか?

最も簡単な方法は、まずCPU上で自分でラスタフォントを作成し、次にテクスチャとしてOpenGLにピクセルの配列を与えることです。

OpenGLは、テクスチャを介してピクセルの配列を処理する方法を非常によく知っています。

テクスチャアトラス

フレームごとにラスター文字を使用してテクスチャを再作成できますが、特に文字のサイズが固定されている場合は、あまり効率的ではありません。

より効率的なアプローチは、使用する予定のすべての文字をラスター化し、単一のテクスチャに詰め込むことです。

そして、それを一度GPUに転送し、カスタムUV座標でテクスチャを使用して適切なキャラクターを選択します。

このアプローチは texture atlas と呼ばれ、テクスチャだけでなく、2DゲームのタイルやWeb UIアイコンなど、繰り返し使用される他のテクスチャにも使用できます。

それ自体がfreetype-glから取得した完全なテクスチャのウィキペディアの写真は、これをよく示しています。

文字配置を最小のテクスチャ問題に最適化することはNP困難な問題であると思われます: さまざまなサイズの長方形を可能な限り最小の長方形にかなり最適な方法でパックするためにどのアルゴリズムを使用できますか?

ウェブ開発でも同じ手法を使用して、複数の小さな画像(アイコンなど)を一度に送信しますが、「CSSスプライト」と呼ばれます: https://css-tricks.com/css-sprites / CPUおよびGPU通信のレイテンシーの代わりにネットワークのレイテンシーを隠すために使用されます。

非CPUラスターメソッド

CPUラスターをテクスチャに使用しないメソッドもあります。

CPUラスタリングは、GPUを可能な限り使用しないため単純ですが、GPUの効率をさらに使用できるかどうかも検討し始めます。

このFOSDEM 2014ビデオ は、他の既存のテクニックについて説明しています。

遠近感のある3Dジオメトリ内部のフォント

(直交HUDと比較して)遠近法で3Dジオメトリ内にフォントをレンダリングすると、遠近法により文字の一部が画面に非常に近く、他方より大きくなり、均一なCPU離散化(ラスター、テッセレーション)近くで見た目が悪い。これは実際に活発な研究トピックです:

enter image description here

距離フィールドは、現在人気のあるテクニックの1つです。

実装

以下の例はすべてUbuntu 15.10でテストされました。

これは前述のように複雑な問題であるため、ほとんどの例は大きく、この回答の30k文字の制限を超えてしまうため、それぞれのGitリポジトリを複製してコンパイルします。

ただし、これらはすべて完全にオープンソースであるため、RTFSのみが可能です。

FreeTypeソリューション

FreeType は、支配的なオープンソースフォントラスタライズライブラリのように見えるため、TrueTypeおよびOpenTypeフォントを使用できるため、最もエレガントなソリューションになります。

例/チュートリアル:

その他のフォントラスタライザ

これらはFreeTypeよりも劣っているように見えますが、より軽量かもしれません。

アントンのOpenGL 4チュートリアルの例26「ビットマップフォント」

フォントは作成者が手動で作成し、単一の.pngファイル。文字は画像内に配列形式で保存されます。

この方法はもちろんあまり一般的ではなく、国際化には困難が伴います。

ビルド:

make -f Makefile.linux64

出力プレビュー:

enter image description here

opengl-tutorial chapter 11 "2D fonts"

テクスチャは DDSファイルから生成されます

チュートリアルでは、 [〜#〜] cbfg [〜#〜] および Paint.Net を使用して、DDSファイルの作成方法を説明します。 。

出力プレビュー:

enter image description here

何らかの理由でスザンヌが私のために行方不明ですが、時間カウンターは正常に動作します: https://github.com/opengl-tutorials/ogl/issues/15

FreeGLUT

GLUTにはglutStrokeCharacterがあり、FreeGLUTはオープンソースです... https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255

OpenGLText

https://github.com/tlorach/OpenGLText

TrueTypeラスター。 NVIDIAの従業員による。再利用性を目指しています。まだ試していません。

ARM Mali GLES SDKサンプル

http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/ は、PNG上のすべての文字をエンコードし、そこからカットするようです。

SDL_ttf

enter image description here

ソース: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c

SDLとは別のツリーにあり、簡単に統合できます。

ただし、テクスチャアトラスの実装は提供されないため、パフォーマンスが制限されます: SDL2でフォントとテキストを効率的にレンダリングする方法

関連するスレッド

プレーンなOpenGLでテキストを描画するのは簡単な作業ではありません。これを行うには、おそらくライブラリをご覧ください(ライブラリを使用するか、実装例として)。

いくつかの良い出発点は、 GLFontOpenGL Font Survey および ビットマップフォント(NeHeチュートリアル) です。

フォント調査で述べたように、OpenGLでテキストを取得する唯一の方法はビットマップではないことに注意してください。

8
larsmoa

enter image description here

glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString)を使用します。

例:A STAR WARS SCROLLER。

#include <windows.h>
#include <string.h>
#include <GL\glut.h>
#include <iostream.h>
#include <fstream.h>

GLfloat UpwardsScrollVelocity = -10.0;
float view=20.0;

char quote[6][80];
int numberOfQuotes=0,i;

//*********************************************
//*  glutIdleFunc(timeTick);                  *
//*********************************************

void timeTick(void)
{
    if (UpwardsScrollVelocity< -600)
        view-=0.000011;
    if(view < 0) {view=20; UpwardsScrollVelocity = -10.0;}
    //  exit(0);
    UpwardsScrollVelocity -= 0.015;
  glutPostRedisplay();

}


//*********************************************
//* printToConsoleWindow()                *
//*********************************************

void printToConsoleWindow()
{
    int l,lenghOfQuote, i;

    for(  l=0;l<numberOfQuotes;l++)
    {
        lenghOfQuote = (int)strlen(quote[l]);

        for (i = 0; i < lenghOfQuote; i++)
        {
          //cout<<quote[l][i];
        }
          //out<<endl;
    }

}

//*********************************************
//* RenderToDisplay()                       *
//*********************************************

void RenderToDisplay()
{
    int l,lenghOfQuote, i;

    glTranslatef(0.0, -100, UpwardsScrollVelocity);
    glRotatef(-20, 1.0, 0.0, 0.0);
    glScalef(0.1, 0.1, 0.1);



    for(  l=0;l<numberOfQuotes;l++)
    {
        lenghOfQuote = (int)strlen(quote[l]);
        glPushMatrix();
        glTranslatef(-(lenghOfQuote*37), -(l*200), 0.0);
        for (i = 0; i < lenghOfQuote; i++)
        {
            glColor3f((UpwardsScrollVelocity/10)+300+(l*10),(UpwardsScrollVelocity/10)+300+(l*10),0.0);
            glutStrokeCharacter(GLUT_STROKE_ROMAN, quote[l][i]);
        }
        glPopMatrix();
    }

}
//*********************************************
//* glutDisplayFunc(myDisplayFunction);       *
//*********************************************

void myDisplayFunction(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
  gluLookAt(0.0, 30.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  RenderToDisplay();
  glutSwapBuffers();
}
//*********************************************
//* glutReshapeFunc(reshape);               *
//*********************************************

void reshape(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60, 1.0, 1.0, 3200);
  glMatrixMode(GL_MODELVIEW);
}

//*********************************************
//* int main()                                *
//*********************************************


int main()
{
    strcpy(quote[0],"Luke, I am your father!.");
    strcpy(quote[1],"Obi-Wan has taught you well. ");
    strcpy(quote[2],"The force is strong with this one. ");
    strcpy(quote[3],"Alert all commands. Calculate every possible destination along their last known trajectory. ");
    strcpy(quote[4],"The force is with you, young Skywalker, but you are not a Jedi yet.");
    numberOfQuotes=5;

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 400);
    glutCreateWindow("StarWars scroller");
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glLineWidth(3);

    glutDisplayFunc(myDisplayFunction);
    glutReshapeFunc(reshape);
    glutIdleFunc(timeTick);
    glutMainLoop();

    return 0;
}
8

この記事 は、さまざまな手法を使用してOpenGLでテキストをレンダリングする方法を説明しています。

Openglのみを使用する場合、いくつかの方法があります。

  • glBitmapを使用して
  • テクスチャを使用する
  • ディスプレイリストを使用する
6
BЈовић

テクスチャとして文字を含む画像をロードし、必要な文字に応じてそのテクスチャの一部を描画します。ペイントプログラムを使用してそのテクスチャを作成したり、ハードコードしたり、ウィンドウコンポーネントを使用して画像に描画したり、システムフォントの正確なコピー用にその画像を取得したりできます。

Glutやその他の拡張機能を使用する必要はありません。基本的なOpenGL操作性だけです。数十年にわたり、非常に成功したゲームやその他のアプリケーションでプロのプログラマーによってこのように行われたことは言うまでもなく、仕事が完了します。

2
RolanDecoy

OpenGLでテキストを描画するための最適なソリューションはテクスチャフォントだと思います。柔軟性があり、高速で、見た目もきれいです(いくつかの例外を除きます)。フォントファイル(たとえば、.ttf)をテクスチャに変換するための特別なプログラムを使用します。これは、いくつかの内部「フォント」形式のファイルに保存されます( http://content.gpwikiに基づく形式とプログラムを開発しました.org/index.php/OpenGL:Tutorials:Font_System 私のバージョンは、Unicodeをサポートするオリジナルなどとはかなり異なります)。メインアプリを起動すると、フォントはこの「内部」形式からロードされます。詳細については上記のリンクをご覧ください。

このようなアプローチでは、メインアプリはFreeTypeのような特別なライブラリを使用しません。これは私にとっても望ましくありません。テキストは、標準のOpenGL関数を使用して描画されています。

1
Yury