OpenGL学习记录:坐标

GLM库

在了解坐标系统之前,必须在OpenGL中添加数学库,GLMGLM是一个只包含头文件的库,它易于使用,方便安装,专门为OpenGL定做的数学库。
只需要下载后,将文件解压,把glm文件夹复制到你的工程文件中,对着glm文件夹右键,点击:包含在项目中,即可使用。

一般来说,GLM的大多数功能在以下三个文件中就有包含:

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>码片

矩阵的知识在此不做过多介绍,直接举例如何利用GLM创建矩阵,并加以如何在着色器中加以使用。

glm::mat4 matrix(1.0f); //创建4*4的单位矩阵
model = glm::scale(model, glm::vec3(0.5, 0.5, 0.5)); //创建缩放矩阵
model = glm::rotate(model, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0));  //创建旋转矩阵
model = glm::translate(model, glm::vec3(1.0f, 1.0f, 0.0f));  //创建变换矩阵

其实我们观察源码后,也能发现原理是一样的,就是将数字模板化,然后直接计算结果。而在游戏开发中,只会涉及到三维空间或二维空间的操作。因此在44矩阵中,即三维空间移动,一般情况只需要vec3作为第二个参数,之所以需要44矩阵,是用于避免三位运动中的欧拉死锁,同时也能更好的表述三维空间运动。

template<typename T, qualifier Q>
	GLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)
	{
		mat<4, 4, T, Q> Result;
		Result[0] = m[0] * v[0];
		Result[1] = m[1] * v[1];
		Result[2] = m[2] * v[2];
		Result[3] = m[3];
		return Result;
	}

在着色器代码中,我们需要定义一个uniform mat4 用于传输数据。uniform可以传输数据进着色器中,mat4对应匹配model的数据类型,之后便可直接使用。其余例子不过多介绍,原理是相同的。

//shader code
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 transform;

void main()
{
    gl_Position = transform * vec4(aPos, 1.0f);
    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
}

//project code
glm::mat4 matrix(1.0f); //创建4*4的单位矩阵
model = glm::scale(model, glm::vec3(0.5, 0.5, 0.5)); //创建缩放矩阵
int location = int location = glGetUniformLocation(program, "transform");
glUniformMatrix4fv(location, 1, GL_FALSE, &model[0][0]);

坐标系统

了解如何使用glm库,如何创建矩阵进行运算后,需要介绍各个坐标系统。在OpenGL中,分五个坐标系统,或五个空间坐标系:

  • 局部空间,或物体空间
  • 世界空间
  • 观察空间,或摄像机视角空间
  • 裁剪空间
  • 屏幕空间

在这里插入图片描述

通常来说,我们创建一个物体后需要对物体进行操作,例如改变形状,局部调整颜色,材质等,都需要先在局部空间上操作。在局部空间上作用的矩阵,称之为模型(Model)
接着多个物体如何拜访,拜访的位置具体在哪,旋转角度如何,是在世界空间上进行操作。局部坐标之后会变成世界坐标,同用Model进行计算。
然后需要调整摄像头的视角,就需要在观察空间进行调整,例如将摄像头拉远拉近,或是围着物体旋转,物体不变但是屏幕上的物体会一直变化。作用在观察空间的矩阵称之为观察(View)
最后我们对摄像头下的视角图片,进行裁剪,然后计算投影到屏幕的每个像素点中,就需要用到**投影(Projection)**矩阵。

裁剪空间

OpenGL是希望所有坐标都在一个特定的范围中,即可视空间。超过这个范围的顶点(Vertex)都会被裁剪掉。有个更常见的现象就是视角穿模,当物体超过可视范围就不会显示顶点坐标。
这个范围可以理解为一个箱子,在这个箱子内的物体才会被显示,而如何理解这个箱子,会有两种观察模式:正射投影透视投影
更贴合生活的投影方式就是透视投影,在远处的东西会越来越小,即透视现象。

透视
原理上,是将远处的坐标xyz都除以w值,从而做到缩小的效果。在OpenGL中可以调用函数创建一个透视投影矩阵:

glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);

第一个参数就是我们常见的视野(FOV),第二个参数是宽高比,往往与窗口宽高比一致,第三第四表示的是近平面和远平面距离。当我们知道视野、宽高比、平面距离,就能确定出一个特定的视角空间,或裁剪空间,在此空间中的物体才会显示。
在这里插入图片描述

应用矩阵

在着色器中,需要创建三个uniform mat4 矩阵,分别代表模型矩阵,视角矩阵和投影矩阵。
注意:矩阵运算是新的矩阵进来需要添加在最左侧,矩阵计算是没有交换律的。
因此顺序,位置也是十分重要的,往往无法产生图像可能就是这里出了问题。

#version 330 core
layout (location = 0) in vec3 aPos;
...
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    // 注意乘法要从右向左读
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    ...
}

在main()函数的主题循环中创建矩阵

//model matrix
glm::mat4 model(1.0f);
model = glm::rotate(model, 45.0f, glm::vec3(1.0f, 0.0f, 0.0f));

//view matrix
glm::mat4 view(1.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

//projection matrix :
glm::mat4 projection(1.0f);
projection = glm::perspective(glm::radians(45.0f), (800.0f / 600.0f), 0.1f, 100.0f);

最终结果:
在这里插入图片描述

同理我们可以构造3D物体了,需要给出8个顶点即可。但是直接构造会出现问题,OpenGL绘制图形是不断绘制三角形的,有些三角形是会重复覆盖某些区域,OpenGL不知道哪些区域应该是哪些三角形覆盖的,就会导致立方体别扭奇怪。
对此需要让OpenGL生成深度缓冲,同时OpenGL存储深度的信息存放在Z缓冲中,在调用片段着色器时,OpenGL会对比深度值和z缓冲,自动计算当前的三角形,是被覆盖还是在最外层,从而达到3D视觉的效果。
我们需要开启深度测试的功能,同时每次渲染迭代都会清除之前的深度缓冲:

glEnable(GL_DEPTH_TEST);

//在主体循环中
while(!glfwWindowShouldClose(window)){
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

最终结果展示:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值