我正在通过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。这是我在这里发布代码时犯的错误,而不是我代码中的错误。
所以问题仍然存在。
更新迅速:
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)
EDIT #2: Solved
我最终解决了这个问题。在我的例子中,问题是我的Objective-C到Swift的转换在几个情况下是不正确的。为简洁起见,我将发布我最初关心的部分的Swift代码的最终版本,但是你可以在这个示例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的回答,因为它确实让我走上了正确的道路。
对于像我这样使用swift 2.1.1和Xcode 7.2的人来说,指针语法已经改变了。这里有一个关于如何使用它的例子。
https://github.com/asymptotik/asymptotik-rnd-scenekit-kaleidoscope/blob/master/Atk_Rnd_VisualToys/ScreenTextureQuad.swift相关代码引用如下:
// bind VBOs for vertex array and index array
// for vertex coordinates
let ptr = UnsafePointer<GLfloat>(bitPattern: 0)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), self.vertexBufferObject)
glEnableVertexAttribArray(self.positionIndex)
glVertexAttribPointer(self.positionIndex, GLint(3), GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(sizeof(GLfloat) * 8), ptr)
glEnableVertexAttribArray(self.textureCoordinateIndex)
glVertexAttribPointer(self.textureCoordinateIndex, GLint(2), GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(sizeof(GLfloat) * 8), ptr.advancedBy(6))
希望这对你有帮助。我还固定了OP的示例github项目在我的分叉:https://github.com/zwang/iOSSwiftOpenGL
我不太懂这些语言,但一个明显的区别是Objective-C版本设置了两个不同的顶点属性,而Swift版本设置了两个相同的属性:
glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(), ...)
glVertexAttribPointer(self.positionSlot, 4 as GLint, GL_FLOAT.asUnsigned(), ...)
第一个参数决定属性的位置,在两种情况下都是相同的。
在我看来也有点奇怪,你在第二次调用中传递了一个变量的地址作为glVertexAttribPointer()
的最后一个参数,作为glDrawElements()
的最后一个参数。但也许&
运算符在Swift中的含义与我习惯的语言有所不同。