OpenGL边用边学------2 OpenGL状态、视口设置

  • OpenGL的状态管理机制
  • 视口与视口坐标系概念
  • 测试视口设置
    • 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);
}
时间: 2024-10-10 08:55:33

OpenGL边用边学------2 OpenGL状态、视口设置的相关文章

[OpenGL红宝书]第一章 OpenGL概述

第一章 OpenGL概述 标签(空格分隔): OpenGL 第一章 OpenGL概述 1 什么是OpenGL 2 初识OpenGL程序 3 OpenGL语法 4 OpenGL渲染管线 41 准备向OpenGL传输数据 42 将传输数据到OpenGL 43 顶点着色 44 细分着色 45 几何着色 46 图元装配 47 剪切 48 光栅化 49 片元着色 410 逐片元的操作 5 第一个程序深入分析 51 进入main函数 52 OpenGL的初始化过程 初始化顶点数组对象 分配顶点缓存对象 将数

OpenGL学习笔记: (1)mac下OpenGL环境搭建

1,OpenGL是什么 OpenGL(全写Open Graphics Library)是个定义了一个跨编程语言.跨平台的编程接口规格的专业的图形程序接口.它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库. 2,OpenGL能做什么 OpenGL能用来开发跨平台的渲染引擎,在Android.OSX.iOS.Windows.PS等平台均可使用 OpenGL(ES). 3,OpenGL不能做什么 OpenGL不能做物理模拟,OpenGL不能做网络通信,一句话,除了渲染以外的事情,Op

OpenGL ES总结(一)OpenGL 初识

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/61615215 OpenGL是在图形图像中,非常优秀的渲染库,文中Demo下载地址:https://github.com/hejunlin2013/OpenGL31,看下今天的Agenda: OpenGL是什么? OpenGL主要功能是什么? OpenGL ES是什么? Android中如何描述OpenGL ES版本 映射坐标绘制对

OpenGL学习之旅01—Xcode+OpenGL环境配置

1.下载和安装HomeBrew 打开terminal,输入下面的命令: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" x 1 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)&quo

ssis package 在调试状态中设置断点,程序 不进入断点 的解决方案

原文:ssis package 在调试状态中设置断点,程序 不进入断点 的解决方案 针对 SSIS intergation 项目 > 属性 > Debug >Run64bITRuntime = False

OpenGL边用边学------2 经典照相机模型

实际照相步骤 1 布置场景和调整照相机位置 3 选择镜头对焦Focus 4 按下快门 5 在电脑窗体中赞赏图片 OpenGL的相机模型 0 确定胶片位置 1 确立场景世界坐标系 2 在世界坐标系中确定相机位置与方向 3 在世界坐标系中建立物理世界模型 4 视图变换与模型变换的抉择 5 在照相机坐标系中确定可视范围对焦投影变换 6 调用glBegin glEnd拍照 OpenGL相机模型与实际相机的不同 1 物体和相机都能够随意移动 2 终于的照片能够是多次拍摄合成的 3 特殊的投影方式正投影 相

OpenGL ES总结(六)OpenGL ES中EGL

Agenda: EGL是什么? EGL数据类型 EGL在Android中应用 EGL的工作流程 GLSurfaceView与EGL区别 简单Demo EGL是什么? EGL? is an interface between Khronos rendering APIs such as OpenGL ES or OpenVG and the underlying native platform window system. It handles graphics context managemen

【OpenGL】详解第一个OpenGL程序

写在前面 OpenGL能做的事情太多了!很多程序也看起来很复杂.很多人感觉OpenGL晦涩难懂,原因大多是被OpenGL里面各种语句搞得头大,一会gen一下,一会bind一下,一会又active一下.搞到最后都不知道自己在干嘛,更有可能因为某一步的顺序错误导致最后渲染出错,又或者觉得记下这些操作的顺序是非常烦人的一件事.那么,OpenGL为什么会长成这个样子呢?这篇文章旨在通过一个最简单的OpenGL程序开始,让我们能够"看懂"它,"记住"这些操作顺序. 我们先来解

OpenGL ES总结(三)OpenGL通过计算纹理坐标来显示一张图片

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/62444395 通过OpenGL来显示一张汽车图片,图片可以看做一个矩形,所以我们先来画一个矩形 OpenGL的基本形状是三角形,一个矩形可以看成由4个三角形构成,如果我们一个一个画,那需要12个顶点,36个坐标,效率不高,所以我们采用另外一种方式--顶点索引与glDrawElements配合使用. 什么是顶点索引呢?顶点索引就是给