Swift、OpenGL和glvertexattributepointer
我正在将Objective-C代码翻译成Swift,以便学习OpenGL的一些基础知识。我对它完全陌生。我有一个正在工作的项目,它编译并生成一个带有浮动矩形的工作NSOpenGLView,但是颜色不对。我已经将问题缩小到使用指向顶点和颜色数据的Swift、OpenGL和glvertexattributepointer,swift,opengl,nsopenglview,Swift,Opengl,Nsopenglview,我正在将Objective-C代码翻译成Swift,以便学习OpenGL的一些基础知识。我对它完全陌生。我有一个正在工作的项目,它编译并生成一个带有浮动矩形的工作NSOpenGLView,但是颜色不对。我已经将问题缩小到使用指向顶点和颜色数据的glvertexattributepointer函数 以下是存储顶点和颜色数据的方式: struct Vertex { var position: (x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat)
glvertexattributepointer
函数
以下是存储顶点和颜色数据的方式:
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)) )
我试图翻译的glvertexattributepointer
函数的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 ));
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(&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)
}
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))
Objective-C版本使用offsetof
宏设置这些函数的指针参数。Swift不允许使用宏,所以我试图找出在它的位置上使用什么。我尝试过通过nil
,如下所示:
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 ));
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(&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)
}
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))
但如果我这样做,颜色数据数组将填充位置数据-不考虑偏移,因此它将位置数据用于位置和颜色属性
我找到了建议将与unsafepointer一起使用的方法,并进行了尝试,如下所示:
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 ));
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(&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)
}
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))
但这会使整个显示器崩溃,需要强制关机和重新启动
我不知道下一步该试什么。我正在编写的完整代码是可用的
编辑:
我还尝试将指针指向第一个数据点,并将其向前移动4GLfloat
s,如下所示:
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 ));
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(&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)
}
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))
让ptr=UnsafePointer([vertexData.v1.position.x])
GLVertexAttribute指针(GLuint(positionAttribute)、4、UInt32(GL_浮点)、UInt8(GL_假)、GLsizei(sizeof(顶点))、ptr)
GLVertexAttribute指针(GLuint(colorAttribute)、4、UInt32(GL_浮点)、UInt8(GL_假)、GLsizei(sizeof(顶点))、ptr.advancedBy(4))
显示器不会崩溃,但屏幕上根本不会显示任何内容。要复制功能的偏移量,您只需知道每个字段在结构中位于哪个字节偏移量
在您的情况下,假设您的结构是紧密打包的,第一个调用应该接收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
因此,我认为这也应该起作用:
let ptr = UnsafePointer<()> + sizeof(GLfloat) * 4
让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
}
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)
}
func BUFFER_OFFSET(n: Int) -> UnsafePointer<Void> {
let ptr: UnsafePointer<Void> = nil
return ptr + n
}
然后我设置顶点
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:)的功能如下:
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
}
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)
}
func BUFFER_OFFSET(n: Int) -> UnsafePointer<Void> {
let ptr: UnsafePointer<Void> = nil
return ptr + n
}
缓冲区偏移函数的定义如下:
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
}
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)
}
func BUFFER_OFFSET(n: Int) -> UnsafePointer<Void> {
let ptr: UnsafePointer<Void> = nil
return ptr + n
}
func缓冲区\u偏移量(n:Int)->UnsafePointer{
设ptr:UnsafePointer=nil
返回ptr+n
}
我能得到结果
非常感谢@Bartek 问题是参数的类型是UnsafePointer
,因此不能只传入Int
值。你必须传递一个指针。我已经在一个操场上测试了我的结构,它是按照你建议的方式布置的-我认为你是对的,颜色数据的偏移量应该是位置数据偏移量的16个字节(4*sizeof(GLfloat)
),我尝试了一些排列,但它仍然崩溃。@RomanSausarnes您是否100%肯定指针的实际值为16?\@RomanSausarnes:不要这样做,您没有使用客户端内存存储顶点数据。如果您将指针传递到CPU端内存,GPU将不知道如何处理它。取一个空指针并将偏移量添加到该指针上。@RomanSausarnes:在C中,这将是一个大意:(float*)0+
。我不熟悉Objective C。GL只需要一个整数偏移量,函数采用指针类型,但不要让它误导您。当数据是GPU端时,它是一个偏移量,不应该与存储在CPU端的任何数据相关。@RomanSausarnes关于nil+16
?或者这一点目前还有效,但需要注意的一个重要问题是,Swift结构的布局没有正式定义,也没有保证在不同的编译器版本之间保持稳定。您可能会发现,当/如果Swift编译器发生更改,您必须对此进行调整。如果您需要绝对确定数据布局/打包,请在C中定义一个结构类型,并从Swift使用它。@rickster首先,非常感谢您的建议。我现在正在学习GLKit和Swift。:)