四边形上的输出纹理不正确 [英] Incorrect output texture on quad

查看:89
本文介绍了四边形上的输出纹理不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用freetype在我的应用程序中显示文本.起初我以为是内置函数(对于打算绘制文本的库来说,这是很自然的).但是只有一个显示符号的功能,然后我决定将这些字符一个一个地放入纹理中.但是再次让我感到失望的是:所有引导一个纹理使用单个图像(可能glTexSubImage2D可以帮助我吗?)现在我在opengl元素的纹理和纹理上放置一个符号这是我的代码(相当混乱,但是现在我我只是想了解它是如何工作的):

I'm trying to display the text in my application using freetype. At first I thought that this built-in function (which would be quite natural for the library intended to draw the text). But there was only a function to display the symbol.Then I decided to take the characters one by one into a texture. But here again I was disappointed: all guides one texture uses a single image (probably glTexSubImage2D can help me?).Now I put a symbol on the texture and texture to opengl element.Here's my code (it's quite messy, but now I'm just trying to understand how it works):

//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():

and from 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"从左到上从左向右移动).

As you can see the "O" and "T" is correct (if I change bottom left and top right corners of texture it will be absolutely correct). But other symbols seems like shifted (for example "E" is shifted at left from top to bottom).

完整代码:

#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;
}

推荐答案

我一直在研究这个问题,虽然这个答案可能不完整,但也许可以帮助您解决问题.

I have been looking into this for a bit, and while this answer is possibly incomplete, maybe it can help you figure it out.

在获得所发现的内容之前,我需要指出您的纹理坐标存在问题.你有这个:

Before I get to what I have found, I need to point out a problem with your texture coordinates. You have this:

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将左上角视为其起源.

note how the top left corresponds to 0, 0 in texture coordinates, and 1, 1 corresponds to the bottom right. This is because (kind of guessing here) freetype puts treats the top left as its origin.

Freetype不会生成尺寸必须为2的幂的位图,这通常是mipmapping所必需的(请参阅: https: //gamedev.stackexchange.com/a/7929 ).

Freetype will not generate a bitmap whose dimensions are necessarily power-of-two, which is often required for mipmapping (see: https://gamedev.stackexchange.com/a/7929 ).

因此,如果您要测试此内容(注意:请不要在代码中实际使用;这仅用于说明),则可以将display中的gluBuild2DMipmaps调用替换为以下内容(请确保#include <cstring>:

So if you want to test this (note: do not actually use this in your code; this is only for illustration) you can replace your gluBuild2DMipmaps call in display with the following (be sure to #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字节缓冲区的左上角,然后从中构建mipmap.结果是:

What it does is copy the bitmap buffer to the upper left corner of a different 64x64-byte buffer, and then builds the mipmaps from that. This is the result:

我的插图代码很糟糕,因为它在每次重绘时都会复制每个字形的位图数据,并且没有考虑位图缓冲区的实际大小,或者如果间距大于64.您可能也不想也可以在每次重绘时都(重新)生成mipmap,但是,如果您只是想学习如何将单词导入OpenGL,则不必担心:)

My illustration code is bad because it copies the bitmap data for each glyph every redraw, and it does not take into account the actual size of the bitmap buffer, or if pitch is greater than 64. You also probably do not want to be (re)generating your mipmaps every redraw, either, but if you are just trying to learn how to get words into OpenGL do not worry about it :)

因为我没有您的字体,所以我不得不使用与您不同的字体.

I had to use a different font than you because I do not have yours.

这篇关于四边形上的输出纹理不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