【问题标题】:How to display shape and text on OpenGL screen simultaneously?如何在 OpenGL 屏幕上同时显示形状和文本?
【发布时间】:2016-08-09 17:46:38
【问题描述】:

下面的代码工作得很好,没有致命错误,但是,当我在“gluortho2d”中使用参数“w”,“h”作为 reshape 函数中的 gluortho2d(0,w,h,0) 时,我会在屏幕上看到文本,而如果我将这些参数“0,0”作为 gluortho2d(0,0,0,0) 我得到盒子的形状。 如何在屏幕上同时显示它们(框和文本)?

#include"glut.h"

void drawBitmapText(char *string, float x, float y, float z);
void reshape(int w, int h);
void display(void);

void drawBitmapText(char *string, float x, float y, float z)
{
    char *c;
    glRasterPos3f(x, y, z);//define position on the screen where to draw text.

    for (c = string; *c != '\0'; c++)
    {
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);
    }
}

void reshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();//Resets to identity Matrix.
    gluOrtho2D(0, w, h, 0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

}

void display(void)
{

    glBegin(GL_POLYGON);//1
    glVertex2f(-0.2, 0.6 - 0.3);
    glVertex2f(-0.1, 0.6 - 0.3);
    glVertex2f(-0.1, 0.5 - 0.3);
    glVertex2f(-0.2, 0.5 - 0.3);
    glEnd();


    glColor3f(0, 1, 0);
    drawBitmapText("Usama Ishfaq", 200, 400, 0);//drawBitmapText("Usama Ishfaq", x(how much right), y(how much down), z);

    glutSwapBuffers();
}


int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Usama OGL Window");
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();

    return 0;
}

