Swift、OpenGL 和 glVertexAttribPointer
Swift, OpenGL and glVertexAttribPointer
我正在将 this repo 中的 Objective-C 代码翻译成 Swift,以学习 OpenGL 的一些基础知识。我对它完全陌生。我有一个工作项目可以编译并生成一个带有浮动矩形的工作 NSOpenGLView,但是颜色是错误的。我已将问题缩小到我使用指向顶点和颜色数据的 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)) )
我尝试翻译的 glVertexAttribPointer
函数的 Objective-C 版本如下所示:
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)
但是如果我这样做,颜色数据数组将填充位置数据 - 不考虑偏移量,因此它使用位置数据作为位置和颜色属性。
我发现 建议使用 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.
编辑:
我也试过将指针指向第一个数据点并将其前进 4 GLfloat
s,如下所示:
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))
显示没有崩溃,但屏幕上根本没有绘制任何内容。
要复制 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
我定义了如下顶点结构:
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(view: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
}
我可以得到结果
非常感谢@Bartek!
我正在将 this repo 中的 Objective-C 代码翻译成 Swift,以学习 OpenGL 的一些基础知识。我对它完全陌生。我有一个工作项目可以编译并生成一个带有浮动矩形的工作 NSOpenGLView,但是颜色是错误的。我已将问题缩小到我使用指向顶点和颜色数据的 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)) )
我尝试翻译的 glVertexAttribPointer
函数的 Objective-C 版本如下所示:
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)
但是如果我这样做,颜色数据数组将填充位置数据 - 不考虑偏移量,因此它使用位置数据作为位置和颜色属性。
我发现 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.
编辑:
我也试过将指针指向第一个数据点并将其前进 4 GLfloat
s,如下所示:
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))
显示没有崩溃,但屏幕上根本没有绘制任何内容。
要复制 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
我定义了如下顶点结构:
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(view: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
}
我可以得到结果
非常感谢@Bartek!