在Swift中调用glDrawElements而在Objective-C中调用时,OpenGL EXC_BAD_ACCESS

时间:2014-06-28 21:45:53

标签: ios objective-c opengl-es swift

我正在完成Ray Wenderlich的OpenGL for iOS教程,试图将他的代码从Objective-C转换为Swift。

我是OpenGL和Swift的新手,并且相信我的问题与我如何翻译Objective-C有关。这就是原因:

在我的swift文件中设置包含OpenGL内容的视图,在最后的逻辑步骤(调用glDrawElements)上,应用程序将因EXC_BAD_ACCESS警报而崩溃。 但是,如果我将此部分代码移动到Objective-C文件,应用程序将按预期工作。

此代码的Swift版本:

var positionDataOffset: Int = 0
glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(), 
    GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)), 
    VertexDataSource.sizeOfVertex(), &positionDataOffset)

var colorDataOffset = (sizeof(Float) * 3) as AnyObject
glVertexAttribPointer(self.positionSlot, 4 as GLint, GL_FLOAT.asUnsigned(), 
    GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)), 
    VertexDataSource.sizeOfVertex(), VertexDataSource.vertexBufferOffset())

var vertexOffset: Int = 0
glDrawElements(GL_TRIANGLES.asUnsigned(), VertexDataSource.vertexCount(),
    GL_UNSIGNED_BYTE.asUnsigned(), &vertexOffset)

这是Objective-C版本:

glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 
    (GLvoid*) (sizeof(float) * 3));

glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);

正如你所看到的,Swift更加冗长......我和其他人一样对此感到陌生。 :)

另一个注意事项:在Swift版本中,您将看到类VertexDataSource上的几个类方法调用。从本质上讲,我无法决定如何将Objective-C的某些部分转换为swift,因此决定(现在)在Objective-C中创建一个可以提供Swift代码的小类。属性。以下是Objective-C中的那些方法:

+ (GLint)sizeOfVertex {
    return sizeof(Vertex);
}

+ (GLint)sizeOfIndices {
    return sizeof(Indices);
}

+ (GLint)sizeOfIndicesAtPositionZero {
    return sizeof(Indices[0]);
}

+ (GLint)sizeOfVertices {
    return sizeof(Vertices);
}

+ (GLvoid *)vertexBufferOffset {
    return (GLvoid *)(sizeof(float) * 3);
}

+ (GLint)vertexCount {
    return self.sizeOfIndices / sizeof(GLubyte);
}

将这些行转换为Swift的任何帮助都会令人惊叹。

编辑#1

正如Reto Koradi指出的那样,上面的Swift代码引用self.positionSlot两次而不是使用colorSlot。这是我在这里发布代码时犯的错误,而不是我的代码中的错误。

所以问题仍然存在。

更新了Swift:

var positionDataOffset: Int = 0
glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(),
    GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)),
    VertexDataSource.sizeOfVertex(), &positionDataOffset)
var colorDataOffset = (sizeof(Float) * 3) as AnyObject
glVertexAttribPointer(self.colorSlot, 4 as GLint, GL_FLOAT.asUnsigned(), 
    GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)), 
    VertexDataSource.sizeOfVertex(), VertexDataSource.vertexBufferOffset())

var vertexOffset: Int = 0
glDrawElements(GL_TRIANGLES.asUnsigned(), VertexDataSource.vertexCount(), 
    GL_UNSIGNED_BYTE.asUnsigned(), &vertexOffset)

编辑#2:已解决

我最终解决了这个问题。我的问题是在几种情况下我将Objective-C转换为Swift是不正确的。为简洁起见,我将为我最初关注的部分发布Swift代码的最终版本,但您可以在this example GitHub repo中查看工作结果的完整源代码。

最终的Swift代码:

let positionSlotFirstComponent: CConstVoidPointer = COpaquePointer(UnsafePointer<Int>(0))
glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(), 
    GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)), Int32(sizeof(Vertex)), 
    positionSlotFirstComponent)
let colorSlotFirstComponent: CConstVoidPointer = COpaquePointer(UnsafePointer<Int>(sizeof(Float) * 3))
glVertexAttribPointer(self.colorSlot, 4 as GLint, GL_FLOAT.asUnsigned(),
    GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)), Int32(sizeof(Vertex)), 
    colorSlotFirstComponent)


let vertextBufferOffset: CConstVoidPointer = COpaquePointer(UnsafePointer<Int>(0))
glDrawElements(GL_TRIANGLES.asUnsigned(), Int32(GLfloat(sizeofValue(Indices)) / 
    GLfloat(sizeofValue(Indices.0))), GL_UNSIGNED_BYTE.asUnsigned(), vertextBufferOffset)

我会继续接受Reto Koradi的回答,因为它确实让我走上正轨。

2 个答案:

答案 0 :(得分:2)

对于像我一样使用带有Xcode 7.2的swift 2.1.1的人,指针语法已经改变。这是一个关于如何使用它的示例。

https://github.com/asymptotik/asymptotik-rnd-scenekit-kaleidoscope/blob/master/Atk_Rnd_VisualToys/ScreenTextureQuad.swift

相关代码引用如下:

${custom.input}

希望这会有所帮助。我还在我的fork中修改了OP的示例github项目:https://github.com/zwang/iOSSwiftOpenGL

答案 1 :(得分:1)

我不太了解这些语言,但一个明显的区别是Objective-C版本设置了两个不同的顶点属性,而Swift版本设置了两次相同的属性:

glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(), ...)
glVertexAttribPointer(self.positionSlot, 4 as GLint, GL_FLOAT.asUnsigned(), ...)

确定属性位置的第一个参数在两种情况下都是相同的。

对我来说,在第二次调用中传递看起来像变量地址的glVertexAttribPointer()的最后一个参数,以及作为{{1的最后一个参数}}。但也许glDrawElements()运算符在Swift中意味着与我以前使用的语言不同。