OpenGL边用边学------2 OpenGL状态、视口设置
2015-12-14 08:47
459 查看
OpenGL的状态管理机制
视口与视口坐标系概念
测试视口设置
1 移动视口
2 多视口
视口小结
OpenGL的渲染需要很多的状态数据来供其使用,如果把所有的这些数据都作为参数传递给渲染函数的话,那么此函数的样子大概是这样的。
这对于客户端使用来说,简直就是场噩梦啊!由于大多数渲染行为都需要这些状态数据,所以O彭GL干脆把这些大家都使用的数据做成了全局变量,供所有渲染函数使用。这样就可以把渲染函数简化成了
当然了,全局变量也带来了渲染函数不可重入的问题,还好在OpenGL中,函数重入不算重要。人们习惯称这种使用了大量全局状态数据的程序为状态机。
其实好多库都采取了状态机的机制,如Windows GDI。
注意:视口坐标系与Windows的窗口坐标系是不同的。
OpenGL用来设置视口的函数是:
函数参数都是针对视口坐标系的。例如
设置的视口位置及大小如下图所示:
每一次渲染的执行(glBegin()和glEnd()中间的代码)都是把当前视口作为最终输出目的地。视口也是OpenGL内部维护的状态变量之一,它可以在一帧的渲染中多次改变,OpenGL在执行渲染时都是使用当前的视口。窗口客户区可以被分割为多个视口,但是同一时刻只有一个视口生效。
在初始化OpenGL窗口环境时,视口被设置为布满整个客户区。
在WM_PAINT的事件处理中,通过绘制布满整个可视空间的矩形来标注出当前的视口位置与大小。注意:我们绘制时使用了默认的颜色状态(白色)。
这样,每当在客户区点击一下鼠标,当前的视口区域就会被标注出来。
源码下载
这样我们就得到了两个不同的视口A,B。最终A和B组成了一帧完整的图像。
我们的程序现在还不能渲染出这么复杂的场景,那么就用简单的颜色矩形来表示吧。
修改渲染函数如下:
源码下载
视口与视口坐标系概念
测试视口设置
1 移动视口
2 多视口
视口小结
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 视口小结
视口是OpenGL里最简单的概念,视口坐标系是唯一一个与窗口环境有关的坐标系。大多数程序,使用一个视口就够了,最可能的情况就是在WM_SIZE的事件响应中自动调整视口大小,使其始终布满整个窗口客户区。void OnSize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int cx = LOWORD(lParam); int cy = HIWORD(lParam); glViewport(0, 0, cx, cy); }
相关文章推荐
- 解决Vista系统OpenGL驱动问题的方法整理
- Delphi下OpenGL2d绘图之画四边形的方法
- Delphi下OpenGL2d绘图之画点的方法
- Delphi下OpenGL2d绘图之初始化流程详解
- Delphi使用OpenGL2d绘图之画图片Bmp的方法
- 通过OpenGL ES混合模式缩放视频缓冲区来适应显示尺寸
- VC运用OPENGL加载BMP纹理图的实现方法汇总
- java实现OpenGL ES纹理映射的方法
- java基于OpenGL ES实现渲染实例
- OpenGL坐标系介绍
- linux下opengl的安装(with qt)
- OpenGL超级宝典笔记——显示列表
- OpenGL超级宝典笔记——顶点数组
- OpenGL生成轮廓
- OpenGL超级宝典笔记——性能比较
- OpenGL超级宝典笔记——顶点缓冲区对象
- OpenGL超级宝典笔记——选择
- OpenGL超级宝典笔记——反馈
- OpenGL超级宝典笔记——遮挡查询
- OpenGL超级宝典笔记——深度纹理和阴影