2015-12-19 4 views
3

Я переводил код Objective-C в this repo в Swift, чтобы узнать некоторые основы OpenGL. Я совершенно новичок в этом. У меня есть рабочий проект, который компилирует и создает рабочий NSOpenGLView с плавающим прямоугольником, но цвета неправильные. Я сузил проблему до моего использования функций glVertexAttribPointer, которые указывают на данные вершин и цветов.Swift, OpenGL и glVertexAttribPointer

Вот как я мои вершинных и цветовые данные хранятся:

struct Vertex { 
    var position: (x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) 
    var color: (r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat) 
} 

struct Vertices { 
    var v1: Vertex 
    var v2: Vertex 
    var v3: Vertex 
    var v4: Vertex 
} 

var vertexData = Vertices(
    v1: Vertex(position: (x: -0.5, y: -0.5, z: 0.0, w: 1.0), 
       color:  (r: 1.0, g: 0.0, b: 0.0, a: 1.0)), 
    v2: Vertex(position: (x: -0.5, y: 0.5, z: 0.0, w: 1.0), 
       color:  (r: 0.0, g: 1.0, b: 0.0, a: 1.0)), 
    v3: Vertex(position: (x: 0.5, y: 0.5, z: 0.0, w: 1.0), 
       color:  (r: 0.0, g: 0.0, b: 1.0, a: 1.0)), 
    v4: Vertex(position: (x: 0.5, y: -0.5, z: 0.0, w: 1.0), 
       color:  (r: 1.0, g: 1.0, b: 1.0, a: 1.0))) 

Версии Objective-C из glVertexAttribPointer функций, которые я пытаюсь перевести выглядеть следующим образом:

glVertexAttribPointer((GLuint)positionAttribute, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)offsetof(Vertex, position)); 
glVertexAttribPointer((GLuint)colourAttribute , 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *)offsetof(Vertex, colour )); 

В версиях Objective-C используется макрос offsetof, чтобы установить параметр указателя этих функций. Swift не разрешает макросы, и поэтому я пытаюсь выяснить, что использовать на своем месте. Я не попробуешь прохождения nil, как это:

glVertexAttribPointer(GLuint(positionAttribute), 4, UInt32(GL_FLOAT), UInt8(GL_FALSE), GLsizei(sizeof(Vertex)), nil) 

glVertexAttribPointer(GLuint(colorAttribute), 4, UInt32(GL_FLOAT), UInt8(GL_FALSE), GLsizei(sizeof(Vertex)), nil) 

Но если я сделаю это, массив цветных данных заполняется данными позиции - смещение не учитывается, поэтому он использует данные позиции для обоих позиции и цвета.

Я нашел this stackoverflow answer, который предлагает использовать withUnsafePointer и попробовал его, как это:

withUnsafePointer(&vertexData.v1.position) { ptr in 
    glVertexAttribPointer(GLuint(positionAttribute), 4, UInt32(GL_FLOAT), UInt8(GL_FALSE), GLsizei(sizeof(Vertex)), ptr) 
} 

withUnsafePointer(&vertexData.v1.color) { ptr in 
    glVertexAttribPointer(GLuint(colorAttribute), 4, UInt32(GL_FLOAT), UInt8(GL_FALSE), GLsizei(sizeof(Vertex)), ptr) 
} 

Но это разбивает весь экран, требующий принудительного выключения и перезагрузки.

Я не уверен, что попробовать дальше. Полный код, над которым я работаю, доступен here.

EDIT:

Я также попытался взять указатель на первую точку данных и продвижения его на 4 GLfloat с, как это:

let ptr = UnsafePointer<GLfloat>([vertexData.v1.position.x]) 
glVertexAttribPointer(GLuint(positionAttribute), 4, UInt32(GL_FLOAT), UInt8(GL_FALSE), GLsizei(sizeof(Vertex)), ptr) 

glVertexAttribPointer(GLuint(colorAttribute), 4, UInt32(GL_FLOAT), UInt8(GL_FALSE), GLsizei(sizeof(Vertex)), ptr.advancedBy(4)) 

Дисплей не врезаться, но ничего нарисован на экране вообще.

ответ

4

Чтобы воспроизвести функциональность offsetof, вам просто нужно знать, при каком смещении байтов каждое поле находится в вашей структуре.

В вашем случае, если ваша структура плотно упакована, первый вызов должен получить 0, а второй 4 * GLfloat, потому что это размер первого компонента. Я не уверен, как извлечь эти данные непосредственно из структуры, тем более, что вы используете кортежи.

Для иллюстрации своей структуры:

struct Vertex { 
    var position: (x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) 
    var color: (r: GLfloat, g: GLfloat, b: GLfloat, a: GLfloat) 
} 

является скорее всего выкладывается так:

GLfloat // <-- structure start // <-- position 
GLfloat 
GLfloat 
GLfloat 
GLfloat // <-- color 
GLfloat 
GLfloat 
GLfloat 

position Отсюда лежит смещение 0 и color в 4 * GLfloat.


Чтобы создать указатель со значением 16, this answer выглядит уместным:

let ptr = UnsafePointer<()> + 16 

Поэтому я полагаю, что это должно работать так:

let ptr = UnsafePointer<()> + sizeof(GLfloat) * 4 
+0

Проблема в том, что параметр имеет тип 'UnsafePointer ', поэтому вы не можете просто передать значение 'Int'. Вы должны передать указатель. Я тестировал свою структуру на игровой площадке, и она изложена так, как вы предлагаете, - я думаю, вы правы, что смещение для данных цвета должно быть 16 байт ('4 * sizeof (GLfloat)') из смещения данные позиции, и я пробовал пару перестановок этого, но он по-прежнему падает. –

+0

@ RomanSausarnes вы на 100% уверенно уверены, что указатель имел фактическое значение 16? \ –

+0

Нет, указатель не имеет фактического значения 16 байт, но я взял указатель на начало структуры и продвинул его на 16 байт. –

2

я определил структуру Vertex, как показано ниже:

struct Vertex { 
var x : GLfloat = 0.0 
var y : GLfloat = 0.0 
var z : GLfloat = 0.0 

var r : GLfloat = 0.0 
var g : GLfloat = 0.0 
var b : GLfloat = 0.0 
var a : GLfloat = 1.0 


init(_ x : GLfloat, _ y : GLfloat, _ z : GLfloat, _ r : GLfloat = 0.0, _ g : GLfloat = 0.0, _ b : GLfloat = 0.0, _ a : GLfloat = 1.0) { 
    self.x = x 
    self.y = y 
    self.z = z 

    self.r = r 
    self.g = g 
    self.b = b 
    self.a = a 
} 

, а затем я установил вершины

let vertices : [Vertex] = [ 
    Vertex(1.0, -1.0, 0, 1.0, 0.0, 0.0, 1.0), 
    Vertex(1.0, 1.0, 0, 0.0, 1.0, 0.0, 1.0), 
    Vertex(-1.0, 1.0, 0, 0.0, 0.0, 1.0, 1.0), 
    Vertex(-1.0, -1.0, 0, 1.0, 1.0, 0.0, 1.0) 
] 

let indices : [GLubyte] = [ 
    0, 1, 2, 
    2, 3, 0 
] 

я использую GLKViewController, поэтому glkView (вид: функция drawInRect :), как показано ниже:

override func glkView(view: GLKView, drawInRect rect: CGRect) { 
    glClearColor(1.0, 0.0, 0.0, 1.0); 
    glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) 

    shader.prepareToDraw() 

    glEnableVertexAttribArray(VertexAttributes.Position.rawValue) 
    glVertexAttribPointer(
     VertexAttributes.Position.rawValue, 
     3, 
     GLenum(GL_FLOAT), 
     GLboolean(GL_FALSE), 
     GLsizei(sizeof(Vertex)), BUFFER_OFFSET(0)) 


    glEnableVertexAttribArray(VertexAttributes.Color.rawValue) 
    glVertexAttribPointer(
     VertexAttributes.Color.rawValue, 
     4, 
     GLenum(GL_FLOAT), 
     GLboolean(GL_FALSE), 
     GLsizei(sizeof(Vertex)), BUFFER_OFFSET(3 * sizeof(GLfloat))) // x, y, z | r, g, b, a :: offset is 3*sizeof(GLfloat) 

    glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer) 
    glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer) 
    glDrawElements(GLenum(GL_TRIANGLES), GLsizei(indices.count), GLenum(GL_UNSIGNED_BYTE), nil) 

    glDisableVertexAttribArray(VertexAttributes.Position.rawValue) 

} 

функция BUFFER_OFFSET определяется, как показано ниже:

func BUFFER_OFFSET(n: Int) -> UnsafePointer<Void> { 
    let ptr: UnsafePointer<Void> = nil 
    return ptr + n 
} 

Я могу получить результат

enter image description here

Большое спасибо @Bartek!

+1

Это работает пока, но важно знать, что макет структур Swift официально не определен или не гарантирован стабильностью в версиях компилятора. Вы можете обнаружить, что вам нужно настроить это, когда/если изменяется компилятор Swift. Если вам нужно быть абсолютно уверенным в макете/упаковке данных, определите тип структуры на C и используйте его из Swift. – rickster

+0

@ rickster Прежде всего, большое спасибо за ваш совет. На данный момент я просто изучаю GLKit и Swift. :) – BurtK

Смежные вопросы