本节是OpenGL学习的第三个课时,下面介绍如何运用显示窗体的视口和裁剪区域:

    (1)知识点引入:

    1)问题现象:

当在窗体中绘制图形后,拉伸窗体图形形状会发生变化:

#include <GL/glut.h>
#include <math.h>
const float Pi = 3.1415926f;
const int n = ;
const float R = 0.8f; void init(void)
{
glClearColor(0.0,0.0,0.0,0.0);//设背景色为黑色
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0f,1.0f,-1.0f,1.0f);
}
void paintCircle()
{
int i;
glColor3f(1.0, 1.0, 1.0);//红色的圆
glBegin(GL_POLYGON);
for (i = ; i<n; ++i)
glVertex2f(R*cos( * Pi / n*i) , R*sin( * Pi / n*i));
glEnd();
glFlush();
} int main(int argv,char **argc)
{
glutInit(&argv,argc);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowSize(,);
glutInitWindowPosition(,);
init();
glutCreateWindow("检测形状变化");
glutDisplayFunc(paintCircle);
glutMainLoop();
}

2)问题产生的原因:

没有正确设置投影矩阵。默认的是透视投影矩阵且高宽比为1。因此高宽比改变了,投影就会变形。因此只要高宽比改变了,投影就应该重新计算。

3)解决办法:

每当窗口的大小改变时,视口和裁剪区域必须重新定义,以适应新的窗口大小。只有这样,才能够使窗口中显示的图像保持原来的形状,而不发生扭曲:

#include <GL/glut.h>
#include <math.h>
const float Pi = 3.1415926f;
const int n = ;
const float R = 30.0f; void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
// 把当前绘图颜色设置为红色
glColor3f(1.0f, 0.0f, 0.0f);
// OpenGL命令,用当前的绘图颜色绘制一个填充矩形
glRectf(-50.0f, 50.0f, 50.0f, -50.0f);
// 刷新绘图命令,此时所有未执行的OpenGL命令被执行
glFlush(); int i;
glColor3f(0.0, 1.0, 0.0);//绿色的圆
glBegin(GL_POLYGON);
for (i = ; i<n; ++i)
glVertex2f(R*cos( * Pi / n*i), R*sin( * Pi / n*i));
glEnd();
glFlush();
} // 设置渲染状态
void SetupRC()
{
// 设置用于清除窗口的颜色
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
} // 当窗口大小改变时由GLUT函数库调用
void ChangeSize(GLsizei w, GLsizei h)
{
//
GLfloat aspectRatio;
// 防止被0所除
if ( == h){
h = ;
}
// 设置视口为窗口的大小
glViewport(, , w, h);
// 选择投影矩阵,并重置坐标系统
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // 计算窗口的纵横比(像素比)
aspectRatio = (GLfloat)w / (GLfloat)h;
// 定义裁剪区域(根据窗口的纵横比,并使用正投影)
if (w <= h) {
glOrtho(-100.0, 100.0, - / aspectRatio, / aspectRatio, 1.0, -1.0);
}
else {
glOrtho(-100.0 * aspectRatio, 100.0 *aspectRatio, -100.0, 100.0, 1.0, -1.0);
}
// 选择模型视图矩阵,并重置坐标系统
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
} int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowSize(,);
glutInitWindowPosition(,);
glutCreateWindow("SubstainSize");
glutDisplayFunc(RenderScene);
// 设置当窗口的大小发生变化时的回调函数
glutReshapeFunc(ChangeSize);
// 设置渲染状态
SetupRC();
// 启动GLUT框架的运行,一经调用便不再返回,直到程序终止
glutMainLoop(); return ;
}

    (2)代码解释:

    1)void glutReshapeFunc( void(*func) (int width,int height) )

GLUT定义了当窗口大小改变时glutReshapeFunc()函数应该被调用。此外,这个函数还会在窗口初次被创建时调用,保证初始化窗口不是正方形的时候渲染也不会变形出错。

    2)自定义函数ChangeSize(GLsizei w, GLsizei h)

API中规定此函数要做的工作有:

1.计算高宽比(wight/height)。(注意为了计算正确,我们必须保证高度不为0。)

2.用函数glViewport把视口设置为整个窗口。

