调用 glDrawElements 时的段错误
Posted
技术标签:
【中文标题】调用 glDrawElements 时的段错误【英文标题】:Segfault when calling glDrawElements 【发布时间】:2017-01-04 06:30:16 【问题描述】:我有一个在 macOS 上开发的 OpenGL 应用程序。我在我的代码中调用了glDrawElements
的段错误。我正在链接OpenGL.framework
文件并包含<OpenGL/gl.h>
。但是,如果我包含<OpenGL/gl3.h>
,则该程序不会出现段错误,并且它或多或少地按预期工作(我仍然收到无效的操作调用,但网格会绘制到屏幕上)。这是扩展加载问题吗?我没有使用 GLEW 或任何扩展加载库。我正在创建一个 2.1 版本的上下文。
Here 是我设置 OpenGL 数据的地方,here 是我进行实际绘图的地方。我还将注意到,它已在 Linux 机器上启动并运行,没有任何问题。这似乎是我遇到段错误的 macOS。
这是堆栈跟踪:
(lldb) bt
* thread #1: tid = 0x206bb7, 0x00007fff92a330d0 libsystem_platform.dylib`_platform_memmove$VARIANT$Nehalem + 112, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
* frame #0: 0x00007fff92a330d0 libsystem_platform.dylib`_platform_memmove$VARIANT$Nehalem + 112
frame #1: 0x00007fff78853c86 GeForceGLDriver`___lldb_unnamed_symbol5651$$GeForceGLDriver + 187
frame #2: 0x00007fff78855102 GeForceGLDriver`___lldb_unnamed_symbol5659$$GeForceGLDriver + 771
frame #3: 0x00007fff789710fe GeForceGLDriver`___lldb_unnamed_symbol10497$$GeForceGLDriver + 393
frame #4: 0x00007fff8227a15f GLEngine`glDrawElements_Exec + 271
frame #5: 0x0000000100030fb4 mcomp`GLRender::DrawModel(this=0x00007fff5fbff7f8, model=0x0000000100770e20) + 5956 at glrender.cc:202
frame #6: 0x0000000100003fa7 mcomp`Mcomp::Update(this=0x00007fff5fbff7b8) + 423 at mcomp.cc:27
frame #7: 0x0000000100007941 mcomp`Engine::Run(this=0x00007fff5fbff798) + 65 at engine.cc:22
frame #8: 0x00000001000026ea mcomp`main(argc=1, argv=0x00007fff5fbffa00) + 378 at main.cc:21
frame #9: 0x00007fff92826255 libdyld.dylib`start + 1
(lldb)
【问题讨论】:
@MohitJain 我用堆栈跟踪更新了答案 你应该发布你的代码。 @diametralpitch 添加了相关代码部分 您应该在绑定 VAO 时绑定 GL_ELEMENT_ARRAY_BUFFER。这样,VAO 将记住它与索引缓冲区的关联。如果是 GL_ARRAY_BUFFER,则没有这样的要求,因为当您调用 glVertexAttribPointer() 时,VAO 会捕获该关联。 【参考方案1】:我在这里看到了一些错误。
您必须调用glVertexAttribPointer() 当您绑定了缓冲区对象,顶点属性应该从该对象中提取数据。我建议首先设置和配置顶点缓冲区(包括顶点属性),然后单独进行索引缓冲区。您目前正在对它们进行某种混合和匹配。 您可能需要在调用 glVertexAttribPointer() 后调用 glEnableVertexAttribArray(),但我不完全记得标准是否要求这样做。 顶点数组对象跟踪您设置的顶点属性。反过来,顶点属性会记住它们从哪个缓冲区对象中提取数据。因此,您无需在绘制时显式绑定缓冲区对象。 当您设置的缓冲区对象太小、尝试绘制的索引多于索引缓冲区的索引或步幅关闭时,您通常会在调用 glDrawElements() 时遇到分段错误。因此,确保所有长度、尺寸等对您有意义是一个想法。当您的索引缓冲区引用越界值时,也可能会发生这种情况,但如果我没记错的话,这可能取决于如何处理这个问题的实现。作为参考,这是我通常设置 VAO 的顺序:
-
创建 VAO
绑定VAO
创建缓冲区(顶点)
绑定缓冲区
用几何数据填充缓冲区
设置相关顶点属性指针
启用顶点属性指针
创建缓冲区(索引)
绑定缓冲区
用索引填充缓冲区
这应该设置一切。绘制,使用相关的shader程序,绑定VAO并调用glDrawElements()
编辑:您能否概述一下为什么要创建 2.x 上下文,而不是 3.x 或 4.x 上下文?使用缓冲区和 VAO 进行绘制是现代 OpenGL 的渲染方式。为什么不将上下文版本与该级别匹配?
【讨论】:
我的目标是具有 Intel HD Graphics 3000 的 Linux 机器。它无法创建 3.2 Core 上下文,所以我只是随意选择了 OpenGL 2.1 并决定加载适当的扩展。 感谢您提供有关顶点数组对象绑定顺序的信息。这似乎是我的问题。我已经重新排序了周围的东西,并且不再出现段错误。什么都没有画,但我最终会弄清楚为什么:) 至少它没有崩溃! 从谷歌搜索看来它应该能够支持 OpenGL 3.0。如果没有绘制任何内容,请确保顶点属性的位置与着色器的位置相匹配。由于您使用的是 GL 4.0 之前的上下文,您可能需要询问 OpenGL 特定的索引属性有哪些(不确定您是否已经这样做了) 基本上,在 2.x 中曾经有一个“固定功能管道”。这意味着您可以使用 glBegin()、glEnd()、glVertex() 等函数来绘制图元。这些功能都非常低效,严重映射到现代硬件,因此从版本 2.x 到 3.x 被取消,以支持缓冲区对象。这些可以使用诸如“glVertexPointer()”或“glNormalPointer()”之类的函数来设置。固定功能管道已完全删除。 版本 3 到 4 基本上取消了诸如法线或纹理缓冲区之类的特殊属性,只使用“通用”缓冲区并将其留给着色器来决定如何处理它们。因此 3.x “gl(Vertex|Normal|Texture|Color)Pointer()” 函数在 v4 中不再存在,基本上迫使您使用当前使用的方法进行绘制。因此,在这一点上支持可怕的 glBegin()/glEnd() 组合的路线是值得称赞的。以上是关于调用 glDrawElements 时的段错误的主要内容,如果未能解决你的问题,请参考以下文章