首先是印象最深刻的:Vertex Shader和Fragment shader都是要自己写的,悲。
然后是整个源代码的Rendering Pipeline。这会是一个很宏观的东西,我不会太涉及具体的代码细节,因为懒(不是
- Part 1:初始化环境
- 我们首先initialize GLFW,这是个给OpenGL做外围管理的东西。我自己是这么理解的:如果说OpenGL是核心,专门负责渲染的东西,那么GLFW就是负责让渲染输出的东西。当然实际的话GLFW也负责响应一些鼠标键盘事件什么的,这个后续再说,主要是我目前还没碰到,我也不会(
- 我们随后创建一个基于GLFW的Window(不是Windows),并让他跑在当前代码所代表的线程,并设置一个函数,来响应窗口变化。
- 我们外围的东西搞好了,才终于开始加载glad这个OpenGL函数指针库了
- Part 2:建造并动态编译我们的Shader程序
- 我们先建立一个空的Vertex Shader,并往里面注入GLSL定义的Vertex Shader代码,然后找编译错误
- 再建立一个空的Fragment Shader,并往里面注入GLSL定义的Fragment Shader代码,然后找编译错误
- 我们再创造一个空的Shader Program,并将Vertex Shader和Fragment Shader给Link进去
- 至此,我们完成了整个Pipeline的建立,我们终于开始渲染了。
- Part 3:我们下面开始准备渲染数据。
- 我们首先准备Vertex Data,并创造Vertex Buffer Data和Vertex Array Data的相关Pointer-Like Thing——我知道我可以用类指针这样的词汇,但我看着烦,用英文反而能特别凸显这个东西的特殊。接下来我也会用一些奇怪的英文,表示一种特殊性。
- 我们说到,OpenGL是一个大型状态机,所以,有一个,十分,十分不习惯的编程方式在这里体现了。如果是习惯了OOP的,肯定会晕。
- 你就假设,现在我们处在一个Raw-State,这个时候,我们使用函数glBindVertexArray(VAO);,这个时候,我们就进去了VAO的里面,到了一个Write-VAO-State。这么想,你现在随身带着两把开天辟地的神剑,一把叫VAO,一把叫VBO。你现在先用了一把叫做VAO的剑,天地开了,你进去了,VAO暂时和世界融为一体。
- 我们继续使用函数glBindBuffer(GL_ARRAY_BUFFER, VBO);,进入到了VAO里面的一个VBO——这么想,你不是还剩一把VBO的剑吗,继续套娃开世界,你又进去了,VBO也和新的世界融在一起。
- 现在你在新的世界作画——说人话就是填数据,刚刚的Vertex Data填进去:glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);——但你还得演奏这个世界的规则,你需要指定世界挥洒七彩的方式——说人话就是glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
- glEnableVertexAttribArray()这个函数,我目前的理解是把某个location的变量给enable了,这个给Vertex Shader传过去的东西:
#version 330 core layout (location = 0) in vec3 aPos; void main() { gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); };
- 这里面,location是0,所以我们也传了过去:glEnableVertexAttribArray(0);
- 梳理一下整个过程:我们首先在glsl里面定义了location = 0,然后在函数glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);里面的第一个参数这里,再设置了把数据填充的地方,最后我们再启用这个数据:glEnableVertexAttribArray(0);
- 然后刚刚不是开天辟地了吗,你现在离开这个世界,首先先是VBO——glBindBuffer(GL_ARRAY_BUFFER, 0);——VBO重新回归手里,然后是VAO——glBindVertexArray(0);——好了,两把剑现在重新在你手里了。数据就这么放完了。Render Loop的话那就之后再说吧,我得去洗澡了。
明天再说Render Loop的事情。