3.设置当前矩阵为投影矩阵,这个矩阵定义了一个可视空间(viewing volume),再调用一个单位矩阵来初始化投影矩阵。

4.根据窗口的纵横比定义裁剪区域,并使用正投影。

5.选择模型视图矩阵,并重置坐标系统。

另外此函数还可以用gluPerspective配合gluLookAt()来编写,同样能达到目的(http://blog.csdn.net/nauty_li/article/details/2227143)。

    3)SetupRC()设置渲染状态:

在渲染新的图形时,需要做一些准备工作。在本例中做的工作就是重设背景色,防止上一张的图像对即将绘制的产生影响。

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

x, y Specify the lower left corner of the viewport rectangle, in pixels. The initial value is (0,0).

width, height Specify the width and height of the viewport. When a GL context is first attached to a window, width and height are set to the dimensions of that window.

glViewport specifies the affine transformation of xx and yy from normalized device coordinates to window coordinates.

调用glViewPort函数来决定视见区域,告诉OpenGL应把渲染之后的图形绘制在窗体的哪个部位。当视见区域是整个窗体时,OpenGL将把渲染结果绘制到整个窗口。

glViewport()函数可以实现拆分窗口的功能。

    (3)相关知识:

    1)定义视口(窗口内部的渲染区域)

void glViewport(GLint x, GLint y, GLsizei width, GLsizeiheight);

其中,x,y参数指定了窗口内部视口的左下角位置,width和height参数指定了视口的大小(以屏幕像素为单位)。

    2)定义裁剪区域

对裁剪区域进行重新定义,使纵横比保持不变,窗口仍然维持在原来的形状。也就是根据新窗口大小的纵横比(像素之比,使用屏幕坐标系统),重新定义裁剪区域的纵横比(逻辑单位之比,使用笛卡尔坐标系统),使裁剪区域与视口的纵横比保持一致,这就是保持图像形状不变的关键所在。

我们在裁剪区域中使用了正投影:

void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);

注:纵横比指的是垂直方向上一个单位长度内的像素数量与水平方向上一个单位长度内的像素数量之比。

3)GL_PROJECTION和GL_MODELVIEW和GL_TEXTURE(矩阵变换http://blog.sina.com.cn/s/blog_537cc4d9010172o9.html)

glMatrixMode就是对接下来要做什么进行一下声明,这几个都是它的参数。

GL_PROJECTION:投影的意思,就是要对投影相关进行操作。也就是把物体投影到一个平面上,就像我们照相一样,把3维物体投到2维的平面上。这样,接下来的语句可以是跟透视相关的函数,比如glFrustum()或gluPerspective()。

GL_MODELVIEW:这个是对模型视景的操作,接下来的语句描绘一个以模型为基础的适应,这样来设置参数,接下来用到的就是像gluLookAt()这样的函数。

GL_TEXTURE:就是对纹理相关进行操作。

    (4)运用模型视景和裁剪区域的实例:

#include <GL/glut.h>

//不显示控制台窗口
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") void paint()
{ //glViewport的四个参数,前两个代表模型视景的起点坐标,后两个代表视景的宽度和高度 glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 0.0);
//画分割线,分成四个视见区
glViewport(, , , );
//多组双顶点线段,点成对出现
glBegin(GL_LINES);
glVertex2f(-1.0, );
glVertex2f(1.0, );
glVertex2f(0.0, -1.0);
glVertex2f(0.0, 1.0);
glEnd(); //定义在左下角
glColor3f(0.0, 1.0, 0.0);
glViewport(, , , );
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(, , , );
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(, , , );
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, 0.0);
glViewport(, , , );
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()
{
glClear(GL_COLOR_BUFFER_BIT);
//灰色作为填充背景
glClearColor(0.5, 0.5, 0.5, 0.5);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//定义裁剪区域
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
} int main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(, );
glutInitWindowSize(, );
glutCreateWindow("视口和裁剪区域应用");
init();//和下面一行的顺序可以颠倒,还可以省略,省略后采用默认设置,背景为黑色
glutDisplayFunc(paint);
glutMainLoop();
}

