JS技术

OpenGL边用边学------2 OpenGL状态、视口设置 - smstong的成长轨迹 - 博客频道 - CSDN

字号+ 作者:H5之家 来源:H5之家 2015-12-14 17:57 我要评论( )

!-- /* default css */table { font-size: 1em; line-height: inherit; border-collapse: collapse;}tr { text-align: left; }div, address, ol, ul, li, option

  • 1 OpenGL的状态管理机制

    从前面的最简单例子可以看出,我们几乎没有进行任何关于颜色和坐标系的配置,OpenGL就已经能够实施渲染了。这是因为OpenGL本身管理了很多渲染时需要的状态数据,并且在初始化时自动设置了合理的默认值。例如,默认的清屏颜色就是黑色,这才是我们看到窗口客户区呈现黑色的原因。

    OpenGL的渲染需要很多的状态数据来供其使用,如果把所有的这些数据都作为参数传递给渲染函数的话,那么此函数的样子大概是这样的。

    glXXX(渲染上下文,颜色,坐标,视口,光照,雾,.....);

    这对于客户端使用来说,简直就是场噩梦啊!由于大多数渲染行为都需要这些状态数据,所以O彭GL干脆把这些大家都使用的数据做成了全局变量,供所有渲染函数使用。这样就可以把渲染函数简化成了

    glXXX(坐标);

    当然了,全局变量也带来了渲染函数不可重入的问题,还好在OpenGL中,函数重入不算重要。人们习惯称这种使用了大量全局状态数据的程序为状态机。

    其实好多库都采取了状态机的机制,如Windows GDI。

    2 视口与视口坐标系概念

    计算机图形学的本质就是创建三维物体的二维图像,涉及到多个坐标系间的转化。本文从最简单的视口坐标系开始。视口(Viewport)就是最终渲染结果显示的目的地。它是一个矩形的区域,长度单位是像素,视口的位置和大小在视口坐标系中定义。视口坐标系是标准的笛卡尔直角坐标系,其原点位于渲染环境窗口客户区的左下角,横轴(x)向右为正,纵轴(y)向上为正。如下图所示:

    视口坐标系

    注意:视口坐标系与Windows的窗口坐标系是不同的。
    OpenGL用来设置视口的函数是:

    void WINAPI glViewport( GLint x, GLint y, GLsizei width, GLsizei height );

    函数参数都是针对视口坐标系的。例如

    glViewport(100,50, 200, 150);

    设置的视口位置及大小如下图所示:

    这里写图片描述

    每一次渲染的执行(glBegin()和glEnd()中间的代码)都是把当前视口作为最终输出目的地。视口也是OpenGL内部维护的状态变量之一,它可以在一帧的渲染中多次改变,OpenGL在执行渲染时都是使用当前的视口。窗口客户区可以被分割为多个视口,但是同一时刻只有一个视口生效。

    在初始化OpenGL窗口环境时,视口被设置为布满整个客户区。

    3 测试视口设置 3.1 移动视口

    我们在WM_LBUTTONDOWN事件的响应中,把视口的左下角坐标设置为鼠标的位置,宽度设置为200像素,高度设置为150像素。然后重新进行OpenGL渲染。

    void OnLeftButtonDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT clientRect; ::GetClientRect(hWnd, &clientRect); int xPos = GET_X_LPARAM(lParam); /* 需要包含 <windowsx.h> */ int yPos = GET_Y_LPARAM(lParam); int x = xPos; /* 把窗口坐标系坐标转换为视口坐标系坐标 */ int y = clientRect.bottom - yPos; glViewport(x, y, 200, 150); InvalidateRect(hWnd, NULL, TRUE); }

    在WM_PAINT的事件处理中,通过绘制布满整个可视空间的矩形来标注出当前的视口位置与大小。注意:我们绘制时使用了默认的颜色状态(白色)。

    void OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_QUADS); glVertex2d(-1, -1); glVertex2d(1, -1); glVertex2d(1, 1); glVertex2d(-1, 1); glEnd(); HDC hdc = ::GetDC(hWnd); ::SwapBuffers(hdc); ::ReleaseDC(hWnd, hdc); }

    这样,每当在客户区点击一下鼠标,当前的视口区域就会被标注出来。

    视口随鼠标移动


    源码下载

    3.2 多视口

    OpenGL的视口也是其内部维护的众多状态变量之一,在某一次OpenGL的渲染中(glBegin()和glEnd()之间的渲染代码),只能使用当前视口进行输出。但是在一帧图像可以包含任意多次OpenGL渲染,也就是说,程序中可以多次调用glBengin()和glEnd()。例如如下伪代码:

    glViewport(A); glBegin(); 渲染在房子里面看到的场景 glEnd(); glViewport(B); glBegin(); 渲染在外面看房子的场景 glEnd();

    这样我们就得到了两个不同的视口A,B。最终A和B组成了一帧完整的图像。

    这里写图片描述

    我们的程序现在还不能渲染出这么复杂的场景,那么就用简单的颜色矩形来表示吧。
    修改渲染函数如下:

    void OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1, 0, 0); glViewport(0, 0, 300, 300); glBegin(GL_QUADS); glVertex2d(-1, -1); glVertex2d(1, -1); glVertex2d(1, 1); glVertex2d(-1, 1); glEnd(); glColor3f(0, 1, 0); glViewport(250, 250, 300, 300); glBegin(GL_QUADS); glVertex2d(-1, -1); glVertex2d(1, -1); glVertex2d(1, 1); glVertex2d(-1, 1); glEnd(); HDC hdc = ::GetDC(hWnd); ::SwapBuffers(hdc); ::ReleaseDC(hWnd, hdc); }

    多视口


    源码下载

    4 视口小结

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • OpenGL边用边学------1 VS2015最简单OpenGL设置代码 - smstong的成长轨迹 - 博客频道

      OpenGL边用边学------1 VS2015最简单OpenGL设置代码 - smstong的成长

      2015-12-13 11:29

    网友点评
    t