当前位置: 首页 > article >正文

从零开始写3D游戏引擎(开发环境VS2022+OpenGL)之九点五 编写运动摄像机镜头的源代码 细嚼慢咽逐条读代码系列

本篇博主金沙阳新开的逐条读代码系列,帮助编程初学者理解3D编程的奥妙之处,如有不周请多多指教。

[!TIP]

本系列的姊妹篇为从零开始写3D游戏引擎(开发环境VS2022+OpenGL)之八点五 细嚼慢咽3D引擎的代码实现-CSDN博客

本篇文章所涉及的源代码可以在这个网页链接找到:可移动镜头中的飞翔的黄金条纹理的立方体资源-CSDN文库

项目要实现的目标

今天项目目标是实现对3D模型的查看。用户可以以自身视觉作为摄像系统,翻转整个模型。这里的模型就是画着金条纹理的立方体。

实现的效果如下图:

在这里插入图片描述

显然,这里面涉及到了3D模型的渲染,具体的实现就是使用OpenGL库。

代码文件目录

下面说一下代码和资源文件有哪些。

如果您从本博文给出的资源处下载的话,一共可以找到7个文件。

其中GoldBar.cpp文件是主程序文件,整个程序的主体都在其中。

三个头文件shader_m.h,stb_image.h以及camera.h文件,分别是着色器相关的头文件,图像处理相关的头文件以及镜头处理相关的头文件。

文件7.4.camera.fs 是片段着色器的文件,

文件7.4.camera.vs是顶点着色器的文件。

这两者都可以被着色器类中的函数处理,从而让GPU编译。

最后一个是纹理图片GoldBars0.jpg。这个就是立方体表面的金条的图片。

格式是jpg。这个最好不要换掉。

下面就开始逐行讲解代码了。

首先讲的是,顶点着色器的待编译文件7.4.camera.vs

7.4.camera.vs

文件内容如下:

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

out vec2 TexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

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

这个文件,是对象化处理顶点着色器的输入文件。使用的语言是着色器语言GLSL。

#version 330 core

第一行代码,指定了OpenGL的版本号,这里用的是3.3版本。不同版本用的特性也不一样。现在最新的版本是4.6,如果你的OpenGL也是4.6版本,你可以将"#version 330 core"替换成"#version 460 core"。当然不同版本的GLSL对应着不同的OpenGL规范,但是一般有较好的对下兼容功能,毕竟不是所有人都有最新的RTX显卡。

第二行与第三行代码:

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

前者表示位置变量的属性位置值为 0,后者表示纹理变量的属性位置值为 1。

[!TIP]

位置变量aPos是一个三维向量,类型名为vec3,对应着一个xyz笛卡尔坐标轴上的点。

纹理变量aTexCoord是一个二维向量,类型名为vec2,对应着一个二维的纹理。

这个时候我们就要跳跃到主文件中对应部分了,在主文件GoldBar.cpp中,给出了顶点的数据:


...
    float vertices[] = {
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
     0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
    ...
}
...

这里,每一行的前三个数值,代表的就是位置坐标。

后两个数值,代表的是如何将纹理图片给映射上去。(0 0)表示左下,(1 1)表示右上,其余的点,你可以类推。

之所以会有位置值0和1,这是因为,GPU得到的数据为下面这样的组成。

在这里插入图片描述

当然,绿色的部分为颜色,在这里你可以将他们忽略,红色和蓝色的部分,分别是坐标(XYZ)和这个顶点对应着的纹理图案的位置(ST)

继续回到顶点着色器代码部分。

layout 后面有个关键词“in”,表示这两个变量aPos和aTexCoord是输入变量,由主程序向GPU顶点着色器小程序发送。

接着看:

out vec2 TexCoord;

这里的关键词 out,表示这个二维变量TexCoord(也就是渲染好的纹理变量)将作为输出,用于新的着色器小程序,也就是我们后面要提到的片段着色器。

这里我们就可以看出来:虽然着色器是各自独立的小程序,但是它们都是一个整体的一部分,出于这样的原因,我们希望每个着色器都有输入和输出,这样才能进行数据交流和传递。GLSL定义了inout关键字专门来实现这个目的。每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。但在顶点和片段着色器中会有点不同。

[!TIP]

这也是为什么渲染过程被称为管线渲染(render pipeline),整个渲染的过程是一环接着一环的,就像一个水管(pipeline)一样。

当然,我们编程的时候只会聚焦我们能够控制的部分,光栅化之类的步骤,因为是在GPU内部自动完成的,所以我们不会去具体的讨论。

再下面就是三个uniform 类变量了。

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

这三个变量 model view以及projection 都是mat4类型的变量,也就是4维矩阵变量。从英文名也可以知道这三个变量的含义,分别是模型(也就是图形里面的立方体),视角(也就是摄像头或者说相机的朝向矩阵)以及投影(也就是我们在镜头中应该看到的部分,窗口划定的部分。)

uniform 类变量,说明这三个变量是全局性的,可以在整个主代码中修改。

毕竟从逻辑上来说,当我们转动鼠标,或者敲击键盘wasd,我们希望摄像头都会出现对应的转动,上下左右以及前后移动。

所以这里用uniform类来声明这个变量再合适不过。

接下来的部分,就是如何处理输入和输出了。

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

GLSL语言就是写给GPU的C语言。只不过是特化的C语言。

gl_Position是默认是归一化的裁剪空间坐标,xyz各个维度的范围为-1到1,仅能在顶点着色器中使用,既是输入也是输出。gl_Position赋值范围就是float的取值范围(32位),只不过只有[-1,1]区间的片元被绘制。它是vec4类型的,不能重声明为dvec4等类型。

因为一个顶点坐标将会根据以下过程被变换到裁剪坐标:
V c l i p = M p r o j e c t i o n ⋅ M v i e w ⋅ M m o d e l ⋅ V l o c a l V_{clip}=M_{projection}⋅M_{view}⋅M_{model}⋅V_{local} Vclip


http://www.kler.cn/a/584784.html

相关文章:

  • flutter 开发中的tips 【持续更新】
  • iframe 内事件冒泡
  • 数据标注质量对AI模型质量的影响分析
  • 微信小程序-实现锚点跳转,页面加载后自动跳转、点击跳转到指定位置
  • vue判断视频链接是否有效
  • windows平台的ffmpeg编译使用
  • 5.1 程序调试
  • Qt-开发设置窗体透明效果
  • Gitlab报错:sudo: a password is required
  • 【模拟CMOS集成电路设计】带隙基准(Bandgap)设计与仿真(基于运放的电流模BGR)
  • autoreconf --install的作用
  • 复试难度解析,西电先进材料与纳米科技学院学院考研录取情况
  • c++ 中的float和double 的区别 开发过程中使用哪个更好
  • 《阿里云Data+AI:开启数据智能新时代》电子书上线啦!
  • 每日一题力扣2697.字典序最小回文串c++
  • 生成式AI+安全:API防护的“进化革命”——从被动防御到智能对抗的技术跃迁
  • 【openGauss】物理备份恢复
  • Nginx的流式响应配置详解
  • 使用服务器搭建开源建站工具Halo 2.0
  • 版本控制案例 | 硬盘巨头希捷(Seagate)的版本管理升级之路:从SVN到Perforce Helix Core