OpenGL 空间、投影、视角

Space、Projection、View

程序运行效果


OpenGL 空间、投影、视角_第1张图片

空间 Space ?

在电脑中,空间就是某种坐标系!
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 空间、投影、视角_第2张图片
(学习OpenGL或者Direct3D,我们可以先不要关注线性代数、离散数学等内容,可以先将流程与代码搞清楚就好…)
dont ask why,first how to do!

shader 代码:

#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以上的大炮随处见!

广角人像效果(我自己西藏自驾游时拍的):
OpenGL 空间、投影、视角_第3张图片
OpenGL 空间、投影、视角_第4张图片
OpenGL 空间、投影、视角_第5张图片
对于镜头来说,可视角度越大,画面的透视越严重。这个原理也适用3D渲染。
可可西里的那张就是14mm拍摄,羊卓雍错第3张是70-200mm的镜头,而布达拉宫第一张是14-28mm拍摄,焦段应该是28mm。

所以我们在传入FOV参数的时候:
fov角度的变化代表我们摄像机镜头焦段的变化。可以拉近拉远。


宽高比,决定了视野剪裁,毕竟我们渲染的内容最终要呈现到屏幕。


近/远平面的范围,我们可以理解为可视的范围,现实中,镜头成像的内容是模拟量,转数字量(采样)细节越小,越看不清。但哪怕是几十公里外的内容也能被拍摄到,至少不清晰。
但在3D渲染中,这个范围外的内容实会被剪裁掉。也就是只显示近/远平面的范围内的内容。
用过maya、3dsmax、softimage这类3D艺术软件的朋友如果接触过超大场景组装的话会发现,通常摄像机的参数中,near会调节到最小,而far会调节到最大,否则软件中也会出现剪裁象形。即超出这个范围的将不可见。

OpenGL 空间、投影、视角_第6张图片正交投影与透视投影:
OpenGL 空间、投影、视角_第7张图片

// 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);
}

Shader Program Code:

#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);
}

全部代码:

你可能感兴趣的:(OpenGL)