[OpenGL ES] - GLSL

GLSL(OpenGL Shading Language)

  1. 类型
类型 说明
void 空类型
bool 布尔类型
int 有符号整型
vec2, vec3, vec4 二维,三维,四维浮点型向量
bvec2, bvec3, bvec4 二维,三维,四维布尔型向量
mat2, mat3, mat4 二维,三维,四维浮点型矩阵
sampler1D, sampler2D, sampler3D 一维,二维,三维纹理
  1. 变量修饰符
修饰符 说明
attribute 全局、只读,只能存在于vertex shader中使用,一般用于修饰顶点、法线、颜色、纹理等数据
uniform 全局、只读,由外部程序传递给vertex shader、fragment shader变量,一般用于修饰视图矩阵、投影矩阵、光源信息等环境数据
varying 用于在vertex shader和fragment shader中传递值

使用GLSL

  1. 设置上下文
        self.glkView = self.view as! GLKView
        
        self.context = EAGLContext.init(api: .openGLES2)
        if context == nil {
            context = EAGLContext.init(api: .openGLES2)
        }
        
        guard let ctx = context else {
            return
        }
        EAGLContext.setCurrent(ctx) // 设置当前上下文
  1. 着色器程序
vertexShader.glsl
uniform highp mat4 u_ModelViewMatrix; // 模型视图矩阵
uniform highp mat4 u_ProjectionMatrix;  // 投影矩阵

attribute vec4 a_Position;   // 顶点坐标
attribute vec4 a_Color;  // 颜色坐标
attribute vec2 a_TexCoord;  // 纹理坐标

varying lowp vec4 frag_Color;   // 传递到片元着色器的颜色坐标
varying lowp vec2 frag_TexCoord; // 传递到片元着色器的纹理坐标

void main(void) {
    frag_Color = a_Color;
    frag_TexCoord = a_TexCoord;
    gl_Position = u_ProjectionMatrix * u_ModelViewMatrix * a_Position;
}
fragmentShader.glsl
uniform sampler2D u_Texture;  // 2D纹理

varying lowp vec4 frag_Color;
varying lowp vec2 frag_TexCoord;

void main(void) {
    gl_FragColor = texture2D(u_Texture, frag_TexCoord);
}

