首页 > 其他分享 >OpenGL(3) ->窗口,视口,裁剪区,视景体

OpenGL(3) ->窗口,视口,裁剪区,视景体

时间:2022-11-22 10:36:26浏览次数:50  
标签:1.0 OpenGL 0.5 视口 窗口 GLdouble 视景


文章目录

  • ​​一、先看几个定义​​
  • ​​二、两个问题​​
  • ​​上次的绘图程序​​
  • ​​1、问题1​​
  • ​​2、问题2​​
  • ​​三、定义视口和裁剪可视区​​
  • ​​1、定义视口​​
  • ​​2、定义裁剪可视区​​
  • ​​四、窗口放缩回调函数​​
  • ​​(1)void glutReshapeFunc(void (*func)(int width, int height));​​
  • ​​(2)void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)​​
  • ​​(3)void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)​​

一、先看几个定义

  • ​窗口​​:即屏幕中的某一个窗口,可放大放小和移动关闭。
  • ​视口​​:即在窗口中可以见到或可以用来绘图的部分。一般设置视口等于窗口。
  • ​视景体(裁剪可视区)​​:是指成像景物所在空间的集合,它是一个空间集合体。可以把它想象成一个房间,在这个可显示区域内的一切物体都可以被显示。也就是说视景体会在三维空间中裁切一部分,允许其中裁下来的部分经过投影变换后在视口内可见。整个视景体的三维坐标将完全映射到整个视口的二维坐标上
  • ​投影变换​​:定义一个视景体,并把它按仿射投影正射投影形式投射到二维的视口上,投影的方式会影响视景体的类型。裁剪出的可视部分可以在视口上显示出来

参考:​​OpenGL投影变换:视景体及glFrustum、gluPerspective 与glOrtho、gluOrtho2D​​

二、两个问题

上次的绘图程序

还记得上次看过的画图程序吗?​​OpenGL(2) ->第一个程序​​ 这个程序里简单地通过显示回调函数,程序如下

#include <GL/glut.h>
//显示回调函数
void myDisplay()
{
glClearColor(0.0, 0.0, 1.0, 0.0); //设置颜色缓冲为蓝色
glClear(GL_COLOR_BUFFER_BIT); //根据颜色缓冲给整个窗口涂色
glColor3f(1.0, 0.0, 0.0); //绘制颜色Red

glBegin(GL_LINE_LOOP); //开始绘图(封闭线段模式)
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glVertex2f(-0.5, -0.5);
glEnd(); //结束绘图
glFlush(); //立即显示
}


int main(int argc, char *argv[])
{
glutInit(&argc, argv); //对GLUT进行初始化
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); //显示方式为 单缓冲 RGB色彩
glutInitWindowPosition(100, 100); //窗口(左上角)位置
glutInitWindowSize(400, 400); //窗口尺寸(单位为像素)
glutCreateWindow("第一个OpenGL程序"); //窗口标题
glutDisplayFunc(&myDisplay); //显示回调函数
glutMainLoop();
return 0;
}

1、问题1

上次并没有说明关键点的坐标系统,所以大家可能不太清除为什么要把坐标定义为​​glVertex2f(-0.5, 0.5);​​这样的值

2、问题2

这个绘图程序的显示效果是这样的

OpenGL(3) ->窗口,视口,裁剪区,视景体_投影矩阵


可以看到,当窗口为默认的正方形时,显示正常;但当窗口尺寸比例变换时,显示的正方形也跟着变了,要是希望不管窗口怎么变化,显示的正方形都保持正方,该怎么做呢?

三、定义视口和裁剪可视区

1、定义视口

  • 利用函数void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
  • 此函数在已打开的窗口中定义视口,(x,y)= (0,0)为打开窗口和定义视口的左下角位置,宽和高单位为像素
  • 默认状态下,视口和窗口是一样大的

OpenGL(3) ->窗口,视口,裁剪区,视景体_回调函数_02

2、定义裁剪可视区

(1) 一共有四个投影函数glFrustumgluPerspectiveglOrthogluOrtho2D,它们将定义不同类型的视景体(裁剪可视区),前两个用于透视投影,后两个用于正射投影。

(2)对于本例这种二维情况,应使用正射投影,关键步骤有以下几个

  1. 重置投影矩阵
    1.进行投影的数学本质是建立投影矩阵进行空间向量运算,上述四个函数都是修改视景体,即创建一个正射投影矩阵,并且用它乘以当前的裁剪区矩阵,所以必须先重置初始矩阵,避免矩阵运算错误。
glMatrixMode(GL_PROJECTION);  //选定投影矩阵为当前矩阵,告诉OpenGL接下来要进行投影变换
glLoadIdentity(); //重置当前矩阵
  1. 进行正射投影
  1. 利用函数 glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)修改一个平行视景体如下,在此区域内的物体可以被显示。实际上这个函数的操作是创建一个正射投影矩阵,并且用它乘以当前的裁剪区矩阵
  2. 正射投影的最大一个特点是无论物体距离相机多远,投影后的物体大小尺寸不变。也就是说,一个处于3D空间中的长方体,人眼看到的应该是近大远小。但使用glOrtho函数进行投影,则远近大小相同。
  3. 如果没有其他变换,正射投影的方向平行于Z轴,且视点朝向Z负轴。这意味着物体在视点前面时far和near都为负值,物体在视点后面时far和near都为正值。

(3)关于视图矩阵

  1. 视图矩阵确定了最后有哪些部分属于可视区域
  2. glOrtho 等函数修改视景体,会导致视图矩阵变化。
  3. 视景体默认值(-1,1,-1,1,-1,1)。这也可以解释上面的问题1,在视景体缺省为(-1,1,-1,1,-1,1)时,正射投影到视口上的坐标为:x从-1到1,y从-1到1,所以定义关键点为​​glVertex2f(-0.5, 0.5)等​​,可以使正方形居中显示
  4. 如下代码重置视图矩阵
glMatrixMode(GL_MODELVIEW);   //选定视图矩阵为当前矩阵
glLoadIdentity(); //重置当前矩阵

四、窗口放缩回调函数

  • void glutReshapeFunc(void (*func)(int width, int height));注册了一个回调函数,当窗口尺寸发送变化时将会调用此回调函数func
  • 窗口缩放时,除非用glViewport函数设定,否则视口将自动选取到整个窗口大小,而视景体不会变化,正射投影到视口上的坐标也就没有变化。也就是说此时各关键点相对视口的相对位置没变,但由于视口的长宽比例和绝对尺寸都发生变化,显示出的图像也就会随着视口发生长宽比例变化和绝对大小变化。换句话说,相当于直角坐标系中,点坐标没变,但有一条坐标轴的比例尺变了,导致点的绝对位置比例发生变化
  • 要想控制图像的长宽比例不变(正方形保持正方),就需要调整视景体。如果窗口高度比例增加了,视景体y方向也要等比例增大;如果窗口宽度比例增加了,视景体x方向也要等比例增大。换句话说,相当于直角坐标系中,有一条坐标轴的取值范围变了但比例关系没变,点的相对位置变化但绝对位置没变
  • 修改程序如下,可以实现比例保持
#include <GL/glut.h>
//显示回调函数
void myDisplay()
{
glClearColor(0.0, 0.0, 1.0, 0.0); //背景blue
glClear(GL_COLOR_BUFFER_BIT); //根据颜色缓冲涂色
glColor3f(1.0, 0.0, 0.0); //线Red
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //指定绘图时的坐标系统,分别是x,y,z的最小、最大值

glBegin(GL_LINE_LOOP); //开始绘图(封闭线段模式)
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glVertex2f(-0.5, -0.5);
glEnd(); //结束绘图
glFlush(); //立即显示
}

//缩放回调函数
//当窗口放缩时,要重新进行坐标映射(重新定义剪裁区域),如果没有这个,放缩后图像会变形
void changeSize(GLsizei w,GLsizei h)//GLsziei 看作 int
{
if (h == 0) //防止除0
h = 1;
GLfloat scale = (GLfloat)w /(GLfloat)h; //窗口协调比例

glViewport(0, 0, w, h); //设置视口为整个窗口

//设置坐标系统
glMatrixMode(GL_PROJECTION); //重置投影矩阵,告诉OpenGL接下来做投影变换
glLoadIdentity();

//等比例修改剪裁区域
if (w < h)
glOrtho(-1.0, 1.0, -1.0 / scale, 1.0 / scale, -1.0, 1.0);
else
glOrtho(-1.0*scale, 1.0*scale, -1.0 , 1.0, -1.0, 1.0);

//告诉openGL未来的转换将影响绘制的图形
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}


