C++ 四边形上的输出纹理不正确

C++ 四边形上的输出纹理不正确,c++,opengl,glut,freetype,C++,Opengl,Glut,Freetype,我正在尝试使用freetype在应用程序中显示文本。起初我认为这个内置函数(对于打算绘制文本的库来说这是很自然的)。但是只有一个功能来显示符号,然后我决定把这些字符一个接一个地放到一个纹理中。但在这里,我再次感到失望:一个纹理使用一个图像(可能glTexSubImage2D可以帮助我吗?)。现在,我在纹理上添加了一个符号,并将纹理添加到opengl元素。下面是我的代码(它相当混乱,但现在我只是想了解它是如何工作的): 并从display()中: void display() { glClear(

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

并从display()中:

void display()
{
glClear(GLU颜色缓冲位);
glClearColor(1.0,1.0,1.0,0.0);
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
glLoadIdentity();//加载标识矩阵
std::string s=“QWERTYOG0l”;
对于(int i=0;i字形;
glTexParameteri(GL_纹理_2D,GL_纹理_最小_过滤器,GL_线性);//线性过滤
glTexParameteri(GL_纹理_2D,GL_纹理_MAG_过滤器,GL_线性);//线性过滤
//glTexParameteri(GL_纹理2D、GL_纹理包裹S、GL_重复);
gluBuild2DMipmaps(GL_纹理_2D,
甘蓝红,
g->位图宽度,
g->bitmap.rows,
甘蓝红,
GL_无符号字节,
g->bitmap.buffer);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f);glVertex3f(0.1f*i-0.1,0.07f,0.0f);//左上角
glTexCoord2f(0.0f,1.0f);glVertex3f(0.1f*i,0.07f,0.0f);//右上角
glTexCoord2f(1.0f,1.0f);glVertex3f(0.1f*i,-0.07f,0.0f);//右下角
glTexCoord2f(1.0f,0.0f);glVertex3f(0.1f*i-0.1,-0.07f,0.0f);//左下角
格伦德();
}

正如您所看到的,“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;
}
#包括
#包括
#包括
#包括
#包括
#包括FT_FREETYPE_H
图书馆;
面部;
const char*fontfilename=“LucidaTypewriterBold.ttf”;
胶合纹理[10];
闪烁均匀的纹理;
int setup(){
if(FT_Init_FreeType(&FT)){
fprintf(stderr,“无法初始化freetype库\n”);
返回0;
}
if(FT_新_面(FT、fontfilename、0和面)){
fprintf(stderr,“无法打开字体%s\n”,fontfilename);
返回0;
}
FT_设置_像素_大小(面,0,48);
FT_Load_Char(面“O”,FT_Load_RENDER);
FT_字形槽g=面->字形;
glGenTextures(1,&纹理[0]);//创建纹理
glBindTexture(GL_TEXTURE_2D,纹理[0]);
glTexParameteri(GL_纹理_2D,GL_纹理_最小_过滤器,GL_线性);//线性过滤
glTexParameteri(GL_纹理_2D,GL_纹理_MAG_过滤器,GL_线性);//线性过滤
//glTexParameteri(GL_纹理2D、GL_纹理包裹S、GL_重复);
gluBuild2DMipmaps(GL_纹理2D,GL_RGBA,g->bitmap.width,g->bitmap.rows,GL_红色,GL_无符号字节,g->bitmap.buffer);
返回1;
}
无效显示()
{
glClear(GLU颜色缓冲位);
glClearColor(1.0,1.0,1.0,0.0);
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
glLoadIdentity();//加载标识矩阵
std::string s=“QWERTYOG0l”;
对于(int i=0;i字形;
glTexParameteri(GL_纹理_2D,GL_纹理_最小_过滤器,GL_线性);//线性过滤
glTexParameteri(GL_纹理_2D,GL_纹理_MAG_过滤器,GL_线性);//线性过滤
//glTexParameteri(GL_纹理2D、GL_纹理包裹S、GL_重复);
gluBuild2DMipmaps(GL_纹理_2D,
甘蓝红,
g->位图宽度,
g->bitmap.rows,
甘蓝红,
GL_无符号字节,
g->bitmap.buffer);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f);glVertex3f(0.1f*i-0.1,0.07f,0.0f);//左上角
glTexCoord2f(0.0f,1.0f);glVertex3f(0.1f*i,0.07f,0.0f);//右上角
glTexCoord2f(1.0f,1.0f);glVertex3f(0.1f*i,-0.07f,0.0f);//右下角
glTexCoord2f(1.0f,0.0f);glVertex3f(0.1f*i-0.1,-0.07f,0.0f);//左下角
格伦德();
}
//玻璃纹理(GL_纹理0);
//glBindTexture(GL_TEXTURE_2D,纹理[0]);//选择我们的纹理
//glUniform1i(均匀纹理,/*GL纹理*/0);
再发现();
glutSwapBuffers();
}
无效时间函数(int值)
{
}
int main(int argc,char*argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_深度| GLUT_双精度);
glutInitWindowSize(800600);
创建窗口(“你好世界”);
//glutTimerFunc(30,TIMERFUNCE,1);
glewInit();
glEnable(GL_纹理_2D);
设置();
glutDisplayFunc(显示器);
glutMainLoop();
返回0;
}

我已经对此进行了一段时间的研究,虽然这个答案可能不完整,但也许它可以帮助您找到答案

初步说明 在我找到之前,我需要指出你的纹理坐标有一个问题。你有:

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不会生成尺寸必须为二次方的位图,这通常是mipmapping所需的(请参阅:)

因此,如果您想测试这一点(注意:不要在代码中实际使用它;这仅用于说明),您可以用以下内容替换
gluBuild2DMipmaps
调用
显示
(请确保
#包括

int pitch=g->bitmap.pitch;
如果(节距<0){
投球=
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
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
);
GLfloat swizzleMask[] = { 0,0,0, GL_RED}; 
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
    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;