在电脑中,空间就是某种坐标系!
Space = Coordinate
Vclip = Mprojection ⋅ Mview ⋅ Mmodel ⋅ Vlocal
V: Vector、 M: Matrix、local: Vertex
反方向(右到左)看过来:
local代表本地的顶点数据---->
---->经由Model Matrix转换得到---->
---->[World Space世界空间] ?坐标系的转换!---->
而得到的世界空间的坐标系我们---->
---->经由View Matrix转换得到---->
---->[View Space观察空间] ? (可以是Camera摄像机) ---->
而得到的观察空间坐标系我们---->
---->经由Projection Matrix转换得到---->
---->[Clip Space剪裁空间] ? (空间很大,但屏幕有限,so…) ---->
---->经由Viewport Transform视口变换 ---->
----> [Screen Space显示器屏幕(2D)]
(学习OpenGL或者Direct3D,我们可以先不要关注线性代数、离散数学等内容,可以先将流程与代码搞清楚就好…)
dont ask why,first how to do!
#version xxx xxx
layout (location = n) in vec3 vert;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(vert, 1.0f);
}
注意:矩阵以及向量相乘的这个顺序不能改变!
代码:
// projection投影矩阵:角度(45度) 视野FOV(Field of View)、宽高比、NearPlane近平面、FarPlane远平面
glm::mat4 proj = glm::mat4(1.0f);
proj = glm::perspective(glm::radians(45.0f), (float)800/(float)600, near, far);
ourShader.setMat4("proj", proj);
glm::mat4 view = glm::mat4(1.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
ourShader.setMat4("view", view);
glm::perspective(fov, aspect-ratio, near-plane, far-plane);
透视投影:(视锥、可视空间的大平截头体)
参数 | 描述 |
---|---|
fov | field of view 视野 |
aspect-ratio | 宽高比 |
near-plane | 近平面 |
far-plane | 远平面 |
FOV这个参数其实玩过摄影的哥们,我说相机镜头的焦段的话,应该很容以就理解了。
我们人类眼睛的焦段通常为:45~55mm,人像头通常为:85mm,而大小三元头中的长焦头通常为:70-200mm,广角:18-28mm,超广角:12-14mm。
说这个,仅为我个人举个简单的例子,镜头的焦段,我们可以理解为镜头的FOV,也就是镜头的视野。
镜头是焦段越小,视野越广,所以超广角通常都是14mm以内。而焦段越长,视野越小,但是与目标成像距离越近(望远镜)所以拍摄远处的特写,例如飞鸟,野生动物,往往200mm焦段的镜头都不够用,400mm以上的大炮随处见!
广角人像效果(我自己西藏自驾游时拍的):
对于镜头来说,可视角度越大,画面的透视越严重。这个原理也适用3D渲染。
可可西里的那张就是14mm拍摄,羊卓雍错第3张是70-200mm的镜头,而布达拉宫第一张是14-28mm拍摄,焦段应该是28mm。
所以我们在传入FOV参数的时候:
fov角度的变化代表我们摄像机镜头焦段的变化。可以拉近拉远。
宽高比,决定了视野剪裁,毕竟我们渲染的内容最终要呈现到屏幕。
近/远平面的范围,我们可以理解为可视的范围,现实中,镜头成像的内容是模拟量,转数字量(采样)细节越小,越看不清。但哪怕是几十公里外的内容也能被拍摄到,至少不清晰。
但在3D渲染中,这个范围外的内容实会被剪裁掉。也就是只显示近/远平面的范围内的内容。
用过maya、3dsmax、softimage这类3D艺术软件的朋友如果接触过超大场景组装的话会发现,通常摄像机的参数中,near会调节到最小,而far会调节到最大,否则软件中也会出现剪裁象形。即超出这个范围的将不可见。
// projection投影矩阵:角度(45度) 视野FOV(Field of View)、宽高比、NearPlane近平面、FarPlane远平面
glm::mat4 proj = glm::mat4(1.0f);
proj = glm::perspective(glm::radians(45.0f), (float)800/(float)600, near, far);
ourShader.setMat4("proj", proj);
glm::mat4 view = glm::mat4(1.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
ourShader.setMat4("view", view);
// 渲染容器
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
// glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// glDrawArrays(GL_TRIANGLES, 0, 36);
for (unsigned int i = 0; i < 10; i++)
{
// transform 就是Model Matrix
glm::mat4 transform = glm::mat4(1.0f);
transform = move(transform,
cubePositions[i].x,
cubePositions[i].y,
cubePositions[i].z
);
GLfloat angle = 20.0f * i;
if (i % 3 == 0)
{
transform = rotate(transform, (GLfloat)glfwGetTime(), 1.0f, 0.3f, 0.5f);
}
else
{
transform = rotate(transform, glm::radians(angle) * (GLfloat)glfwGetTime(), 5.0f, 1.0f, 2.0f);
}
ourShader.setMat4("transform", transform);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
#version 330 core
layout (location = 0) in vec3 aPos;
// layout (location = 1) in vec3 aColor;
layout (location = 1) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
uniform mat4 transform;
uniform mat4 view;
uniform mat4 proj;
void main()
{
// transform = model(matrix)
gl_Position = proj * view * transform * vec4(aPos, 1.0f);
// ourColor = aColor;
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}