2.1 编译着色器程序

    // 编译着色器
    func compileShader(_ shaderName:String, shaderType:GLenum) ->GLuint {
        // shader file path
        let path = Bundle.main.path(forResource: shaderName, ofType: nil)
        do {
            // shader file content string
            let shaderString = try NSString(contentsOfFile: path!, encoding: String.Encoding.utf8.rawValue)
            // 根据类型创建一个shader
            let shaderHandle = glCreateShader(shaderType)
            var shaderStringLength:GLint = GLint(Int32(shaderString.length))
            var shaderCString = shaderString.utf8String
            /// 将shader源码附加带shader对象上
            ///
            /// - Parameters:
            ///   - shader: shader对象
            ///   - count: 源码字符串个数
            ///   - string: 源码字符串
            ///   - length: 源码字符串长度
            glShaderSource(shaderHandle, GLsizei(1), &shaderCString, &shaderStringLength)
            
            // 编译shader
            glCompileShader(shaderHandle)
            var compileStatus : GLint = 0
            // 获取编译状态
            glGetShaderiv(shaderHandle, GLenum(GL_COMPILE_STATUS), &compileStatus)
            
            if compileStatus == GL_FALSE { // 编译失败
                
                var infoLength : GLsizei = 0
                let bufferLength : GLsizei = 1024
                
                glGetShaderiv(shaderHandle, GLenum(GL_INFO_LOG_LENGTH), &infoLength)
                // 创建char数组
                let info : [GLchar] = Array(repeating: GLchar(0), count: Int(bufferLength))
                var actualLength : GLsizei = 0
                // 获取错误信息
                glGetShaderInfoLog(shaderHandle, bufferLength, &actualLength, UnsafeMutablePointer(mutating: info))
                NSLog(String(validatingUTF8: info)!)
                exit(1)
            }
            
            return shaderHandle
            
        } catch {
            exit(1)
        }
    }
    // 将顶点着色器和片元着色器编译后附加到程序中然后链接程序
    func compile(vertexShader: String, fragmentShader: String) {
        // 1.编译着色器
        let vertexShader = self.compileShader(vertexShader, shaderType: GLenum(GL_VERTEX_SHADER))
        let fragmentShader = self.compileShader(fragmentShader, shaderType: GLenum(GL_FRAGMENT_SHADER))
        
        // 2.创建程序
        self.program = glCreateProgram()
        // 3.将shader附加到程序中
        glAttachShader(program, vertexShader)
        glAttachShader(program, fragmentShader)
        
        glBindAttribLocation(program, VertexAttributes.position.rawValue, "a_Position") // 顶点坐标属性
        glBindAttribLocation(program, VertexAttributes.color.rawValue, "a_Color") // 颜色坐标属性
        glBindAttribLocation(program, VertexAttributes.texCoord.rawValue, "a_TexCoord") // 纹理坐标属性
        // 4.链接
        glLinkProgram(program)
        
        self.modelViewMatrixUniform = glGetUniformLocation(program, "u_ModelViewMatrix") // 模型视图矩阵
        self.projectionMatrixUniform = glGetUniformLocation(program, "u_ProjectionMatrix") // 投影矩阵
        self.textureUniform = glGetUniformLocation(program, "u_Texture") // 纹理
        
        var linkStatus : GLint = 0
        // 获取链接状态
        glGetProgramiv(self.program, GLenum(GL_LINK_STATUS), &linkStatus)
        if linkStatus == GL_FALSE {
            var infoLength : GLsizei = 0
            let bufferLength : GLsizei = 1024
            glGetProgramiv(self.program, GLenum(GL_INFO_LOG_LENGTH), &infoLength)
            
            let info : [GLchar] = Array(repeating: GLchar(0), count: Int(bufferLength))
            var actualLength : GLsizei = 0
            
            glGetProgramInfoLog(self.program, bufferLength, &actualLength, UnsafeMutablePointer(mutating: info))
            NSLog(String(validatingUTF8: info)!)
            exit(1)
        }
    }
  1. 设置VAO
    func setupVAO() {
        // 申请vao空间
        glGenVertexArraysOES(1, &vao)
        glBindVertexArrayOES(vao)
        // 顶点buffer
        var vertexBuffer: GLuint = 0
        glGenBuffers(1, &vertexBuffer)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)
        glBufferData(GLenum(GL_ARRAY_BUFFER), vertexs.size(), vertexs, GLenum(GL_STATIC_DRAW))
        // 索引buffer
        var indexBuffer: GLuint = 0
        glGenBuffers(1, &indexBuffer)
        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
        glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexList.size(), indexList, GLenum(GL_STATIC_DRAW))
        // 顶点坐标
        let positionSlotFirstComponent = UnsafePointer<Int>(bitPattern: 0)
        glEnableVertexAttribArray(VertexAttributes.position.rawValue)
        glVertexAttribPointer(VertexAttributes.position.rawValue, 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<Vertex>.size), positionSlotFirstComponent)
        // 颜色坐标
        let colorSlotFirstComponent = UnsafePointer<Int>(bitPattern: MemoryLayout<GLfloat>.size * 3)
        glEnableVertexAttribArray(VertexAttributes.color.rawValue)
        glVertexAttribPointer(VertexAttributes.color.rawValue, 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<Vertex>.size), colorSlotFirstComponent)
        // 纹理坐标
        let texSlotFirstComponent = UnsafePointer<Int>(bitPattern: MemoryLayout<GLfloat>.size * 7)
        glEnableVertexAttribArray(VertexAttributes.texCoord.rawValue)
        glVertexAttribPointer(VertexAttributes.texCoord.rawValue, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout<Vertex>.size), texSlotFirstComponent)
        
        glBindVertexArrayOES(0)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), 0)
        
    }
  1. 设置投影矩阵和模型视图矩阵然后渲染
    // 投影矩阵
    self.projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(85.0),GLfloat(self.view.bounds.size.width / self.view.bounds.size.height),1,150)
    // 模型矩阵
    func modelMatrix() -> GLKMatrix4 {
        var modelMatrix : GLKMatrix4 = GLKMatrix4Identity
        modelMatrix = GLKMatrix4Translate(modelMatrix, self.position.x, self.position.y, self.position.z)
        modelMatrix = GLKMatrix4Rotate(modelMatrix, self.rotationX, 1, 0, 0)
        modelMatrix = GLKMatrix4Rotate(modelMatrix, self.rotationY, 0, 1, 0)
        modelMatrix = GLKMatrix4Rotate(modelMatrix, self.rotationZ, 0, 0, 1)
        modelMatrix = GLKMatrix4Scale(modelMatrix, self.scale, self.scale, self.scale)
        return modelMatrix
    }
    // 渲染
    override func glkView(_ view: GLKView, drawIn rect: CGRect) {
        
        glClearColor(1.0, 1.0, 1.0, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))
        
        glEnable(GLenum(GL_DEPTH_TEST))
        // 模型矩阵
        self.modelViewMatrix = modelMatrix()
        // 准备绘制
        self.prepareToDraw()
        // render
        glBindVertexArrayOES(vao)
        glDrawElements(GLenum(GL_TRIANGLES), GLsizei(indexList.count), GLenum(GL_UNSIGNED_B
    }

结尾

DEMO源码地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容