【问题讨论】:

    标签: c++ opengl text textures screen


    【解决方案1】:

    通过不遵循糟糕的教程并在唯一有效的地方调用glViewport 和投影矩阵设置:显示函数。 在重塑处理程序中设置视口和投影矩阵是一种反图案。不要这样做。

    这样做

    void display(void)
    {
        int const w = glutGet(GLUT_WINDOW_WIDTH);
        int const h = glutGet(GLUT_WINDOW_HEIGHT);
    
        glViewport(0, 0, w, h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();//Resets to identity Matrix.
        gluOrtho2D(-1, 1, -1, 1);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();    
    
        glBegin(GL_POLYGON);//1
        glVertex2f(-0.2, 0.6 - 0.3);
        glVertex2f(-0.1, 0.6 - 0.3);
        glVertex2f(-0.1, 0.5 - 0.3);
        glVertex2f(-0.2, 0.5 - 0.3);
        glEnd();
    
        /* viewport doesn't change in this
         * application, but it's perfectly
         * valid to set a different
         * glViewport(...) here */
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();//Resets to identity Matrix.
        gluOrtho2D(0, w, h, 0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    
        glColor3f(0, 1, 0);
        drawBitmapText("Usama Ishfaq", 200, 400, 0);//drawBitmapText("Usama Ishfaq", x(how much right), y(how much down), z);
    
        glutSwapBuffers();
    }
    

    更新(由于评论中的要求):

    为什么在reshape handler中设置viewport和projection参数会出错?好吧,您自己刚刚经历了原因:它们不是“一刀切”的状态,并且在整个渲染过程中稍微复杂的帧超出了仅绘制的网格,您将希望在整个渲染过程中混合和匹配不同的视口和投影.以下是在渲染单个帧时需要具有不同视口和投影的(不完整)列表:

    • 渲染到纹理 (FBO) - 需要具有纹理边界的视口,并且通常还需要不同的投影(对于阴影映射、动态立方体贴图和许多其他高级多通道渲染技术很重要)
    • 小地图/概览框架或角落中的类似物(视口仅覆盖角落)
    • 文本注释覆盖(不同的投影;通常是简单的恒等变换,以便直接在 NDC 空间中绘制文本矩形)
    • “放大镜”覆盖

    由于在稍微复杂一点的 OpenGL 绘图中会多次更改视口和投影状态,因此

    a) 在 reshape 处理程序中设置它的零意义:无论处理程序设置什么,都将仅在第一帧的绘制开始时设置,此后帧绘制代码本身必须重置为 reshape 处理程序设置的内容.那么,为什么还要费心在重塑处理程序中做呢?

    b) 从长远来看,将视口和投影设置代码放在重塑处理程序中是一种负担,因为它可能会导致程序的其他部分依赖于它。如果发生这种情况,一旦您意识到自己的错误并尝试将该视口和投影设置代码移动到它属于程序的其他部分的位置,这些部分依赖于从重塑处理程序中断中调用它,您也必须修复这些。

    总而言之,没有理由在重塑处理程序中放置任何与绘图相关的调用(并且 glViewport 和投影设置肯定与绘图相关)。当然,“一次性”初始化在那里完全没问题,即,如果您想调整 FBO 渲染目标的大小以匹配窗口,或者如果您想准备一个稍后重复应用的叠加图像。

    【讨论】:

    • 非常感谢你这么好的回答。
    • 如果回答解决并解决了您的问题 - 接受它。
    • 您能准确补充一下为什么在reshape 中执行glViewport 等是不正确的吗?我有点好奇,尽管我从不使用 GLUT。
    【解决方案2】:

    您可以使这变得更简单。对于您正在做的事情,根本不需要设置转换。

    看起来,对于盒子,您正在尝试将 [-1.0, 1.0] 范围内的坐标用于两个坐标方向。这对应于 OpenGL NDC(标准化设备坐标)坐标系,即在应用模型视图和投影变换后的坐标空间顶点。如果将它们保留在默认单位矩阵中,则可以直接在 NDC 空间中指定坐标。换句话说,要使用 [-1.0, 1.0] 范围内的坐标,请……什么都不做,只保留默认值。

    当您调用时,框渲染为您工作的原因:

    gluOrtho2D(0.0, 0.0, 0.0, 0.0);
    

    这个调用是否会导致错误,如man page 中所述:

    如果 left = right、bottom = top、或 near = far,则生成 GL_INVALID_VALUE。

    因此将保持默认设置不变,这正是您所需要的。

    现在,对于文本,您似乎想要以像素为单位指定位置。您遇到的问题是 glRasterPos*() 通过转换管道运行指定的坐标,这意味着,使用默认的身份模型视图和投影转换,它期望输入坐标在 [-1.0, 1.0] 范围内,就像您传递给glVertex2f() 的坐标。

    幸运的是,有一种非常简单的方法可以避免这种情况。有一个非常相似的glWindowPos*() 调用,唯一的区别是传递给它的坐标是窗口坐标,以像素为单位。

    总结一下:

    • 删除所有glMatrixMode() 调用。
    • 删除所有glLoadIdentity() 调用。
    • 删除所有gluOrtho2D() 调用。
    • drawBitmapText() 中,将glRasterPos3f() 调用替换为:

      glWindowPos2f(x, y);
      

    唯一需要注意的是窗口坐标的原点在底部左角。因此,如果您的文本位置是相对于左上角给出的,您将需要以下内容:

    glWindowPos2f(x, windowHeight - y);
    

    要解决另一个答案中的一些误导性信息:只要您对所有渲染使用相同的视口,在 reshape() 函数中调用 glViewport() 就可以了。在更复杂的应用程序中,您通常需要为渲染的不同部分使用不同的视口(例如,当您渲染到 FBO 或仅渲染到窗口的一部分时),因此您需要在渲染期间在适当的位置调用 glViewport()。但是对于一个简单的例子,你对整个窗口进行所有渲染,在reshape() 中调用它并没有错。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-16
      • 2013-10-25
      • 1970-01-01
      • 2017-10-31
      相关资源
      最近更新 更多