OpenGL学习进程(5)第三课:视口与裁剪区域
本节是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)第三课:视口与裁剪区域的更多相关文章
- OpenGL学习进程(8)第六课:点、边和图形(三)绘制图形
本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识: (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”. ...
- OpenGL学习进程(12)第九课:矩阵乘法实现3D变换
本节是OpenGL学习的第九个课时,下面将详细介绍OpenGL的多种3D变换和如何操作矩阵堆栈. (1)3D变换: OpenGL中绘制3D世界的空间变换包括:模型变换.视图变换.投影变换和视口 ...
- OpenGL学习进程(11)第八课:颜色绘制的详解
本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿. (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...
- OpenGL学习进程(10)第七课:四边形绘制与动画基础
本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识: (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图 ...
- OpenGL学习进程(7)第五课:点、边和图形(二)边
本节是OpenGL学习的第五个课时,下面介绍OpenGL边的相关知识: (1)边的概念: 数学上的直线没有宽度,但OpenGL的直线则是有宽度的.同时,OpenGL的直线必须是有限长度,而不是像数学概 ...
- OpenGL学习进程(6)第四课:点、边和图形(一)点
本节是OpenGL学习的第四个课时,下面介绍OpenGL点的相关知识: (1)点的概念: 数学上的点,只有位置,没有大小.但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点 ...
- OpenGL学习进程(4)第二课:绘制图形
本节是OpenGL学习的第二个课时,下面介绍如何用点和线来绘制图形: (1)用点的坐标来绘制矩形: #include <GL/glut.h> void display(void) ...
- OpenGL学习进程(3)第一课:初始化窗体
本节是OpenGL学习的第一个课时,下面介绍如何初始化一个窗体: (1)显示一个有蓝色背景的窗体: #include <GL/glut.h> #include <st ...
- OpenGL学习进程(13)第十课:基本图形的底层实现及算法原理
本节介绍OpenGL中绘制直线.圆.椭圆,多边形的算法原理. (1)绘制任意方向(任意斜率)的直线: 1)中点画线法: 中点画线法的算法原理不做介绍,但这里用到最基本的画0<=k ...
随机推荐
- LeetCode300. Longest Increasing Subsequence
Description Given an unsorted array of integers, find the length of longest increasing subsequence. ...
- TP id 对字符串的查找
// 还剩的图片的id $oldPid = implode(',', $_POST['OldGoodsPic']); // 从数据库中找需要出删除了的 FIND_IN_SET(id,'$oldPid' ...
- Eclipse 生成jar包
Eclipse 生成jar包 打开 Jar 文件向导 Jar 文件向导可用于将项目导出为可运行的 jar 包. 打开向导的步骤为: 在 Package Explorer 中选择你要导出的项目内容.如果 ...
- php生成rss订阅
代码: <?php $host = $_SERVER['HTTP_HOST']; $xmls = '<?xml version="1.0" encoding=" ...
- Yii GridView::widget
GridView::widget文档 http://demos.krajee.com/grid GridView::widget([ 'dataProvider' => $dataProvide ...
- python3 - 使用__slots__限制实例属性
为了限制实例的属性,可以在定义class的时候,定义一个特殊的__slots__变量,来限制class实例能添加的属性.比如,只允许对Persion实例添加name 和 age 属性 class Pe ...
- 自然语言处理(NLP)资源
1.HMM学习最佳范例全文文档,百度网盘链接: http://pan.baidu.com/s/1pJoMA2B 密码: f7az 2.无约束最优化全文文档 -by @朱鉴 ,百度网盘链接:链接:htt ...
- 【BZOJ1190】[HNOI2007]梦幻岛宝珠 分层背包DP
[BZOJ1190][HNOI2007]梦幻岛宝珠 Description 给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值. ...
- 【BZOJ2034】[2009国家集训队]最大收益 贪心优化最优匹配
[BZOJ2034][2009国家集训队]最大收益 Description 给出N件单位时间任务,对于第i件任务,如果要完成该任务,需要占用[Si, Ti]间的某个时刻,且完成后会有Vi的收益.求最大 ...
- 《从零开始学Swift》学习笔记(Day 15)——请注意数字类型之间的转换
原创文章,欢迎转载.转载请注明:关东升的博客 在C.Objective-C和Java等其他语言中,整型之间有两种转换方法: 从小范围数到大范围数转换是自动的: 从大范围数到小范围数需要强制类型转换,有 ...