int main(int argc, char *argv[])
{
glutInit(&argc, argv); //对GLUT进行初始化
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); //显示方式为 单缓冲 RGB色彩
glutInitWindowPosition(100, 100); //窗口(左上角)位置
glutInitWindowSize(400, 400); //窗口尺寸(单位为像素)
glutCreateWindow("第一个OpenGL程序"); //窗口标题
glutDisplayFunc(&myDisplay); //显示回调函数
glutReshapeFunc(&changeSize); //窗口放缩回调函数
glutMainLoop();
return 0;
}

再回顾一下几个重要的函数

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

  • 窗口放缩回调函数,这个函数告诉 GLUT :当窗口大小发生化时,func函数将被自动调用
  • 如果不在这个函数里重新设置视口并裁剪可视区域(重置坐标映射),在窗口放缩时显示将会变形

(2)void glViewport (GLint x, GLint y, GLsizei width, GLsizei height)

  • 在打开的窗口中定义视口,(x,y)= (0,0)为打开窗口和定义视口的左下角位置,宽和高单位为像素

(3)void glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)

  • 这是一个正投影映射
  • 此函数指定了一个平行视景体,体现在确定了绘制最终图像时的坐标系统
  • 绘图窗口(像素数量描述其大小)映射到此函数参数值确定的视景体坐标范围内,默认正射投影的方向平行于Z轴,且视点朝向Z负轴,所以x坐标范围[left,right];y坐标范围[bottom,top]
  • 视景体参数默认为-1,1,-1,1,-1,1,这种设置如下图所示



标签:1.0,OpenGL,0.5,视口,窗口,GLdouble,视景
From: https://blog.51cto.com/u_15887260/5876705

相关文章

  • OpenGL(2) ->第一个程序
    文章目录​​一、先看几个定义​​​​二、第一个程序​​​​1、代码​​​​2、简单解析​​​​1、main函数​​​​(1)intmain(intargc,char*argv[])​​​​(2)voidgl......
  • OpenGL(1) ->概念&介绍
    文章目录​​一、计算机图形系统​​​​二、相关概念​​​​1、分辨率​​​​2、屏幕坐标系​​​​三、OpenGL图形软件包​​​​1、简介​​​​2、四种变换​​​​......
  • QT + OpenGL
    1、QT+Opengl的优势1)安装简单,QT借助于Qt的封装,无需配置第三方库如:GLFW+GLADGLFWGLADGLFW解决操作系统层面的不同GLAD使得代码可以用于不同的Opengl驱动......
  • OpenGL Shader-实现亮度、对比度、饱和度效果 转载文章
    基础概念亮度图像亮度其实就是图像的明暗程度,数字图像f(x,y)=i(x,y)r(x,y),如果灰度值在[0,255]之间,则f值越接近0亮度越低f值越接近255亮度越高。对比度对比度是图像......
  • DLGOPENGL-05
    在我们开始直接绘制之前,我们首先需要删除图像,因为如前一课所述,我们会在每次循环运行时重新绘制场景。glClear函数删除包含图像信息的缓冲区。我们片段的颜色信息(片段与屏幕......
  • OpenGL
    QtCreator中的3D绘图及动画教程(参照NeHe)-走看看(zoukankan.com)Windows下Qt开发环境:OpenGL导入3DMax模型(.3DS)-走看看(zoukankan.com)......
  • DLGOPENGL-04理论知识
    什么是OPENGL?我们需要知道OpenGL是“开放图形库”的缩写。OpenGL是一种API,它允许我们相对容易地在屏幕上输出图形,而不必确切地知道背景中发生了什么。整个过程在某种程度......
  • OpenGL ES google angle
    目录一.googleangle简介1.ANGLE支持跨平台2.ANGLE支持渲染器3.ANGLE下载地址二.EGL坐标系三.猜你喜欢零基础OpenGLES学习路线推荐:OpenGLES学习......
  • OpenGL ES glut glew glfw glad freeglut
    目录一.简介1.freeglut2.glew3.glut4.glfw5.glad二.分类1.窗口管理2.函数加载三.组合使用1.freeglut+glew2.glfw+glew3.glfw+glad四.猜你喜......
  • OpenGL ES glfw 下载和使用
    目录一.glfw简介二.glfw下载三.glfw编译四.glfw使用1.OpenGLglfw+glad效果演示2.OpenGLglfw+glad《源码下载》五.猜你喜欢零基础OpenGLES学......