OpenGL EXC_BAD_ACCESS при вызове glDrawElements в Swift, но не в Objective-C

#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, как я, синтаксис указателя изменился. Вот пример того, как его использовать.

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))
  

Надеюсь, это поможет. Я также исправил пример проекта 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, а не ошибка, которая на самом деле есть в моем коде (так что это не решает проблему). Хороший улов, хотя :).