在我的跨平台OpenGL应用程序中,我想使用顶点缓冲区对象进行绘制。 但是我遇到了调用glDrawRangeElements的问题。

glDrawRangeElements(GL_TRIANGLES, start, start + count, count, 
            GL_UNSIGNED_INT,  static_cast<GLvoid *>  (start * sizeof(unsigned int)));

编译器(Mac OS X上的CLang)不喜欢最后一个参数“错误:无法从类型'unsigned long'转换为指针类型'GLvoid *'(又名'void *')”。 OpenGL API将最后一个参数的类型定义为const GLvoid *,并且当此api与顶点数组一起使用时需要一个指针。 但是我知道当使用顶点缓冲区对象而不是指针时,应该将一个表示偏移量的整数值传递给缓冲区数据。 这就是我想要做的事情,因此我必须施展。 如何协调api要求与编译器进行严格的检查?

===============>>#1 票数:6

由于它是如此常用,人们经常使用宏来进行类型转换。 它可以这样定义:

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

这是一种干净且安全的方式来进行转换,因为它不会对具有相同大小的整数和指针类型做出任何假设,而这些假设在64位系统上通常不会。

由于我个人更喜欢C ++样式转换,并且不使用NULL,我会这样定义:

#define BUFFER_OFFSET(idx) (static_cast<char*>(0) + (idx))

===============>>#2 票数:1

像这样:

reinterpret_cast <GLvoid *> (start * sizeof(unsigned int));

===============>>#3 票数:1

这是我的答案https://stackoverflow.com/a/8284829/524368的几乎逐字副本,稍作修改,使其与此问题相符。


C定义(和C ++跟随它),指针可以转换为整数,即类型为uintptr_t ,如果以这种方式获得的整数转换回它来自的原始指针类型,则会产生原始指针。

然后是指针算术,这意味着如果我有两个指针指向所以相同的对象我可以得到它们的差异,产生一个整数(类型为ptrdiff_t ),并且该整数被添加或减去任何一个原始指针,将产生另一个。 它还定义了,通过向指针添加1,可以产生指向索引对象的下一个元素的指针。 另外两个uintptr_t的差值除以同一个对象的指针的sizeof(type pointed to)必须等于它们自己被减去的指针。 最后但并非最不重要的是, uintptr_t值可能是任何值。 它们也可以是不透明的手柄。 它们不需要是地址(尽管大多数实现都是这样做的,因为它有意义)。

现在我们可以看看臭名昭着的空指针。 C定义从uintptr_u值为0的类型为无效指针的指针。 请注意,源代码中的值始终为0 在后端,在编译的程序中,用于实际将其表示到机器的二进制值可能完全不同! 通常它不是,但它可能是。 C ++是相同的,但是C ++不允许比C更多的隐式转换,因此必须将0明确地转换为void* 另外,因为空指针不引用对象,因此没有解除引用的大小指针算术未定义为空指针 引用无对象的空指针也意味着,没有定义可以将它明智地转换为类型指针。

所以,如果这一切都未定义,那为什么这个宏会起作用呢? 因为大多数实现(意味着编译器)都非常容易上当,而编译器编码器在最高程度上是懒惰的。 大多数实现中指针的整数值只是指针本身在后端的值。 所以空指针实际上是0.虽然没有检查空指针上的指针算法,但是如果指针得到某种类型的指定,大多数编译器都会默默地接受它,即使它没有意义。 如果你想这么说, char是“单位大小”的C类型。 因此,关于强制转换的指针算法就像后端地址上的artihmetic一样。

简而言之,尝试使用预期结果做指针魔术是C语言方面的偏移是没有意义的,它只是不起作用。

让我们退一步,记住,我们实际上要做的是:最初的问题是,原始OpenGL顶点数组函数将指针作为其数据参数,但对于顶点缓冲区对象,我们实际上想要指定一个字节基于我们数据的偏移量,这是一个数字。 对于C编译器,该函数采用指针(我们学习的不透明的东西)。 相反,OpenGL定义的是利用编译器的工作方式。 大多数编译器将指针及其整数等价物实现为相同的二进制表示。 所以我们要做的是,它使编译器用我们的数字而不是指针来调用这些函数。

所以在技术上我们唯一需要做的就是告诉编译器“是的,我知道你认为这个变量a是一个整数,你是对的,而且函数glDrawElements只为它的数据参数取一个void* 。但是猜猜:该整数是从void* “产生的,通过将其转换为(void*)然后握住拇指,编译器实际上是如此愚蠢以传递整数值,因为它是函数。

所以这一切都归结为以某种方式绕过旧的函数签名。 转换指针是恕我直言的脏方法。 我做的有点不同:我搞乱了功能签名:

typedef void (*TFPTR_DrawElementsOffset)(GLenum,GLsizei,GLenum,uintptr_t);
TFPTR_DrawElementsOffset myglDrawElementsOffset =
    (TFPTR_DrawElementsOffset)glDrawElements;

现在你可以使用myglDrawElementsOffset而不做任何愚蠢的强制转换,并且offset参数将传递给函数,没有任何危险,编译器可能会搞乱它。 这也是我在程序中使用的方法。

===============>>#4 票数:0 已采纳

当我使用古代c风格的转换时,我使用CLang和c ++ 11进行编译。

