4. glViewport 和 gluOrtho2D

博客参考: http://jiangcs2010.blog.sohu.com/165071219.html && http://blog.sina.com.cn/s/blog_4e6f376d0100c0o2.html

定义视口大小:glViewport (GLint x, GLint y, GLsizei width, GLsizei height) ,默认是(0,0,窗口的宽度,窗口的高度), (x, y)是视口左下角在窗口里位置的坐标, (0, 0)是窗口左下角,w、h是视口的宽和高, 截图就在窗口这一部分进行显示.

截取图像大小:gluOrtho2D(x_mix, x_max, y_mix, y_max), 用来指定屏幕区域对应的模型坐标范围,我们自己所绘制的图形的坐标必须在这个范围内,不然不能看到自己绘制的图形。在没调用gluOthor2d函数之前,坐标范围是 X:-1 - 1,Y:-1 - 1;调用了这个函数之后坐标范围是 X:x_mix - x_max,Y: y_mix - y_max。其实就是截取空间中某个平行六面体形成的空间内的模型到视口范围内进行显示,范围比模型所在空间稍大即可,太小导致模型显示不全,太大导致模型显得太小。

#include <gl/glut.h>

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 0.0, 0.0);
    //画分割线,分成四个视见区
    glViewport(0, 0, 400, 400);
    glBegin(GL_LINES);
    glVertex2f(-1.0, 0);
    glVertex2f(1.0, 0);
    glVertex2f(0.0, -1.0);
    glVertex2f(0.0, 1.0);
    glEnd();

    //定义在左下角的区域
    glColor3f(0.0, 1.0, 0.0);
    glViewport(0, 0, 200, 200);
    glBegin(GL_POLYGON);
    glVertex2f(-0.5, -0.5);
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, 0.5);
    glVertex2f(0.5, -0.5);
    glEnd();

    //定义在右上角的区域
    glColor3f(0.0, 0.0, 1.0);
    glViewport(200, 200, 200, 200);//注意,后面这两个参数是高度和宽度,而不是坐标
    glBegin(GL_POLYGON);
    glVertex2f(-0.5, -0.5);
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, 0.5);
    glVertex2f(0.5, -0.5);
    glEnd();

    //定义在左上角的区域
    glColor3f(1.0, 0.0, 0.0);
    glViewport(0, 200, 200, 200);//注意,后面这两个参数是高度和宽度,而不是坐标
    glBegin(GL_POLYGON);
    glVertex2f(-0.5, -0.5);
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, 0.5);
    glVertex2f(0.5, -0.5);
    glEnd();

    //定义在右下角
    glColor3f(1.0, 1.0, 1.0);
    glViewport(200, 0, 200, 200);//注意,后面这两个参数是高度和宽度,而不是坐标
    glBegin(GL_POLYGON);
    glVertex2f(-0.5, -0.5);
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, 0.5);
    glVertex2f(0.5, -0.5);
    glEnd();
    glFlush();
}

void init()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glColor3f(1.0, 1.0, 1.0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //定义剪裁面
    gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
}

int main(int argc, char** argv)
{
    glutInit(&argc, (char**)argv);
    glutInitDisplayMode(GLUT_SINGLE| GLUT_RGB);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("openGL");
    glutDisplayFunc(display);
    init();

    glutMainLoop();//enters the GLUT event processing loop.  
    return 0;
}

显示效果入下

OpenGL 绘图的机制是: 先用 OpenGL 的绘图上下文 Rendering Context (简称为 RC )把图画好,再把所绘结果通过 SwapBuffer() 函数传给 Window 的 绘图上下文 Device Context (简记为 DC).要注意的是,程序运行过程中,可以有多个 DC,但只能有一个 RC。因此当一个 DC 画完图后,要立即释放 RC,以便其它的 DC 也使用。

glFlush:将GL命令队列中的命令发送给显卡并清空命令队列,发送完立即返回;

glFinish:将GL命令队列中的命令发送给显卡并清空命令队列,显卡完成这些命令(也就是画完了)后返回。因此,在绘图命令比较冗长的情况下,可以分段调用glFlush以清空命令队列并让显卡开始先执行这些命令,最后调用glFinish来同步。举个例子:我的渲染器一共有9种shader,渲染时从shader0一直渲染到shader8,以前是在所有shader渲染完成后才调用glFinish(注意:这里如果把glFinish换成glFlush,那么调用wglSwapBuffer的时候在不同的平台上会产生不同的结果,具体结果我也不清楚,个人感觉好像没什么问题,但是游戏的时钟系统会被扰乱——最明显的就是帧速算错),那么CPU就要等GPU绘图,浪费了大把大把的时间;现在改成每个shader完成后调用一次glFlush,强制GPU开始执行命令队列中的GL命令,最后调用glFinish等待GPU完成当前帧渲染,然后调用wglSwapBuffer调换前后缓存。

这里就会发现这样一件事情:无论如何,都要等glFinish返回了,如果GPU绘制需要比较多的时间,那么CPU在这里等待的时间就比较可观了,如何提高CPU效率呢?个人认为有两个办法:

1、使用多线程。将更新和渲染作为线程A,辅助性计算如AI策略、**图生成作为线程B。那么当线程A因为glFinish阻塞时,线程B便可以利用CPU进行计算。

2、使用CPU时间预算方法。即先给出一帧所需要的时间预算,在调用glFinish之前判断是否还有多的时间预算,若有多,则先作辅助计算,完成或超过预算时间后才调用glFinish(若此时GPU已经完成命令,就不需要等待了)

对于SwapBuffers,SwapBuffer命令只是把前台和后台的缓冲区指针交换一下而已也就是把前台的内容变成后台缓冲的内容,把后台的缓冲内容换到了前台这个函数它本身并不对换过来的成为了后台的buffer做清理工作,所以每帧都glClear一次,然后再绘制,而后再SwapBuffers。

posted @ 2020-05-06 23:43  采男孩的小蘑菇  阅读(388)  评论(0编辑  收藏  举报