OpenGL ES 3.0入门之画一个三角形

bancheng发布

前面对 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脚本

初始化顶点坐标

将顶点坐标推给OpenGL

渲染

写在最后

写这篇博客的时候刚刚开始学 openGLES,在写这个博客的demo时候,各种查资料零零散散 费半日之力才成。在写的过程中出现了许多问题主要还是openGL es api方面的熟悉,api中各种参数代表的含义还是有多多的不了解。通过写这个demo我主要学习到一下几点
* 所有的buffer 都需要有 申请–>绑定–>使用的一个过程
* shader的主要流程有, 创建–>加载–>编译–>检测编译状态–>装配到着色程序–>着色程序进行链接–>使用着色程序的过程
* 顶点buffer必须有glGenBuffers –> glBindBuffer –> glBufferData –> glEnableVertexAttribArray –> glVertexAttribPointer 流程。

demo地址


bancheng

iOS开发者一枚,现就职中国北京。在这里记录自己开发遇到的问题和学习记录的笔记。喜欢学习、摄影。

发表评论

电子邮件地址不会被公开。 必填项已用*标注