内容简介:前面对 OpenGL ES3.0做了个基本的介绍,这节我们尝试着来写一个OpenGL ES 的 “hello word”程序 — 画一个三角形输入三角形顶点和色值 –> openGL 处理 –> CAEAGLLayer 显示
前面对 OpenGL ES3.0做了个基本的介绍,这节我们尝试着来写一个OpenGL ES 的 “hello word”程序 — 画一个三角形
效果
EAGLContext 和 CAEAGLLayer
- EAGLContext对象是管理OpenGL ES渲染上下文,若想使用OpenGL ES 进行绘制工作,则必须一个上下文对象。该对象管理者openGL ES 绘制使用的上下文对象
-
CAEAGLLayer 将OpenGL ES 渲染结果显示的屏幕上的layer (TODO:开一篇单独介绍)
流程
输入三角形顶点和色值 –> openGL 处理 –> CAEAGLLayer 显示
初始化 OpenGL 环境
var context: EAGLContext? = EAGLContext(api: .openGLES3) var glLayer: CAEAGLLayer { return layer as! CAEAGLLayer } open override class var layerClass: Swift.AnyClass { return CAEAGLLayer.self } private func setupLlayer() { glLayer.opacity = 1.0 glLayer.drawableProperties = [ kEAGLDrawablePropertyRetainedBacking: true, kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8, ] } private func setupContext() { if context == nil { context = EAGLContext(api: .openGLES2) } assert(context != nil && EAGLContext.setCurrent(context), "初始化环境失败") }
初始化 frameBuffer 和 renderBuffer
为什么要用两个buffer,这个跟OpenGL 内部优化有关系(TODO:另外开一篇博客,写好了贴链接)
frameBuffer 负责管理buffer缓冲区的和显示buffer切换。
renderBuffer 负责将渲染结果推到CAEAGLLayer显示。
//初始化 frameBuff private func setupFrameBuffer() { deleteFrameBuff() glGenFramebuffers(1, &frameBuffer) glBindFramebuffer(GLenum(GL_FRAMEBUFFER), frameBuffer) glFramebufferRenderbuffer( GLenum(GL_FRAMEBUFFER), GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_RENDERBUFFER), renderBuffer) } private func deleteFrameBuff() { if frameBuffer != 0 { glDeleteBuffers(1, &frameBuffer) frameBuffer = 0 } } //初始化 renderBuffer private func setupRenderBuffer() { deleteRenderBuffer() glGenRenderbuffers(1, &renderBuffer) glBindRenderbuffer(GLenum(GL_RENDERBUFFER), renderBuffer) context?.renderbufferStorage(Int(GL_RENDERBUFFER), from: glLayer) } private func deleteRenderBuffer() { if renderBuffer != 0 { glDeleteBuffers(1, &renderBuffer) renderBuffer = 0 } }
- glGenFramebuffers(_ n: GLsizei, _ framebuffers: UnsafeMutablePointer
!) 申请 n 个 frameBuffer 并返回申请的 frameBuffer的id列表 - glBindRenderbuffer(_ target: GLenum, _ renderbuffer: GLuint) 将申请到的 frameBuffer 绑定到 OpenGL ES 中
- glFramebufferRenderbuffer 将frameBuffer 和 renderbuffer关联
- glGenRenderbuffers:申请n个renderBuffer
- glBindRenderbuffer:将申请到的 renderBuffer 绑定到 OpenGL ES 中
- glDeleteBuffers: 删除指定的buffer
检查 frameBuffer 状态
private func checkFrameBuffer() throws -> Bool { let status: GLenum = glCheckFramebufferStatus(GLenum(GL_FRAMEBUFFER)) var result: Bool = false var errorMessage: String = "" print("\(GLenum(GL_FRAMEBUFFER_UNSUPPORTED))," + "\(GLenum(GL_FRAMEBUFFER_COMPLETE))," + "\(GLenum(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT))," + "\(GLenum(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS)),") switch status { case GLenum(GL_FRAMEBUFFER_UNSUPPORTED): errorMessage = "framebuffer不支持该格式" result = false case GLenum(GL_FRAMEBUFFER_COMPLETE): print("frame buffer 创建成功") result = true case GLenum(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT): errorMessage = "Framebuffer不完整 缺失组件" result = false case GLenum(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS): errorMessage = "Framebuffer 不完整, 附加图片必须要指定大小" result = false default: errorMessage = "未知错误" result = false } if errorMessage.isEmpty == false { let error: NSError = NSError(domain: "com.colin.error", code: Int(status), userInfo: ["errorMSG": errorMessage]) throw error } return result }
编写shader脚本
- 顶点着色器脚本
attribute vec4 position; attribute vec4 color; varying vec4 colorVarying; void main(void) { colorVarying = color; gl_Position = position; }
- 片段着色器脚本
varying lowp vec4 colorVarying; void main(void) { gl_FragColor = colorVarying; }
编译、链接shader脚本
open class ShaderCompiler{ open class func loadShader(_ vertPath:String,fragPath:String)throws -> GLuint { var verShader:GLuint = 0,fragShader:GLuint = 0 do { verShader = try self.compileShader(vertPath, type:GLenum(GL_VERTEX_SHADER)) fragShader = try self.compileShader(fragPath, type: GLenum(GL_FRAGMENT_SHADER)) //创建着色程序 let program:GLuint = glCreateProgram() //装配 着色程序 glAttachShader(program, verShader) glAttachShader(program, fragShader) glLinkProgram(program) programLog(GLenum(GL_LINK_STATUS), program: program) return program } catch let error { print(error) throw error } } open class func compileShader(_ shaderPath:String,type:GLenum)throws -> GLuint{ do { let shaderStr:String = try String.init(contentsOfFile: shaderPath) let shaderStringUTF8 = shaderStr.cString(using:.utf8) var shaderStringUTF8Pointer = UnsafePointer<GLchar>(shaderStringUTF8) var shaderStringLength: GLint = GLint(Int32(shaderStr.count)) let shaderHandle:GLuint = glCreateShader(type) glShaderSource(shaderHandle, 1,&shaderStringUTF8Pointer, &shaderStringLength) glCompileShader(shaderHandle) shaderLog(GLenum(GL_COMPILE_STATUS), shader: shaderHandle) return shaderHandle } catch let error { print(error) throw error } } open class func programLog(_ statue:GLenum,program:GLuint) { var linkSucc:GLint = 0 glGetProgramiv(program, GLenum(statue), &linkSucc) if linkSucc == GL_FALSE { var message:Array<GLchar> = Array<GLchar>.init(repeating: 0, count: 256) glGetProgramInfoLog(program, GLsizei(MemoryLayout<GLchar>.stride * message.count), nil, &message[0]) let msg = String.init(cString: message) print("gl link program fail msg = \(msg)") exit(1) } else { print("link ok") } } open class func shaderLog(_ statue:GLenum,shader:GLuint){ var status:GLint = 0 glGetShaderiv(shader, statue, &status) if status == GL_FALSE { var message:Array<GLchar> = Array<GLchar>.init(repeating: 0, count: 256) glGetShaderInfoLog(shader, GLsizei(MemoryLayout<GLchar>.stride * message.count), nil, &message[0]) let msg = String.init(cString: message) print("glGetShaderiv shaderIngoLog type = \(statue) shader = \(shader) "+" \(msg)") exit(1) } else { print("\(statue) \(shader) shader 操作成功") } } }
初始化顶点坐标
//前三位为顶点坐标 后四位为顶点色值rgba var vertices: [GLfloat] = [ -0.5, 0.5, 1.0, 1, 0, 0, 1, -0.5, -0.5, 1.0, 0, 1, 0, 1, 0.5, -0.5, 1.0, 0, 0, 1, 1, ]
将顶点坐标推给OpenGL
private func setupVBOs() { var vertexBuffer: GLuint = 0 glGenBuffers(1, &vertexBuffer) glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer) glBufferData(GLenum(GL_ARRAY_BUFFER), MemoryLayout<GLfloat>.size * vertices.count, vertices, GLenum(GL_STATIC_DRAW)) }
渲染
private func render() { glBindFramebuffer(GLenum(GL_FRAMEBUFFER), frameBuffer) glBindRenderbuffer(GLenum(GL_RENDERBUFFER), renderBuffer) glClearColor(0, 1, 1, 1) glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) glViewport(0, 0, GLsizei(frame.width),GLsizei(frame.height)) glVertexAttribPointer(GLuint(self.positon), 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 7), nil) let offset: GLsizeiptr = MemoryLayout<GLfloat>.size * 3 glVertexAttribPointer(GLuint(self.color), 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<GLfloat>.size * 7), UnsafeRawPointer(bitPattern: offset)) glDrawArrays(GLenum(GL_TRIANGLES), 0, 3) context?.presentRenderbuffer(Int(GL_RENDERBUFFER)) }
写在最后
写这篇博客的时候刚刚开始学 openGLES,在写这个博客的demo时候,各种查资料零零散散 费半日之力才成。在写的过程中出现了许多问题主要还是openGL es api方面的熟悉,api中各种参数代表的含义还是有多多的不了解。通过写这个demo我主要学习到一下几点
* 所有的buffer 都需要有 申请–>绑定–>使用的一个过程
* shader的主要流程有, 创建–>加载–>编译–>检测编译状态–>装配到着色程序–>着色程序进行链接–>使用着色程序的过程
* 顶点buffer必须有glGenBuffers –> glBindBuffer –> glBufferData –> glEnableVertexAttribArray –> glVertexAttribPointer 流程。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- WebGL 3D 入门系列:绘制渐变三角形 --- 深入理解缓冲区
- CSS三角形和饼图
- go gl 彩色的三角形
- 【Leetcode】120.三角形最小路径和
- 【WPF】用三角形网格构建三维图形
- 音视频之opengl绘制三角形
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。