概述
为了将坐标从一个坐标系统转换成另一个坐标,我们需要经历几个变换(1:模型 2:观察 3:投影)
我们的顶点坐标起始于局部坐标,然后变成世界坐标,观察坐标,剪裁坐标 最后以屏幕坐标的形式结束
坐标系统
将坐标变换为标准化设备坐标,接着再转化为屏幕坐标的过程通常是分步进行的,也就是类似于流水线那样子。在流水线中,物体的顶点在最终转化为屏幕坐标之前还会被变换到多个坐标系统(Coordinate System)。将物体的坐标变换到几个过渡坐标系(Intermediate Coordinate System)的优点在于,在这些特定的坐标系统中,一些操作或运算更加方便和容易,这一点很快就会变得很明显。对我们来说比较重要的总共有5个不同的坐标系统:
局部空间(Local Space,或者称为物体空间(Object Space))
世界空间(World Space) 模型矩阵
观察空间(View Space,或者称为视觉空间(Eye Space)) 观察矩阵
裁剪空间(Clip Space) 投影: 正投投影,透视投影
屏幕空间(Screen Space)
这就是一个顶点在最终被转化为片段之前需要经历的所有不同状态。
局部空间
局部坐标是对象相对于局部原点的坐标,也是物体的起始坐标
世界空间坐标
下一步骤是将局部空间转换成世界空间坐标,世界空间坐标是处于一个更大的空间范围的。这些坐标相对于世界的全局原点,它们会和其它物体一起相对于世界的原点进行摆放。
从局部空间转换成世界空间 通过 (模型矩阵)
观察空间
接下来我们将世界空间坐标变换成观察空间坐标,使的每个坐标都是从摄像机或者观察者的的角度观察的
从世界空间转换成观察空间通过(视图矩阵)
剪裁空间
坐标到达观察坐标后,我们需要将其投影到剪裁坐标,剪裁坐标会被处理至 -1-1的范围内并判断哪些顶点将会出现在屏幕上。
将顶点坐标从查看空间转换成剪裁空间 通过(投影矩阵)
投影矩阵: 分为两种:
1: 正投影
2: 透视投影(基本用透视投影)
投影坐标
最后,我们将裁剪坐标变换为屏幕坐标,我们将使用一个叫做视口变换(Viewport Transform)的过程。视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段
模型矩阵
我们首先创建一个模型矩阵,这个模型矩阵包含了位移,缩放,与旋转操作,他们会被应用到所有物体的顶点上,以变换他们到全局的世界空间。
作用: 使用模型矩阵 将局部空间转变成 世界空间
glm::mat4 model;
model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
视图矩阵
作用: 将世界空间转变成 观察空间
glm::mat4 view;
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
投影矩阵
作用:将观察空间转换成 剪裁空间
glm::mat4 projection;
projection = glm::perspective(glm::radians(45.0f), screenWidth / screenHeight, 0.1f, 100.0f);
模型 与 顶点着色器关联’
-
三个模型 以制服的形式存在。并和顶点着色器相乘
#version 330 core layout (location = 0) in vec3 aPos; ... uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { // note that we read the multiplication from right to left gl_Position = projection * view * model * vec4(aPos, 1.0); ... }
-
将模型 发送到着色器上(每一帧完成过后 就应该发送)
发送方式:(其中一种) int modelLoc = glGetUniformLocation(ourShader.ID, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
学习网站:
https://learnopengl.com/Getting-started/Coordinate-Systems
代码存储网址:
https://github.com/heisai/Learn-opengl/tree/master/opengl6
展示结果: