OpenGL3.3 视口变换 裁剪

关于矩阵的计算可以看另一篇博客

计算机图形学第二天

关于透视矩阵如何实现可以看另一篇博客

OpenGL3.3透视矩阵原理计算

观察视图

视图变换

将设置好的摄像机放置到世界中

模型变换

将准备拍摄的对象移动到场景中必要的位置上

投影变换(视锥体设置)

设置相机的焦距 或者调整缩放比例 只是对捕捉场景的范围大小 不对结果进行拉伸

应用变换结果

拍摄照片

视口变换

对结果图像进行拉伸或者挤压 将它变换到需要 的图片大小
将裁剪空间的坐标转换到屏幕坐标空间的过程叫做视口变换 视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内
剪切空间坐标(0,0)一般会被映射到窗口空间的中心
x坐标轴正向指向右侧
y坐标轴正向指向上方
(-1,-1)位于窗口的左下方
(1,1)位于窗口右上方

(设置剪切坐标到窗口坐标的映射方式)glClipControl(GLenum origin,GLenum depth)

origin设置的是窗口坐标x和y的原点
origin必须是GL_LOWER_LEF或者GL_UPPER_LEFT中的一个
GL_LOWER_LEF:剪切空间x,y坐标(-1,-1)对应窗口左上角 y轴正向对应窗口空间的下方向
depth设置的是剪切空间深度值映射到glDepthRange()所设置的数值的方式
depth可以为:
GL_NEGATIVE_ONE_TO_ONE:窗口空间深度值对应于剪切空间的[-1,1]
GL_ZERO_TO_NOE:剪切空间[0,1]被映射到窗口空间深度值 0.0表示近平面 1.0表示远平面 剪切空间的z负值将被处于近屏幕后方 但是观察者眼前的数据进度之会被的更高

在这里插入图片描述

坐标变换顺序

模型局部坐标系->世界坐标系->观察空间坐标(眼坐标系)->裁剪坐标系(投影变换)->屏幕坐标系
**局部空间 **:物体自己的坐标 每个物体有自己的坐标 原点 所以局部空间有很多个 键盘输入的坐标就是局部坐标空间
**世界空间 **:就是所有物体都在的一个空间 局部空间坐标*世界空间的位置=该物体在世界空间的每个顶点的坐标 就是局部坐标×model就是进入世界空间
**观察空间 **:大概的理解就是摄像机的视角里的空间,每个坐标都是从摄像机或者说观察者的角度进行观察的 世界坐标×view就是进入观察空间
**齐次裁剪空间(cvv) **:这个空间并不是视锥体空间 而是(1,-1)(1,-1)(1,-1)标准化空间 由投影矩阵创建的观察箱被称为平截头体,将特定范围内的坐标转化到标准化设备坐标系(应该就是齐次裁剪空间)的过程(而且它很容易被映射到2D观察空间坐标)被称之为投影 观察空间×projection就是进入cvv空间
NDC空间:这个空间是在cvv空间裁剪之后进行透视除法(/w)之后就进去NDC空间 这个空间的坐标是最容易转化到屏幕空间
屏幕空间:将裁剪空间的坐标转换到屏幕坐标空间的过程叫做视口变换 视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内 最后变换出来的坐标将会送到光栅器,将其转化为片段

齐次坐标

为什么需要齐次坐标:
1.实现对三维坐标的平移(易于仿射变换)(因为线性变换有个重要规则 :(0.0,0.0,0.0)坐标和三维坐标或者三维矩阵进行乘除一定是(0.0,0.0,0.0) 所以如果不添加一齐次坐标 三维坐标就一定不能实现平移)
2.实现透视效果

线性变换

f(x)=Ax
线性变换从几何直观有三个要点:
1.变换前是直线的,变换后依然是直线
2.直线比例保持不变
3.变换前是原点的,变换后依然是原点

仿射变换:

f(x)=Ax+b
也就是相对于线性变换 新增了平移变换
实际上就是增加一个维度 通过高维度的线性变换完成低纬度的仿射变换
在这里插入图片描述
特点:
(1)凸性
(2)共线性:若几个点变换前在一条线上,则仿射变换后仍然在一条线上
(3)平行性:若两条线变换前平行,则变换后仍然平行
(4)共线比例不变性:变换前一条线上两条线段的比例,在变换后比例仍然共线 比例相同

如何通过高纬度线性变换完成低纬度的仿射变换

如下图 将二维的图形放到三维的z=1平面上 z=1和z=0的图形就形成了一个柱子 然后再让柱体做推移变换(线性变换之一) 最后将图形还原到二维就形成了平移的效果
在这里插入图片描述

如何通过齐次坐标实现透视效果

