#ios #objective-c #opengl-es #swift
#iOS #objective-c #opengl-es #swift
Вопрос:
Я работаю над учебным пособием по OpenGL для iOS Рэя Вендерлиха, пытаясь преобразовать его код из Objective-C в Swift.
Я очень новичок в OpenGL и Swift и считаю, что моя проблема связана с тем, как я перевел Objective-C. Вот почему:
В моем файле swift для настройки моего представления, содержащего содержимое OpenGL, на последнем логическом шаге (вызов glDrawElements) приложение завершит работу с предупреждением EXC_BAD_ACCESS. Однако, если я переместил эту часть кода в файл Objective-C, приложение работает так, как ожидалось.
Быстрая версия этого кода:
var positionDataOffset: Int = 0
glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(),
GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)),
VertexDataSource.sizeOfVertex(), amp;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(), amp;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
Как указал Рето Коради, приведенный выше код Swift ссылается self.positionSlot
дважды, а не использует цветовой интервал. Это была ошибка, которую я допустил при публикации кода здесь, а не ошибка в моем коде.
Таким образом, проблема все еще существует.
Обновленный Swift:
var positionDataOffset: Int = 0
glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(),
GLboolean.convertFromIntegerLiteral(UInt8(GL_FALSE)),
VertexDataSource.sizeOfVertex(), amp;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(), amp;vertexOffset)
РЕДАКТИРОВАТЬ # 2: решаемая
В итоге я решил это. Проблема в моем случае заключалась в том, что мое преобразование Objective-C в Swift было неправильным в нескольких случаях. Для краткости я опубликую окончательную версию кода Swift для той части, о которой я изначально беспокоился, но вы можете просмотреть полный исходный код рабочего результата здесь, в этом примере репозитория GitHub.
Окончательный код 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)
Я собираюсь пойти дальше и принять ответ Рето Коради, поскольку он, безусловно, привел меня на правильный путь.
Комментарии:
1. Привет,
let vertextBufferOffset: CConstVoidPointer = COpaquePointer(UnsafePointer<Int>(0)
), похоже, больше не работает. Вы случайно не знаете какие-либо другие альтернативы? Заранее спасибо.2. вместо этих длинных
convertFrom...
функций попробуйте простоGLboolean(GL_FALSE)
3. также
GLenum(GL_TRIANGLES)
4. Я изучаю OpenGL с помощью того же руководства, и у меня также есть проблемы с swift.
Ответ №1:
Для людей, которые используют swift 2.1.1 с Xcode 7.2, как я, синтаксис указателя изменился. Вот пример того, как его использовать.
Соответствующий код приведен ниже:
// 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))
Надеюсь, это поможет. Я также исправил пример проекта github OP в моем fork здесь: https://github.com/zwang/iOSSwiftOpenGL
Ответ №2:
Я действительно не знаю языков, но одно очевидное отличие заключается в том, что версия Objective-C устанавливает два разных атрибута вершины, в то время как версия Swift устанавливает один и тот же атрибут дважды:
glVertexAttribPointer(self.positionSlot, 3 as GLint, GL_FLOAT.asUnsigned(), ...)
glVertexAttribPointer(self.positionSlot, 4 as GLint, GL_FLOAT.asUnsigned(), ...)
Первый аргумент, который определяет местоположение атрибута, одинаков в обоих случаях.
Мне также кажется странным, что вы передаете то, что выглядит как адрес переменной, в качестве последнего аргумента glVertexAttribPointer()
во втором вызове и в качестве последнего аргумента glDrawElements()
. Но, возможно amp;
, оператор означает что-то другое в Swift, чем на языках, к которым я привык.
Комментарии:
1. Вы правы в отношении positionSlot, но это была ошибка, которую я допустил при публикации в SO, а не ошибка, которая на самом деле есть в моем коде (так что это не решает проблему). Хороший улов, хотя :).