glDrawRangeElements(GL_TRIANGLES, start, start + count, count, GL_UNSIGNED_INT,
        (GLvoid *)  (start * sizeof(unsigned int)));

我喜欢较少但也被编译器接受的替代品是

glDrawRangeElements(GL_TRIANGLES, start, start + count, count, GL_UNSIGNED_INT,
  reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(start * sizeof(unsigned int))));


glDrawRangeElements(GL_TRIANGLES, start, start + count, count, GL_UNSIGNED_INT,
    (char *)(0) +  start * sizeof(unsigned int)); 

===============>>#5 票数:-2

您可以尝试这样调用它:

// The first to last vertex is 0 to 3
// 6 indices will be used to render the 2 triangles. This make our quad.
// The last parameter is the start address in the IBO => zero

glDrawRangeElements(GL_TRIANGLES, 0, 3, 6, GL_UNSIGNED_SHORT, NULL);

请查看OpenGL教程

  ask by LRaiz translate from so

未解决问题?本站智能推荐:

1回复

glMultiDrawElements:传递给“ indices”参数的值(GLvoid **)

从原始重启动到使用glMultiDrawElements我不得不转换一些代码(用于为2D形状的轮廓构建VBO数据,即它们不仅是三角形网格,它们还可以是任意长度的多边形轮廓)。 现在,我意识到glMultiDrawArrays实际上更适合我的应用程序,但与该问题无关(实际上,如果我更聪明并且将其
1回复

如何从八叉树转换为带有缓存的线性数组?

我有一个3d网格(稀疏八叉树),其中每个叶子(最深的节点)都存储一个带有颜色的3d点。 我想将整个八叉树转换为3d点的线性数组(顶点缓冲区),可以将其直接上传到OpenGL。 以一种幼稚的方式,我可以遍历八叉树的所有节点并填充线性数组。 现在,我面临的问题是,当我向稀疏八叉树添加新
1回复

将OpenGL立即模式渲染实用程序方法转换为使用VBO的最佳方法?

我为自己编写了一个小型实用程序类,其中包含在OpenGL中快速轻松地渲染线条,方形,立方体等的有用方法。 到目前为止,我几乎一直使用立即模式,因此我可以专注于学习OpenGL的其他方面。 切换到使用VBO似乎是审慎的做法。 但是,我想保留我一直在使用的许多相同功能,例如我的实用程序类。
2回复

如何将模型矩阵包括到VBO中?

我想发送一个缓冲区列表(到GPU /顶点着色器),其中包含有关顶点位置,世界位置,颜色,比例和旋转的信息。 如果我的每个3D对象在矩阵中都具有与转换有关的信息,我如何通过VBO将这个矩阵数组(除了其他顶点数据之外)传递给GPU? 已更新请原谅任何错别字: 请注意,这些缓冲区(
1回复

OpenGL —一次渲染多个网格,并进行单独的转换

我正在寻找一次渲染多个网格的方法,这样就不必为每个网格发出绘制调用。 我在这里处理2D渲染,一个典型的对象(例如正方形)可能只有两个三角形。 但是,对象也可能非常复杂,并且具有数千个三角形。 现在,每个对象都可以自己移动。 从概念上讲,每个“对象”都有一个VBO(或VBO / IBO
1回复

如何将多个四边形批量放入一个巨型缓冲区

我试图将多个精灵分批放入一个大缓冲区中,但是遇到了一些技术难题。 我认为我没有正确设置我的vbo大小,但让我们看看。 尽管我想渲染两个,但目前只能渲染1个彩色四边形。 这就是我设置我的vbo的方式。 这里是精灵对象。 由于我试图绘制精灵,因此我手动创建它们,如下所
3回复

将ARGB纹理转换为2纹理的下一个幂的快速方法

我们有一些旧设备不支持非罐纹理,并且我们有一个功能可以将ARGB纹理转换为2纹理的下一个幂。 问题在于它的运行速度很慢,我们想知道是否有更好的方法来转换这些纹理。 在某些设备上,这可以轻松使用100%的CPU,因此任何优化都将是惊人的。 我可以查看执行此转换的任何现有功能吗?
2回复

C ++ 11中的cstr文字,如何将(char * [])传递给函数

在包装OpenGL着色器时,我发现一个必需参数之一存在问题。 标准顶点着色器的源由OpenGL复制到内部表示中。 一个简单的例子可能是这样的: GLchar定义为char ,因此本质上是cstr。 我写了一个包装器对象,可以帮助我创建和销毁着色器( GLuint是OpenGL句柄)
1回复

C ++ / OpenGL:纹理到像素图示例-缩小转换错误

我正在尝试从OpenGL运行此纹理到pixmap示例 ,并得到以下错误 该错误涉及示例的以下代码块: 此错误的原因是什么? 是编译器还是c ++ 11问题? 有没有办法让我的编译器忽略-Wnarrowing或进行安全转换?
1回复

如何将顶点位置传递给我的顶点着色器。 我写了一个不会在屏幕上绘制任何内容的着色器

我编写了一个着色器程序,该程序不会在屏幕上绘制任何内容,我认为这是因为可能会遗漏一些东西,我不知道如何将顶点位置传递给它。 我的顶点着色器是: 我的片段着色器是: 这是代码: