今天,我将展示如何打开一个窗口并创建一个OpenGL上下文。 这是一个非常困难的任务,OpenGL仍然没有用于创建上下文的官方跨平台工具,因此我们将依赖第三方库(在这种情况下,GLFW很高兴)。 互联网上已经有很多类似的问候世界,但是我不喜欢看到的一切:要么非常复杂,要么示例中的图片非常原始(
或两者都有 !)。 非常感谢所有作者,但是我将下载另一个教程:)
今天我们将得出:

该模型是由艺术家
Samuel Sharit(arshlevon)绘制的,非常感谢他允许我将其用作计算机图形学课程的一部分!
阶段0:阅读tinyrenderer
一般来说,最好是(虽然不是必需的)阅读完我的整个
tinyrenderer课程后再做一次讲座。 对于那些不会说英语
的人 ,尽管我不再支持俄语版本,但可以
在中心上此课程。 作为本讲座的一部分,我向您展示了如何仅用五百行代码就可以绘制这张图片,甚至完全禁止使用第三方库:

令人惊讶的是,我的许多学生都不知道该软件光栅化器不仅是玩具,而且是OpenGL工作原理的真实介绍。 因此,今天,我将展示如何通过硬件加速来渲染糖尿病,并且我将在许多方面使用软件光栅化程序存储库中的代码。
注意,我并没有为自己解释每一行代码,因为我依靠阅读文档是理解所有内容的最佳方式这一事实。 我的代码仅是为了知道确切地阅读文档中的内容以及以什么顺序进行。 而且,我不会解释什么是着色器 ,也不会解释如何读取法线贴图 。 我花了很多时间在tinyrenderer上,所有的东西都整理好了。第一阶段,最困难的是:创建一个窗口
整个仓库都
在这里 ; 在github的每一步都创建了一个提交,因为github为所有所做的更改提供了非常方便的查看器。 我们从
这里开始,我们的目标是获得这个窗口:

该代码是使用CMake编译的; 我在Linux(g ++)和Windows(Visual Studio 2017)下进行了检查。 在Linux下,最新版本的代码按以下方式编译:
git clone --recurse-submodules https://github.com/ssloy/hellOGL.git cd hellOGL mkdir build cd build cmake .. make
如果您想编译一个单独的提交而不是最新版本,请使用`git checkout`。 该代码加载了glad和GLFW,创建了一个具有必要键盘回调的窗口,并从磁盘加载了空的顶点和像素着色器。
第二阶段:加载3D模型
在此阶段对项目进行的更改,
请参见此处 。 在此阶段,我们的目标是解析3D模型文件,并绘制第一个三角形,而无需担心当前的照明:

请注意,模型本身和用于处理向量的库都是如此,我完全从tinyrenderer中获取了模型解析器。 也许软件渲染器不是那么没用吗?
现代OpenGL中的基本思想非常简单。 我们首先上传一个3D模型,然后创建一个3 * 3 *(三角形数)大小的顶点数组。 每个三角形都有三个顶点,对吗? 每个顶点由三个数字(x,y,z)描述。 总的来说,3 * 3 * model.nfaces()就足以描述整个模型:
std::vector<GLfloat> vertices(3*3*model.nfaces(), 0); for (int i=0; i<model.nfaces(); i++) { for (int j=0; j<3; j++) { for (int k=0; k<3; k++) vertices[(i*3+j)*3 + k] = model.point(model.vert(i, j))[k]; } }
然后,我们告诉OpenGL这是一个本机绘制的数组!
while (!glfwWindowShouldClose(window)) { [...]  glDrawArrays(GL_TRIANGLES, 0, vertices.size()); [...] }
顶点着色器没有任何有趣的作用,它只是将数据直接传递给片段着色器:
#version 330 core
好了,
片段着色器也没有伪装。 它只是将当前的泡菜用红色绘制:
#version 330 core
完成最困难的事情,现在是技术问题!
第三阶段:漫射照明
在此阶段对项目进行的更改,
请参见此处 。 我们应该得到这张照片:

如您所知,Phong模型中的漫射照明是一种简单的标量产品,介于
法线向量和照明向量。 因此,除了顶点数组之外,我还添加了另一个法线数组。 不看代码,告诉我它的大小是多少?
最有趣的事情发生在片段着色器中,在主.cpp文件中,仅加载了数据:
#version 330 core
第四阶段:转换矩阵
在此阶段对项目进行的更改,
请参见此处 。 至此,我对模型,视图和投影矩阵进行了编码。 刚开始时它们只是单个,但是如果按空格键,模型将开始旋转:每次绘制图片时,我都将模型矩阵绕z轴旋转0.01弧度:
{
在这里,函数rot_z()返回围绕z轴旋转给定角度的旋转矩阵。 由于OpenGL对我的矩阵类一无所知,因此我不得不将矩阵export void export_row_major()添加到指向浮点数的简单指针中。

第五步:法线贴图
在此阶段对项目进行的更改,
请参见此处 。 至此,我们将学习如何叠加纹理。 由于通常的漫反射纹理很无聊,因此我将立即应用法线贴图,甚至在切线空间中也是如此。 法线贴图看起来像这样:

温和地说,相应的计算并不明显,因此再次
阅读tinyrenderer中的说明 。 在数据方面,您需要添加几个缓冲区:uv坐标以及切线和双切线向量的数组。

第五阶段:漫反射纹理
好吧,如果我们已经知道如何计算法线贴图,那么应用法线漫反射贴图就很简单了。 在此阶段对项目进行的更改,
请参见此处 。

第六阶段:眩光
在此阶段对项目进行的更改,
请参见此处 。 在最后一个阶段,添加另一个纹理,该纹理将使我们能够模拟发光表面的照明眩光:

结论
此代码有很多可以改进的地方,并且视觉效果可以无休止地扭曲。 但这不是我的目标,我的目标是证明我在软件渲染中涉及的所有技术绝对都适用于当前OpenGL上下文。 而且我个人仍然认为,您需要通过绘制图片来开始熟悉3D图形,而无需使用图形库的魔力。
作为扩展,例如尝试
添加阴影或计算
全局照明量 ,或者最终绘制辉光贴图:毕竟,暗黑破坏神前额中的眼睛和水晶应该发光!