如果齐次坐标最后一个分量为0 则表示这个点在无穷远的地方 在平行线最终相交的位置就是无穷远的地方
透视变换会把齐次坐标的w值修改为1.0以外的值
如果齐次坐标中w的值越大 那么坐标就离摄像机越远 因为OpenGL在准备绘制几何体的时候 他会使用w分量除以前面的三个分量 将齐次坐标变回笛卡尔坐标
裁剪(视锥剔除)和NDC转换都已集成到GL_PROJECTION
NDC是Normal Device Coordinate的简写(标准设备(屏幕)坐标系)
物体的坐标从世界坐标系剪切到视景体的坐标中(由近平面和远平面形成的一个视景体)(具体就是投影到近平面上)在这里插入图片描述
注意:视景体坐标系和标准设备坐标系是不同方向的坐标系

透视投影

有两种情况的透视投影:
1.中心对称的视图截锥 z轴位于锥体的中央位置
2.不对称的视图截锥 就像靠近窗口又没有正对窗口的情况
对于这两种情况 在这个坐标系内 观察点(摄像机的位置)都是位于(0,0,0)并且朝向z轴正方向

视口

glViewport(GLint x,GLint y,GLint width,GLint height)

在窗口中定义一个矩形的像素区域 并且将最终渲染的图像映射到其中
x,y设置了视口左下角的坐标 width和height设置了视口矩形的像素大小 默认情况为 (0,0,winWidth,winHeight)winWidth和winHeight为窗口的像素尺寸

用户裁剪和剪切(目前还不知道怎么用)

看到一篇还不错的博客里面有解释但是也不全
别人的博客

gl_CullDistance[](裁剪平面)(裁剪整个图元)

裁剪平面最大值是gl_MaxCullDistancs
如果图元的所有顶点对于平面都返回了负数的裁减距离值,那么整个图元需要被裁减。
在着色器中使用时需要手动声明他的大小 或将他作为一个编译时的常量使用 (也就是gl_CullDistance[2]需要写数字)数字表示我们将要使用的平面数量
在不同的着色器中声明的gl_CullDiastance[]和gl_ClipDistance[]数字都必须一样

gl_ClipDistance(剪切平面)(截掉部分图元)

剪切平面最大值是gl_MaxClioDistances

输出的裁剪距离将和图元进行线性插值,插值距离小于0,则图元部分将剪切掉(也就是插值距离小于0的那部分被剪切掉
距离为0表示顶点落在平面之上 正数值表示顶点在剪切平面内测(保留这个顶点) 图元中剪切距离是线性插值OpenGL会将完全落在某个裁剪平面之外的图元剔除(如果图元与所有裁剪平面相交且一部分落在他们的内测 则认为它应当被保留) 而且OpenGL会直接抛弃所有距离值小于0的片元

启用剪切平面

glEnable(GL_CLIP_PLANE0) 还有GL_CLIP_PLANE1,GL_CLIP_PLANE2等 这些枚举时按顺序定义的 因此GL_CLIIP_PLANEi总是等价于GL_CLIP_PLANE0+i 着色器必须卸任所有启用的平面距离值 否则会得到奇怪的剪切结果

gl_ClipDistance和gl_CullDistance[]的关系

gl_ClipDistance和gl_CullDistance的每个元素都对应于一个平面 平面数量有限 一般是八个 通常这个数量是gl_ClipDistance和gl_CullDistance共享 可以是8个剪切平面 也可以是8个裁剪平面 也可以各4个 但是两个数组的平面总数不能超过8个 可以用gl_MaxCombinedClioAndCullDistances来查询平面总数具体值

使用例子gl_ClipDistance和gl_CullDistance[]

先在绘制之前开启glEnable(GL_CLIPDISTANCE0);
然后再着色器中:
#version 450 core
uniform vec4 Plane;//平面方程 Ax+By+Cz+D = 0
in vec4 Vertex; //w = = 1.0
float gl_ClipDistance[1];//使用一个剪切平面 如果不写这个应该是默认只有一个GL_CLIPDISTANCE0可以用
void main()
{
/计算平面方程/
gl_ClioDistance[0] = dot(Vertex,Plane);
//也可也使用gl_CullDistance[0];//来进行裁剪
//gl_ClipDistance[0] = Plane[3] - Plane[0]*aPos.x - Plane[1]*aPos.y - Plane[2]*aPos.z;
//就是在程序中传值给着色器中的Plane 然后通过这个式子计算是否大于0 如果大于0 才会被显示出来
}

作用结果

原来的样子
在这里插入图片描述

gl_ClipDistance作用
在这里插入图片描述
gl_CullDistance作用
在这里插入图片描述

摄像机的原理

想要实现摄像机的效果 OpenGL本身没有摄像机(Camera)的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种我们在移动的感觉,而不是场景在移动。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值