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地址


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

查看所有标签

猜你喜欢:

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

智慧社会

智慧社会

阿莱克斯·彭特兰 (Alex Pentland) / 汪小帆、汪容 / 浙江人民出版社 / 2015-4 / CNY 56.90

●如果要在大数据领域推举出一个代表性的科学家,阿莱克斯·彭特兰是一个无法令人忽略的名字。经过数年极具开创性的研究,社会物理学这个全新科学领域的根基已足够深厚。社会物理学是关于想法流的科学,正是在想法流的帮助下,我们才得以提高集体智能,促进智慧社会的形成。 ● 通过研究数以百万计的人在智能手机、GPS设备、互联网等地方留下的“数字面包屑”,大数据的应用已成为一股无法被忽视的力量。在大数据的应用......一起来看看 《智慧社会》 这本书的介绍吧!

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

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具