这是我从零开始学OpenGL,也是从零开始学Swift,多说无益,先来个HelloWorld, 绘制一个长方形,效果如下:
A3F0F8A8-8C39-4B56-92AC-50E783628A21.png首先来个核心的概念--缓存,几乎所有的程序提供给GPU的数据都应该放在缓存中,而为缓存提供数据主要有7个步骤:
- 生成(Generate)
- 绑定(Bind)
- 缓存数据(Buffer Data)
- 启用(Enable)或者禁用(Disable)
- 设置指针(Set Pointers)
- 绘图(Draw)
- 删除(Delete)
核心函数
- glGenBuffers()--生成一个唯一的缓存标识符
- glBindBuffers()--绑定接下来使用的缓存
- glBufferData() or glBufferSubData()--为绑定的缓存进行分配并初始化足够的连续内存
- glEnableVertexAttribArray() or glDisableVertexAttribArray()--接下来的渲染是否使用缓存中的数据
- glVertexAttribPointer()--缓存中的数据类型和需要访问数据的内存偏移量
- glDrawArrays() or glDrawElements()--使用绑定的缓存整个场景或一部分
- glDeleteBuffers()--删除缓存并释放资源
--------------------------------------适配 Swift 3.0,顺便复习 17.04.12 --------------------------------------
详细实现
1.顶点数组
import GLKit
extension Array {
func size() -> Int {
if self.count > 0 {
return self.count * MemoryLayout.size(ofValue: self[0])
}
return 0;
}
}
struct SceneVertex {
var positionCoords : GLKVector3
}
var vertices = [
SceneVertex(positionCoords: GLKVector3Make(-0.5, -0.5, 0.0)),
SceneVertex(positionCoords: GLKVector3Make(0.5, -0.5, 0.0)),
SceneVertex(positionCoords: GLKVector3Make(0.5, 0.5, 0.0)),
SceneVertex(positionCoords: GLKVector3Make(-0.5, 0.5, 0.0))
]
class ViewController: GLKViewController {
var vertextBufferId: GLuint = GLuint()
var baseEffect = GLKBaseEffect()
override func viewDidLoad() {
super.viewDidLoad()
let view = self.view as! GLKView
view.context = EAGLContext(api: .openGLES3)
EAGLContext.setCurrent(view.context)
//使用恒定不变的颜色
baseEffect.useConstantColor = GLboolean(UInt8(GL_TRUE))
baseEffect.constantColor = GLKVector4Make(1, 0, 1, 1)
/**
&0:生成缓存标识符的数量
&1:生成标识符的内存位置
*/
glGenBuffers(1, &vertextBufferId)
//绑定缓存
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertextBufferId)
//缓存数据
glBufferData(GLenum(GL_ARRAY_BUFFER), vertices.size(), vertices, GLenum(GL_STATIC_DRAW))
}
override func glkView(_ view: GLKView, drawIn rect: CGRect) {
baseEffect.prepareToDraw()
glClear(GLenum(GL_COLOR_BUFFER_BIT))
glEnableVertexAttribArray(0)
glVertexAttribPointer(
0,
3, //坐标轴数
GLenum(GL_FLOAT),
GLboolean(UInt8(GL_FALSE)),
GLsizei(MemoryLayout<SceneVertex>.size),
nil
)
glDrawArrays(
GLenum(GL_TRIANGLE_FAN), //根据实际来设置样式
0, //从buffers中的第一个vertice开始
GLsizei(vertices.count)
)
}
}
GL_TRIANGLE_FAN 是一个铺满的三角形,因为有四个顶点,所以成了一个长方形,如果 GL_LINE_LOOP 就成了一个空心的正方形了,GL_LINES 则是二条线,其它的效果可以自己分别体验。
源码点这里,喜欢就关注吧,持续更新中。
网友评论
我看了你和这个地址的例子.
有几个地方不同点
1. 你用GLKView , 他那边使用了UIView+CAEAGLLayer
2. 他在画的时候使用了 glBindVertexArrayOES(VAO). 你那边没有相关代码
3. 你使用了` override func glkView(_ view: GLKView, drawIn rect: CGRect)`这个代理方法
4. glViewport(0, 0, GLint(self.frame.size.width), GLint(self.frame.size.height))
我这边目前偏向的写法是 UIView+CAEAGLLayer+drawRect.
因为正在考虑替换现有的绘图代码 , 我现在的UIView里面已delegate, 跟GLKView的delegate有冲突, 所以我这边不能使用GLKView
基于我现在试验的方案, 在写demo的过程中遇到一些问题
1. 这里不明白为什么你那边没有glBindVertexArrayOES 可以画出来.
2. 你那边没有glViewport调用为什么坐标系也不存在问题?
3. 如果自定义一个类似GLKView, 对于drawRect的内部操作如何控制比较好. 我现在的想法是把clear, present放到负累里面去 . 让子类重写drawRect的时候 只管自己相关的绘制 . 不知道这样放置是否合理
glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
…
self.context.presentRenderbuffer(Int(GL_RENDERBUFFER))