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

栏目: 编程工具 · 发布时间: 5年前

内容简介:前面对 OpenGL ES3.0做了个基本的介绍,这节我们尝试着来写一个OpenGL ES 的 “hello word”程序 — 画一个三角形输入三角形顶点和色值 –> openGL 处理 –> CAEAGLLayer 显示

前面对 OpenGL ES3.0做了个基本的介绍,这节我们尝试着来写一个OpenGL ES 的 “hello word”程序 — 画一个三角形

效果

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

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 流程。

demo地址


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Vim实用技巧

Vim实用技巧

[英] Drew Neil / 杨源、车文隆 / 人民邮电出版社 / 2014-5-1 / 59.00元

vim是一款功能丰富而强大的文本编辑器,其代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中得到非常广泛的使用。vim能够大大提高程序员的工作效率。对于vim高手来说,vim能以与思考同步的速度编辑文本。同时,学习和熟练使用vim又有一定的难度。 《vim实用技巧》为那些想要提升自己的程序员编写,阅读本书是熟练地掌握高超的vim技巧的必由之路。全书共21章,包括121个技巧。每一章......一起来看看 《Vim实用技巧》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换