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