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

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

内容简介:前面对 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地址


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

查看所有标签

猜你喜欢:

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

TCP/IP详解 卷1:协议

TCP/IP详解 卷1:协议

W.Richard Stevens / 范建华 / 机械工业出版社 / 2000-4-1 / 45.00元

《TCP/IP详解卷1:协议》是一本完整而详细的TCP/IP协议指南。描述了属于每一层的各个协议以及它们如何在不同操作系统中运行。作者W.Richard Stevens用Lawrence Berkeley实验室的tcpdump程序来捕获不同操作系统和TCP/IP实现之间传输的不同分组。对tcpdump输出的研究可以帮助理解不同协议如何工作。 《TCP/IP详解卷1:协议》适合作为计算机专业学......一起来看看 《TCP/IP详解 卷1:协议》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具