如何同时在OpenGL屏幕上显示形状和文字?

时间:2016-08-09 17:46:38

标签: c++ opengl text textures screen

以下代码完美无缺,没有致命错误但是,当我使用参数" w"," h" in" gluortho2d"作为重塑函数中的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;
}

2 个答案:

答案 0 :(得分: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();
}

更新(由于请求中的内容):

为什么在重塑处理程序中设置视口和投影参数是错误的?嗯,你刚才经历过这样的理由:他们不是"一个尺寸适合所有"状态和整个渲染稍微复杂的帧,不仅仅是绘制的网格,你想要在整个渲染过程中混合和匹配不同的视口和投影。这是一个(不完整的)列表,在渲染单个帧时需要具有不同的视口和投影:

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

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

a)在重塑处理程序中设置它的意义为零:无论处理程序集将仅在第一帧的绘制开始时设置,此后框架绘图代码本身必须重置为重塑处理程序设置的内容。那么为什么还要在重塑处理程序中麻烦呢?

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

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

答案 1 :(得分:0)

你可以让这更简单。对于您正在做的事情,根本不需要为设置转换而烦恼。

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

调用时框渲染适用于您的原因:

setIntent(null);

是这次调用会导致错误,如man page

所述
  

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

因此会保持默认值不变,这正是您所需要的。

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

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

总结如下:

  • 删除所有glWindowPos*()来电。
  • 删除所有glMatrixMode()来电。
  • 删除所有glLoadIdentity()来电。
  • gluOrtho2D()中,将drawBitmapText()来电替换为:

    glRasterPos3f()

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

glWindowPos2f(x, y);

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