OpenGL逻辑学入门 卷零 元问题:我们到底在学什么?
卷零 元问题我们到底在学什么难度★☆☆视角[CPU]优先级P0在写第一行glClear之前先回答一个被所有教程跳过的问题你以为自己在学什么和你真正应该学什么根本不是一回事。0.1 三个根本性误解误解一OpenGL 是一个图形库你打开 IDE搜索include opengl找到了GL/gl.h。你以为这就像stdio.h一样是某个具体实现的头文件。它不是。GL/gl.h里写的只是函数声明、常量定义、类型别名。真正的实现——也就是glDrawArrays跑起来到底做什么——不在任何一个你能下载的库里。它在你显卡驱动的某个.dll/.so文件里由 NVIDIA / AMD / Intel / 高通 / Arm / 苹果 各自实现互相之间的实现细节差距大到能写一本书。那 OpenGL 是什么OpenGL 是一份规范specification——一份由 Khronos 组织发布的 PDF 文档规定了如果你声称实现了 OpenGL 4.6那么glDrawArrays(GL_TRIANGLES, 0, 3)必须做出什么样的可观察行为。你写的代码不是在调用 OpenGL是在通过驱动向 GPU 发送一份符合 OpenGL 协议的命令流。这个误解不解决你永远理解不了为什么同一段代码在 NVIDIA 上跑得飞快、在 Intel 集显上崩溃、在 macOS 上根本不支持。误解二学 OpenGL 就是学一堆gl*函数打开任何一本 OpenGL 教材的目录第一章glClear第二章glDrawArrays第三章glBindBuffer……翻到最后你记住了 200 个函数名写代码时还是不知道该按什么顺序调用、为什么必须这个顺序、调换了会怎样。因为你学错了东西。OpenGL 真正要教你的是一套异构计算的协作模型你CPU 上的程序和它GPU是两个独立的执行体你们之间通过一个异步命令队列通信这个队列有它自己的全局状态你写的每个glEnable都在改这个状态队列的执行结果不会立即可见给你除非你强制同步gl*函数只是这套模型的操作动词。模型才是名词。不理解模型背一万个动词也写不出对的程序。误解三OpenGL 难是因为函数多不。OpenGL 真正难的地方在于它的心智模型与你日常编程范式正交日常编程OpenGL函数有返回值glDraw*几乎不返回任何东西错了会抛异常错了悄悄记一个 error code等你下次去问对象 一块内存对象 一个GLuint整数句柄调用即执行调用只是排队何时执行不可控配置参数随调用传配置藏在当前绑定的全局槽位里只要你还带着函数即指令的直觉去读 OpenGL 代码每一行都会令你困惑。搞懂这套模型只需要一周不搞懂这套模型挣扎一年都进不了门。0.2 因果驱动的学习方法本专栏与教你写 OpenGL 代码的教程不同。我们的目标是让你在合上书之后能从第一性原理推导出 OpenGL 必须长成现在这样。为此每一节都会用以下三种叙述模板之一不一定全用但至少满足一种模板 A反证法“如果没有 X 这个设计会发生什么”例如果没有 VBO顶点数据每帧都得从内存拷到显存——带宽瓶颈无解60fps 不可能。所以 VBO 不是OpenGL 提供的便利是性能上的逻辑必然。模板 B备选方案对比“X 还可以这样设计OpenGL 选了这个代价和收益是什么”例错误处理可以用异常可以用回调可以用错误码轮询。OpenGL 选了错误码轮询——代价是错误位置丢失、调试困难收益是完全无开销不查就不付出任何代价、跨语言C 没异常、与异步执行不冲突。模板 C可观察现象佐证“如果你不信我说的打开 RenderDoc / 控制台 / 调试器你会看到 Y。”例你以为glDrawArrays调用完三角形就画上去了打开 RenderDoc你会看到 Draw Call 在你eglSwapBuffers之后才被 GPU 真正执行。这是异步队列的直接证据。没有这三种之一的逻辑解释都只是描述不是理解。0.3 三层视角强制切换这是本专栏最重要的方法论约束。OpenGL 的复杂性在于它横跨三个执行层任何一个概念都必须从三个视角同时看才能看懂[CPU]应用程序员视角你写的 C/C 代码、你调用的gl*函数、你管理的句柄。这层关心我应该按什么顺序调用这个 API 的输入输出是什么出错了我能看到什么[Drv]驱动开发者视角NVIDIA / AMD / Intel / 高通工程师维护的那一层。这层关心用户的 API 调用如何翻译成 GPU 的硬件命令如何缓存、合并、重排来榨干性能如何在不同硬件代际上保持规范一致性[GPU]硬件视角显存、计算单元、固定功能模块。这层关心数据从哪个总线进来哪些计算被并行化、并行度多少哪些操作是固定流水线、哪些可编程为什么必须三层一起看举个例子glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)。[CPU]视角把data这块内存上传到当前绑定的 buffer 对象[Drv]视角分配显存、安排 DMA 传输、记录这是 STATIC 用法所以放进高速显存[GPU]视角未来某次 Draw Call 时从这块显存按 VAO 描述的格式读取顶点只看 CPU 视角你以为这是个普通的内存拷贝会奇怪为什么不能直接传指针。只看 GPU 视角你看不到为什么GL_STATIC_DRAW是个 hint 而不是强制。三层一起看你立刻明白这是 CPU 内存 → 驱动调度 → 显存放置 的三段协作每一段都有自己的代价。后续每一节标题会标注它属于哪个视角可多个。遇到只标[CPU]的节请放松遇到[CPU][Drv][GPU]三标的节请慢读。0.4 阅读路线图本专栏共 12 卷 附录全读完是大工程。按你的目的选路速通路线理解派1~2 周只想搞懂 OpenGL 的道理不准备立刻写代码卷零 → 卷一 → 卷三管线全景 → 卷四变换 → 卷九调试读完你能给同事讲清楚 OpenGL 是什么、为什么这么设计。实战路线动手派3~4 周要在两周内交付一个能跑的 OpenGL Demo卷零 → 卷一 1.3/1.4 → 卷二 → 卷三 → 卷五 → 卷六 → 卷十一实战每读完一卷立即在 Demo 里实践对应章节。深究路线架构派1~2 月准备做引擎、写图形中间件、或迁移到 Vulkan全卷顺序读每节做完逻辑学三选一自检读完你能独立评估该不该用 OpenGL 做这个项目。不同读者的最短路径我是谁我应该至少读Android 应用开发想做相机滤镜卷零 卷一 1.3 卷二 EGL 卷三 卷六 卷十一桌面游戏程序员卷零 卷一 卷三 卷四 卷七 卷八想从 OpenGL 转 Vulkan全卷 卷十二教学/做技术分享卷零 卷一 卷三 卷九0.5 一个承诺与一个免责承诺读完本专栏你打开任何一份 OpenGL 代码应该能对每一行回答两个问题这一行在三层视角CPU/Drv/GPU各自做了什么如果删掉这一行最早在哪一步会出问题如果做不到是我没写好欢迎指出。免责本专栏不教你成为图形学专家。光照模型、PBR、全局光照、路径追踪——这些是图形学的内容不是图形 API的内容。OpenGL 只是一个让你把算好的颜色送到屏幕的协议颜色本身怎么算那是另一本书的事。0.6 在开始之前请确认你的环境满足一台能跑 OpenGL 4.0 的机器2010 年之后的几乎所有显卡都行macOS 用户注意只能到 4.1装好 GLFW GLAD卷十一会给最小骨架或 Android NDK EGL移动端读者装好 RenderDoc——本专栏多次用它做可观察现象佐证C/C 编译器任意主流即可最后一件事如果你读到任何一节觉得这就是个 API 描述没看出什么逻辑请立即合上书去喝杯水。这本书的失败模式只有一个——退化成另一本《OpenGL 函数手册》。请帮助我盯紧它。下一卷我们去看一个尴尬的事实OpenGL.dll到底在哪里