2012-01-13 80 views
27

我沒有選擇使用除opengl方法以外(即glxxx()方法())。我只需要使用gl方法繪製文本。閱讀紅皮書後,我明白,只有通過glBitmap()方法纔有可能。如果這是唯一可行的方法,那麼任何人都可以幫助我獲得所有字符的像素數組信息。是否有其他方式來繪製文字?如何僅使用OpenGL方法繪製文本?

回答

5

This article描述瞭如何使用各種技術在OpenGL中呈現文本。

由於只有使用OpenGL的,有幾種方法:

  • 使用glBitmap
  • 使用顯示列表
7

純OpenGL繪圖文字不是straigth-使用紋理

  • 前向任務。你可能應該看看這樣做的庫(通過使用庫或作爲示例實現)。

    一些很好的起點可能是GLFont,OpenGL Font SurveyNeHe Tutorial for Bitmap Fonts (Windows)

    請注意,位圖不是在字體調查中提到的在OpenGL中實現文本的唯一方法。

  • +0

    感謝訥河教程鏈接 – befzz 2014-08-09 15:36:02

    1

    我認爲在OpenGL中繪製文本的最佳解決方案是紋理字體,我與他們合作了很長時間。他們靈活,快速和漂亮的外觀(有一些例外)。我使用特殊程序將字體文件(例如.ttf)轉換爲紋理,保存爲一些內部「字體」格式的文件(我已經開發了基於http://content.gpwiki.org/index.php/OpenGL:Tutorials:Font_System的格式和程序,儘管我的版本與原始支持相差甚遠Unicode等)。啓動主應用程序時,字體將從此「內部」格式加載。查看上面的鏈接瞭解更多信息。

    使用這種方法,主應用程序不使用任何特殊的庫,如FreeType,這對我也是不可取的。正在使用標準的OpenGL函數繪製文本。

    +0

    如果我可以添加一些東西給這個alrea DY很好的答案,要注意任何字體渲染系統的optmization,因爲它可能非常有限的HW資源,如移動設備影響您的發動機的性能。 – 2012-01-13 09:48:34

    8

    enter image description here

    使用glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString)

    例如:星球大戰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; 
    } 
    
    +46

    glutStrokeCharacter不是opengl函數 – 2013-05-16 12:04:59

    +15

    它適合於glxxx()OP的要求,雖然:) – AndroidGecko 2013-11-03 18:58:19

    +1

    這裏的代碼被修改爲在Ubuntu上工作(glutInit,包括):https://gist.github.com/tgandor/3963f112324030a2c833 – 2015-03-17 15:30:14

    2

    加載一個帶有字符的圖像作爲紋理,並根據您想要的字符繪製該紋理的一部分。您可以使用繪圖程序創建該紋理,對其進行硬編碼或使用窗口組件繪製圖像並檢索該圖像以獲取系統字體的精確副本。

    無需使用Glut或任何其他擴展,只需基本的OpenGL可操作性。它完成了這項工作,更不用說數十年來由專業程序員在非常成功的遊戲和其他應用程序中這樣做了。

    +1

    甚至有一些程序可以用來爲您生成圖像紋理。 – fintelia 2014-07-17 17:41:18

    36

    理論

    爲什麼很難

    流行的字體格式,如TrueType和OpenType是矢量輪廓格式:他們用貝塞爾曲線來定義字母的邊界。

    Image source

    轉化這些格式轉換爲像素陣列(光柵化)是過於具體,從OpenGL的範圍,特別是因爲OpenGL的沒有非直語(例如見Why is there no circle or ellipse primitive in OpenGL?

    最簡單的方法是先光柵字體我們自己在CPU上,然後將像素數組作爲紋理賦予OpenGL。

    然後OpenGL知道如何通過紋理非常好地處理像素數組。

    紋理圖集

    我們可以光柵字符,每幀並重新創建的紋理,但不是非常有效,特別是如果字符大小是固定的。

    更有效的方法是將您計劃使用的所有字符柵格化並將其填充到單個紋理中。

    然後將其傳輸到GPU一次,並使用它與自定義uv座標的紋理來選擇正確的字符。

    這種方法被稱爲https://en.wikipedia.org/wiki/Texture_atlas,它不僅可用於紋理,還可用於其他重複使用的紋理,如2D遊戲中的貼圖或Web UI圖標。

    質感十足的維基百科圖片,這是本身的FreeType-GL拍攝,說明了這口井:

    我懷疑優化字符的位置,以最小的結構問題是一個NP問題,請參閱:What algorithm can be used for packing rectangles of different sizes into the smallest rectangle possible in a fairly optimal way?

    Web開發中使用同樣的技術來一次傳輸幾個小圖像(如圖標),但它被稱爲「CSS Sprites」:https://css-tricks.com/css-sprites/並用於隱藏網絡延遲而不是那個CPU/GPU通信。

    非CPU光柵方法

    也存在不使用的CPU光柵到紋理的方法。

    CPU rastering很簡單,因爲它儘可能少地使用GPU,但我們也開始考慮是否可以進一步使用GPU效率。

    這FOSDEM 2014視頻https://youtu.be/LZis03DXWjE?t=886說明其他現有技術:

    字體的3D幾何結構的內側透視

    渲染與立體三維幾何的內部字體(相比於正交HUD )要複雜得多,因爲透視可以使角色的一部分更接近屏幕和la比另一個更高,從而實現統一的CPU離散化(例如,光柵,鑲嵌)在關閉部分看起來不好。這實際上是一個活躍的研究課題:

    enter image description here

    距離場是現在流行的技術之一。

    實現

    下面的示例是在Ubuntu 15.10所有測試。

    因爲這是如前面所討論的複雜問題,大多數的例子是大,會炸掉這個答案的30K字符的限制,所以只克隆各自的Git代碼庫進行編譯。

    但它們都是完全開源的,所以你可以只用RTFS。

    FreeType的解決方案

    FreeType貌似主導開源字體光柵化庫,所以這將允許我們使用TrueType和OpenType字體,使之成爲最完美的解決方案。

    例子/教程:

    個其他字體光柵化

    那些似乎比FreeType的那麼好,但可能更輕巧:

    安東的OpenGL 4教程實例26 「位圖字體」

    的字體是由作者手動創建並且存儲在單個文件.png。字母在圖像內以數組形式存儲。

    這種方法當然不是很一般,而且你會遇到國際化的困難。

    建設有:

    make -f Makefile.linux64 
    

    輸出預覽:

    enter image description here

    OpenGL的教程第11章 「2D字體」

    紋理是從DDS files生成。

    本教程介紹瞭如何使用CBFGPaint.Net創建DDS文件。

    輸出預覽:

    enter image description here

    出於某種原因,蘇珊缺少我,但時間計數器工作正常:https://github.com/opengl-tutorials/ogl/issues/15

    FreeGLUT

    過多已經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 SDK GLES樣品

    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,並可以輕鬆集成。

    不提供紋理圖集實施然而,這樣的表現將受到限制:Rendering fonts and text with SDL2 efficiently

    相關主題