基于deepseek完成,主要踩坑点:安装glad
环境准备
你需要安装以下库:
- GLFW:窗口管理和输入处理
- GLAD 或 GLEW:OpenGL函数指针加载
安装命令(Linux):
sudo apt install libglfw3-dev
第二步:生成并安装 GLAD
glad/glad.h: No such file or directory— 系统找不到 GLAD 的头文件libglad-dev不存在 — 这就是问题的关键:GLAD 不是一个可以通过apt安装的库,它是一个需要在线生成的单文件库
GLAD 和 GLFW 不同:
- GLFW:是一个完整的库,有
.so文件,可以用apt安装- GLAD:只是一个头文件 + 一个
.c文件,需要从网页生成并手动添加到项目中
sudo apt install libglad-dev这个命令不存在,因为 Ubuntu 的仓库里没有 GLAD 包。
查找库文件
find /usr -name "*glfw*" 2>/dev/null | grep -E ".(so|a)$"
/usr/lib/x86_64-linux-gnu/libglfw.so
因为库文件名是libglfw.so,链接器的规则是:
-lglfw→ 找libglfw.so或libglfw.a-lglfw3→ 找libglfw3.so或libglfw3.a
- 打开浏览器,访问 https://glad.dav1d.de/
- 按以下设置选择:
- Language: C/C++
- Specification: OpenGL
- gl: 选择 Version 3.3 或更高(推荐 4.5,你的 940MX 支持),4.5没问题
- Profile: Core
- 勾选 Generate a loader
- 点击 Generate 按钮
- 下载生成的
glad.zip文件 - 解压并复制
# 解压 unzip glad.zip 整理目录为 learn_opengl/ ├── glad.c ├── glad/ │ └── glad.h ├── KHR/ │ └── khrplatform.h ├── triangle.c
khrplatform.h是 Khronos Group(OpenGL/OpenCL/Vulkan 的标准制定组织)提供的跨平台类型定义头文件。它解决了不同操作系统和编译器之间数据类型大小不一致的问题。
比如它定义了:
khronos_float_t- 跨平台的浮点类型khronos_uint64_t- 跨平台的64位无符号整数khronos_int32_t- 跨平台的32位整数
简单说:glad.h依赖khrplatform.h,两者缺一不可。
第一个 OpenGL 程序
下面是一个完整的、可运行的 OpenGL 程序,在窗口中央绘制一个彩色三角形。
2.2 完整代码
// triangle.c - 第一个OpenGL程序,绘制彩色三角形 #include
#include
#include
// 顶点着色器源代码 const char* vertexShaderSource = "#version 330 core " "layout (location = 0) in vec3 aPos; " "layout (location = 1) in vec3 aColor; " "out vec3 ourColor; " "void main() { " " gl_Position = vec4(aPos, 1.0); " " ourColor = aColor; " "}0"; // 片段着色器源代码 const char* fragmentShaderSource = "#version 330 core " "in vec3 ourColor; " "out vec4 FragColor; " "void main() { " " FragColor = vec4(ourColor, 1.0); " "}0"; // 检查着色器编译错误 void checkShaderCompile(GLuint shader, const char* name) } // 检查程序链接错误 void checkProgramLink(GLuint program) } int main() // 配置OpenGL版本(你的940MX支持OpenGL 4.5) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // ========== 2. 创建窗口 ========== GLFWwindow* window = glfwCreateWindow(800, 600, "我的第一个OpenGL程序", NULL, NULL); if (!window) { printf("窗口创建失败 "); glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // ========== 3. 加载OpenGL函数(GLAD) ========== if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { printf("GLAD初始化失败 "); return -1; } // ========== 4. 编译着色器 ========== // 顶点着色器 GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); checkShaderCompile(vertexShader, "顶点着色器"); // 片段着色器 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); checkShaderCompile(fragmentShader, "片段着色器"); // 链接为着色器程序 GLuint shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); checkProgramLink(shaderProgram); // 删除着色器对象(已链接到程序,可以删除) glDeleteShader(vertexShader); glDeleteShader(fragmentShader); // ========== 5. 准备顶点数据 ========== // 顶点数据:位置(x,y,z) + 颜色(r,g,b) float vertices[] = { // 位置 // 颜色 -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下 - 红色 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 右下 - 绿色 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部 - 蓝色 }; // 创建顶点数组对象(VAO)和顶点缓冲对象(VBO) GLuint VAO, VBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); // 绑定VAO glBindVertexArray(VAO); // 绑定并填充VBO glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 设置顶点属性:位置(location=0) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 设置顶点属性:颜色(location=1) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); // ========== 6. 主渲染循环 ========== while (!glfwWindowShouldClose(window)) { // 清空屏幕 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // 使用着色器程序 glUseProgram(shaderProgram); // 绘制三角形 glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 3); // 交换缓冲区(双缓冲) glfwSwapBuffers(window); // 处理事件(键盘、鼠标等) glfwPollEvents(); } // ========== 7. 清理资源 ========== glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteProgram(shaderProgram); glfwDestroyWindow(window); glfwTerminate(); return 0; }
2.3 编译和运行
gcc -o triangle triangle.c glad.c -I. -lglfw -lGL -lm -lXrandr -lXi -lX11 -lXxf86vm -lpthread -ldl -lXinerama -lXcursor
测试一下这样也可以 gcc -o triangle triangle.c glad.c -I. -lglfw -lGL -ldl
编译成功后运行
./triangle
参数说明:
glad.c 直接编译 GLAD 的源文件(它不是一个库,是源码)
-lglfw 链接 GLFW 库
-lGL 链接 OpenGL 库
-lX11 -lXrandr ... Linux 下 GLFW 需要的 X11 相关库
-I. 告诉编译器也在当前目录(.)查找头文件。
2.4 预期结果
运行后会弹出一个 800x600 的窗口,背景为深青色(0.2, 0.3, 0.3),窗口中央显示一个彩色三角形:
- 左下角:红色
- 右下角:绿色
- 顶部:蓝色
- 三角形内部颜色平滑渐变
2.5 代码结构解析
glfwInit(),
glfwCreateWindow() 创建窗口和OpenGL上下文 函数加载
gladLoadGLLoader() 加载OpenGL函数地址 着色器
glCreateShader(),
glCompileShader() 编译顶点/片段着色器 数据准备
glGenBuffers(),
glBufferData() 创建VBO并填充顶点数据 属性设置
glVertexAttribPointer() 告诉OpenGL如何解析顶点数据 渲染循环
glDrawArrays(GL_TRIANGLES, 0, 3) 绘制3个顶点组成的三角形
2.6 OpenGL 调试技巧
方法一:glGetError()
GLenum err; while ((err = glGetError()) != GL_NO_ERROR) {
printf("OpenGL Error: %d
“, err); }
方法二:着色器编译日志
代码中已包含 checkShaderCompile() 和 checkProgramLink() 函数,编译失败时会输出详细错误信息。
方法三:RenderDoc
对于你的940MX,强烈推荐使用 RenderDoc:
- 启动 RenderDoc,设置可执行文件路径
- 捕获一帧
- 可以逐Draw Call查看输入输出、纹理内容、着色器变量
还没有尝试:基于cmake编译
创建一个 CMakeLists.txt 文件:
cmake_minimum_required(VERSION 3.10) project(Triangle)
find_package(OpenGL REQUIRED) find_package(glfw3 REQUIRED)
add_executable(triangle triangle.c glad.c)
target_link_libraries(triangle OpenGL::GL glfw)
然后编译:
mkdir build && cd build cmake .. make ./triangle
参考学习路线
恭喜!你已经迈出了图形编程的第一步。下面是循序渐进的学习路线:
阶段一:修改现有三角形(5个练习)
示例:让三角形变色(动态 uniform)
修改片段着色器:
#version 330 core uniform vec3 uColor; // 新增 uniform 变量 in vec3 ourColor; out vec4 FragColor;
void main()
在渲染循环中每帧改变颜色:
float time = glfwGetTime(); float r = (sin(time) + 1) / 2; float g = (sin(time + 2) + 1) / 2; float b = (sin(time + 4) + 1) / 2; glUniform3f(glGetUniformLocation(shaderProgram, ”uColor“), r, g, b);
阶段二:纹理贴图(下一个大目标)
学习内容:
- 加载图片(使用
stb_image.h库) - 创建纹理对象
- 修改顶点数据,添加纹理坐标
- 修改片段着色器采样纹理
效果:把一张图片贴到三角形/矩形上
阶段三:3D 图形
示例:旋转立方体(你会学到真正的 3D 渲染)
阶段四:实用小项目
- 粒子系统(100个彩色粒子飞舞)
- 简单的 2D 游戏(Pong、贪吃蛇)
- 分形绘制(曼德勃罗集、朱丽叶集)
- 图片滤镜(灰度、模糊、边缘检测)
- 简单的 CAD 查看器(加载 OBJ 模型文件)
阶段五:进阶主题
免费教程(从你现在的水平开始)
- LearnOpenGL CN(https://learnopengl-cn.github.io/);
- 中文版,质量极高
- 从三角形到高级主题,循序渐进
- 每个章节都有完整代码示例
建议顺序:
- 入门 → 三角形(已完成)
- 入门 → 着色器
- 入门 → 纹理
- 入门 → 变换
- 入门 → 坐标系统
- 入门 → 摄像机
- OpenGL 红宝书(《OpenGL 编程指南》)
- 权威参考书,适合查阅
练习网站
- ShaderToy(https://www.shadertoy.com/);
- 在线编写片段着色器,看别人写的炫酷特效
- 适合学习着色器技巧
- OpenGL 示例集合(GitHub 搜索 “opengl-examples”)
基于你现在的情况(940MX 显卡 + 刚画完三角形),我建议:
明天做什么:
- 实现三角形的动画旋转(学 uniform)
- 用键盘控制三角形移动(学输入处理)
- 尝试画一个矩形(两个三角形)
本周目标:
- 完成 LearnOpenGL 的「纹理」章节
- 把一张图片贴到矩形上
本月目标:
- 绘制一个旋转的 3D 立方体
- 实现简单的第一人称摄像机控制
进阶玩法
GeForce 940MX 完全有能力支持“高级” OpenGL 开发。它的硬件规格对于学习和运行现代图形技术来说是足够的,但在性能上确实会存在一些限制。
为了让你更清晰地了解这块显卡的能力,下面是它的关键规格和功能支持情况:
关于“高级”OpenGL,你能做什么?
简单来说,除了对性能或专用硬件有强需求的功能外,绝大部分OpenGL技术你都可以在自己的电脑上实现。
✅ 你可以轻松学习和实践的功能:
- 现代核心管线 (Core-profile):你现在学的就是这种,完全支持。
- GLSL 着色器 (Shading Language):可以编写复杂的顶点、几何、片段和计算着色器。
- 高级光照模型:如冯氏光照、布林-冯氏光照、法线贴图、阴影贴图等。
- 帧缓冲对象 (FBO):用于离屏渲染,实现如镜子、动态反射等后期处理特效。
- 实例化渲染 (Instancing):高效绘制大量重复物体。
- Uniform Buffer Object (UBO) 和 Shader Storage Buffer Object (SSBO):更高效地在着色器间传递和管理数据。
⚠️ 可能遇到性能瓶颈,需要优化代码的功能:
- 高精度的阴影贴图:需要处理大量纹理采样,可能会卡顿。
- 大量动态物体的场景:同时绘制成千上万个独立的物体时,CPU和GPU的负载会很高。
- 复杂的后期处理特效链:如多重模糊、高动态光照等,会对显存带宽和计算能力提出挑战。
❌ 硬件上不支持,无法学习的功能:
- 硬件加速光线追踪 (DXR / Vulkan RT):这是RTX 20系及以后显卡才有的功能。
- 网格着色器 (Mesh Shaders) / 纹理空间着色器 (Texture-Space Shading):较新的架构特性,940MX的Maxwell架构不支持。
总结
结论很明确:GeForce 940MX 是一块非常适合 OpenGL 学习的“教学卡”。
它的 OpenGL 4.6 支持,意味着在功能上,它可以让你完整地走完《LearnOpenGL》教程中从基础到进阶的所有核心章节。虽然 2GB 显存和有限的算力 是你未来需要面对的性能天花板,但这也正好能倒逼你写出更高效、更优化的图形代码,养成良好的编程习惯。
opengl和vulkan
这是一个很好的问题。基于你的硬件情况(GeForce 940MX)和学习进度(刚完成第一个OpenGL程序),我的建议是:
对于你目前的情况,OpenGL 是更好的起点。
根据搜索结果显示,你的 940MX 硬件规格如下:
重要发现:有用户在 940MX 上实际测试过 Vulkan 和 OpenGL 的性能对比:
“On Nvidia GTX 940MX using Vulkan is slowest, OpenGL is fast and D3D11 is also fast but not as slow as Vulkan.”
这意味着在 940MX 上,Vulkan 的性能表现反而可能不如 OpenGL。这是因为:
- Maxwell 架构对 Vulkan 的驱动优化不如现代架构完善
- Vulkan 的低开销特性需要开发者做大量优化,否则性能可能更差
阶段一:深入学习 OpenGL(3-6个月)
目标:掌握现代图形管线核心概念
学习路径:
- LearnOpenGL CN(https://learnopengl-cn.github.io/);
- 入门 → 三角形(✅已完成)
- 入门 → 着色器、纹理、变换、坐标系统、摄像机
- 光照 → 颜色、基础光照、材质、光照贴图、投光物
- 模型加载 → Assimp 库使用
- 高级OpenGL → 深度测试、模板测试、混合、面剔除、帧缓冲、立方体贴图
- 高级光照 → 高级光照、Gamma校正、阴影映射、法线贴图
- 实践项目:
- 旋转3D立方体(学矩阵变换)
- 带光照的场景(学冯氏光照模型)
- 加载外部3D模型(学Assimp)
- 实现阴影映射(学高级技术)
阶段二:过渡到 Vulkan(3-6个月后)
何时可以开始:
- 你已经完全理解 OpenGL 的渲染管线
- 你知道什么是顶点缓冲、索引缓冲、Uniform Buffer
- 你遇到过 OpenGL 的性能瓶颈,理解为什么需要更底层的控制
- 你能用 C++ 熟练管理内存和资源
过渡方式:
- 阅读《Vulkan Programming Guide》
- 跟随 Vulkan-Tutorial.com 的教程(比官方文档友好)
- 理解 Vulkan 的核心概念:实例、设备、队列、命令缓冲、描述符集、渲染通道、管线
预计学习时间:2-3个月才能画出第一个三角形
Vulkan 相比 OpenGL 增加了大量开发者需要手动管理的复杂性:
核心理解:Vulkan 不是”更快“的 OpenGL,而是”给优化留出空间“的 API。如果你不知道如何优化,写出来的 Vulkan 代码可能比 OpenGL 还慢。
一句话建议:OpenGL 是学习图形学的**入门API,Vulkan 是掌握后的进阶方向。先花3-6个月学透OpenGL,再决定是否深入Vulkan。
这是一个很好的观察,你直觉上认为“版本更高”应该意味着“更高级”,但实际情况恰恰相反。
Vulkan 的“版本号”更高 (1.x vs 4.x),代表的是它诞生的时间更晚,吸取了OpenGL的经验教训,而不是它比OpenGL“更高级”。 它的核心理念是做减法:通过降低驱动程序的复杂度和对硬件的抽象程度,让开发者能更直接地控制GPU。
为了理解这一点,可以把 GPU 编程想象成开一家餐厅。
OpenGL:有“万能管家”的餐厅
在 OpenGL 的模型下,你作为“厨师长”,只需对“管家”(驱动程序)说:“我要一份牛排。”
- 管家(驱动)的工作:他会负责去菜市场采购(准备数据)、在厨房里安排位置(分配内存)、检查煤气灶是否正常(验证状态)、全程盯着火候并最终把牛排端给你(执行渲染)。
- 问题所在:这个管家非常全能且负责,但也意味着你无法插手他工作的细节。当你需要同时处理1000份订单时,管家就成了唯一的瓶颈。他的“全能”(自动内存管理、状态验证、同步)变成了巨大的CPU开销。
Vulkan:你“亲力亲为”的厨房
Vulkan 则撤掉了那个“万能管家”,把整个厨房的管理权直接交给你。
- 你的工作(开发者的责任):你需要亲自去规划菜市场采购量(管理内存)、亲自检查煤气灶和烤箱(验证硬件状态)、亲自安排多个厨师同时工作(多线程命令缓冲)、并精确地告诉每个厨师什么时候点火、什么时候关火(显式同步)。
- 好处是什么:因为没有管家的干预,流程效率极高。你可以根据厨房的实际情况(具体硬件)来优化流程,最大限度地压榨出每一分性能。
从技术角度看,Vulkan 通过以下三个核心特性实现了对硬件的直接控制:
1. 显式控制 vs. 隐式管理
- OpenGL:采用隐式API。你发出一个绘制指令,驱动程序会在背后做大量工作,比如检查当前状态是否合法、验证着色器、管理显存等。这些“安全检查”虽然省心,但占用了宝贵的CPU时间。
- Vulkan:采用显式API。驱动程序几乎不做事后验证,它假设你清楚自己在做什么。这极大地降低了CPU的“API开销”(Overhead),让指令能更快地送达GPU。
2. 预编译着色器 vs. 运行时编译
- OpenGL:你提供给驱动的是 GLSL 源代码。驱动程序在程序运行时(甚至在绘制第一帧时)需要实时将源码编译为当前GPU的机器码。这个过程是造成游戏卡顿(俗称“shader compilation stutter”)的主要原因之一。
- Vulkan:要求你提供预编译的 SPIR-V 中间码。这就像直接给了厨房一份精确的自动化烹饪程序,GPU拿到手就能立刻执行,省去了编译等待的时间。
3. 多线程支持 vs. 单线程瓶颈
- OpenGL:核心状态机设计决定了它难以高效利用多核CPU。大部分渲染工作都挤在同一个线程上,导致CPU单核负载过重。
- Vulkan:天生为多线程而生。你可以让多个CPU核心并行地录制“命令缓冲区”,最后再统一提交给GPU执行。这使得现代多核CPU的性能得以完全释放。
总结
Vulkan 并不是一个“版本更高”的 OpenGL,而是一个“思路不同”的接班人。
你可以这样理解:
- OpenGL 像是一台自动挡汽车,上手容易,开起来省心,但操作的上限和效率受限于变速箱的电脑逻辑。
- Vulkan 则像是一台手动挡赛车,操作极其复杂(需要踩离合、换挡、补油),对驾驶者要求极高。但一旦熟练,你可以将车辆的性能发挥到极限,做出自动挡无法完成的精准操作。
对于你的 940MX,学习 OpenGL 依然是更明智的选择。它能让你用更低的成本掌握现代图形学的核心概念(如渲染管线、着色器、纹理、矩阵变换等)。等你完全精通这些概念后,再转学 Vulkan,你就能明白 Vulkan 每一项“繁琐”的设定究竟是为了解决 OpenGL 时期的什么痛点。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/251359.html