OpenGL学习进程(5)第三课:视口与裁剪区域的更多相关文章

  1. OpenGL学习进程(8)第六课:点、边和图形(三)绘制图形

    本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识:     (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”. ...

  2. OpenGL学习进程(12)第九课:矩阵乘法实现3D变换

    本节是OpenGL学习的第九个课时,下面将详细介绍OpenGL的多种3D变换和如何操作矩阵堆栈.     (1)3D变换: OpenGL中绘制3D世界的空间变换包括:模型变换.视图变换.投影变换和视口 ...

  3. OpenGL学习进程(11)第八课:颜色绘制的详解

        本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿.     (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...

  4. OpenGL学习进程(10)第七课:四边形绘制与动画基础

        本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识:     (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图 ...

  5. OpenGL学习进程(7)第五课:点、边和图形(二)边

    本节是OpenGL学习的第五个课时,下面介绍OpenGL边的相关知识: (1)边的概念: 数学上的直线没有宽度,但OpenGL的直线则是有宽度的.同时,OpenGL的直线必须是有限长度,而不是像数学概 ...

  6. OpenGL学习进程(6)第四课:点、边和图形(一)点

    本节是OpenGL学习的第四个课时,下面介绍OpenGL点的相关知识:     (1)点的概念:     数学上的点,只有位置,没有大小.但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点 ...

  7. OpenGL学习进程(4)第二课:绘制图形

    本节是OpenGL学习的第二个课时,下面介绍如何用点和线来绘制图形:     (1)用点的坐标来绘制矩形: #include <GL/glut.h> void display(void) ...

  8. OpenGL学习进程(3)第一课:初始化窗体

        本节是OpenGL学习的第一个课时,下面介绍如何初始化一个窗体:     (1)显示一个有蓝色背景的窗体: #include <GL/glut.h> #include <st ...

  9. OpenGL学习进程(13)第十课:基本图形的底层实现及算法原理

        本节介绍OpenGL中绘制直线.圆.椭圆,多边形的算法原理.     (1)绘制任意方向(任意斜率)的直线: 1)中点画线法: 中点画线法的算法原理不做介绍,但这里用到最基本的画0<=k ...

随机推荐

  1. figure margins too large错误解决

    使用Rstudio,遇到下面这个错误: figure margins too large 这是因为界面右下角的“plot”窗口太小,显示不了,将右下角的窗口调大就能解决

  2. ThinkPHP与EasyUI整合之二(datagrid):删除多条记录

    学习EasyUI已有一段时间了,现在开始逐步把平时学习的细节和难点记录下来. 1. datagrid选中多条记录的语句是: var rows = $('#dg').datagrid('getSelec ...

  3. 第一百九十五节,jQuery EasyUI,Resizable(调整大小)组件

    jQuery EasyUI,Resizable(调整大小)组件 学习要点: 1.加载方式 2.属性列表 3.事件列表 4.方法列表 本节课重点了解 EasyUI 中 Resizeable(调整大小)组 ...

  4. 通过 after() 和 before() 方法添加若干新元素

    after() 和 before() 方法能够通过参数接收无限数量的新元素.可以通过 text/HTML.jQuery 或者 JavaScript/DOM 来创建新元素. 在下面的例子中,我们创建若干 ...

  5. spark通过合理设置spark.default.parallelism参数提高执行效率

    spark中有partition的概念(和slice是同一个概念,在spark1.2中官网已经做出了说明),一般每个partition对应一个task.在我的测试过程中,如果没有设置spark.def ...

  6. python socket编程入门(编写server实例)+send 与sendall的区别与使用方法

    python 编写server的步骤: 1. 第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参 ...

  7. thinkPHP3.2.2中支持的URL的四种模式

  8. 笔记-Android学习历程

    1. Junit 配置:在manifest节点下 写入instrumentation,在其兄弟节点下配置application <instrumentation android:name=&qu ...

  9. libnids介

    转自:http://blog.chinaunix.net/uid-22832715-id-2111578.html Libnids开发包介绍     Libnids是一个用于网络入侵检测开发的专业编程 ...

  10. 1503 猪和回文(DP)

    1503 猪和回文 题目来源: CodeForces 基准时间限制:2 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 一只猪走进了一个森林.很凑巧的是,这个森林的形状是长方形的,有 ...