0

I am writing text module for OpenGL engine using NVidia Path extension (NV Path). The extension allows loading system and external font files using trutype metrics. Now, I need to be able to set a standard font size (in pixels) for the glyphs when rendering the text. By default the loaded glyph has EMscale = 2048. Searching for glyph metrics-to-pixels conversion I have found this:

Converting FUnits to pixels

Values in the em square are converted to values in the pixel coordinate system by multiplying them by a scale. This scale is: pointSize * resolution / ( 72 points per inch * units_per_em )

So units_per_em equals 2048, pointSize and resolution are the unknowns I can't resolve.How do I get the resolution value for the viewport width and height to get into this equation? Also, what should be the point size if my input is the pixel size for the font?

I tried to solve this equation with different kind of input but my rendered text gets always smaller (or bigger) than the reference text (AfterEffects).

NV_Path docs refer to FreeType2 metrics. The reference says:

The metrics found in face->glyph->metrics are normally expressed in 26.6 pixel format (i.e., 1/64th of pixels), unless you use the FT_LOAD_NO_SCALE flag when calling FT_Load_Glyph or FT_Load_Char. In this case, the metrics will be expressed in original font units.

I tried to scale down the text model matrix by 1/64. It approximates to the correct size but still not perfect.

Here is how I currently setup the text rendering in the code:

            emScale=2048;

        glyphBase = glGenPathsNV(1+numChars);
    pathTemplate= ~0;
    glPathGlyphRangeNV(glyphBase,GL_SYSTEM_FONT_NAME_NV,
        "Verdana",GL_BOLD_BIT_NV,0,numChars,GL_SKIP_MISSING_GLYPH_NV,pathTemplate,emScale);


    /* Query font and glyph metrics. */
    glGetPathMetricRangeNV(
        GL_FONT_Y_MIN_BOUNDS_BIT_NV|
        GL_FONT_Y_MAX_BOUNDS_BIT_NV|
        GL_FONT_X_MIN_BOUNDS_BIT_NV|
        GL_FONT_X_MAX_BOUNDS_BIT_NV|
        GL_FONT_UNDERLINE_POSITION_BIT_NV|
        GL_FONT_UNDERLINE_THICKNESS_BIT_NV,glyphBase+' ' ,1 ,6*sizeof(GLfloat),font_data);


    glGetPathMetricRangeNV(GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV,
        glyphBase,numChars,0,horizontalAdvance);

    /* Query spacing information for example's message. */

    messageLen = strlen(message);
    xtranslate =(GLfloat*)malloc(sizeof(GLfloat) *messageLen);
    if(!xtranslate){
        fprintf(stderr, "%s: malloc of xtranslate failed\n", "Text3D error");
        exit(1);
    }

    xtranslate[0] = 0.0f;  /* Initial xtranslate is zero. */
    /* Use 100% spacing; use 0.9 for both for 90% spacing. */
    GLfloat advanceScale = 1.0f,
        kerningScale = 1.0f; 

    glGetPathSpacingNV(GL_ACCUM_ADJACENT_PAIRS_NV,
        (GLsizei)messageLen,GL_UNSIGNED_BYTE,message,glyphBase,
        advanceScale,kerningScale,GL_TRANSLATE_X_NV,&xtranslate[1]); /* messageLen-1 accumulated translates are written here. */

    const unsigned char *message_ub = (const unsigned char*)message;
    totalAdvance = xtranslate[messageLen-1] +
        horizontalAdvance[message_ub[messageLen-1]];
    xBorder = totalAdvance / messageLen;

    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_NOTEQUAL ,0 ,~0);
    glStencilOp(GL_KEEP,GL_KEEP,GL_ZERO);


    ////////// init matrices  /////////////

    translate(model ,vec3(0));
    translate(view  ,vec3(0));

                    float nearF=1 ,farF = 1200;
            glViewport(0,0,_viewPortW,_viewPortH);
        glMatrixLoadIdentityEXT(GL_PROJECTION);


        float aspect_ratio =(float) _viewPortW /(float) _viewPortH;
        glMatrixFrustumEXT(GL_PROJECTION ,-aspect_ratio,aspect_ratio,-1 ,1 ,nearF,farF);





        model=translate(model,vec3(0.0f,384.0,0.0f));//move up
            //scale by 26.6 also doesn't work:
    model=scale(model,vec3((1.0f/26.6f),1.0f/26.6f,1.0f/26.6f));
    view=lookAt(vec3(0,0,0),vec3(0,0,-1),vec3(0,1,0));

}
4

1 回答 1

1

The resolution is device dependent and using your equation given as DPI (dots per inch). point_size is the size of the font, choosen by the user in Points. A Point = 1/72 Inch (actually this is the size of a Point as used in PostScript, the actual unit "Point" as used by typesetters is slightly different).

The device resolution can be queried using OS dependent methods. Google for "Display DPI $NAMEOFOPERATINGSYSTEM". Using a size in points this gives you constant physical font sizes independent of the used display device.

Note that when rendering with OpenGL you'll still go through the transformation pipeline which must be accounted for.

于 2013-04-30T21:01:04.150 回答