iOS --- OpenGLES之着色器(shader)的編譯、鏈接及使用

在上一篇博客 iOS — OpenGLES之着色器(shader)語法介紹 中,簡要介紹了OpenGLES的着色器shader的基本語法,以及Vertex Shader和Fragment Shader的差異。本文中,將簡要介紹着色器(shader)的編譯、鏈接及使用。

Vertex Shader和Fragment Shader

Vertex Shader如下:

// variable pass into
attribute vec4 Position;    // position of vertex
attribute vec4 SourceColor; // color of vertex

// variable pass out into fragment shader
// varying means that calculate the color of every pixel between two vertex linearly(smoothly) according to the 2 vertex's color 
varying vec4 DestinationColor;

void main(void) {
    DestinationColor = SourceColor;
    // gl_Position is built-in pass-out variable. Must config for in vertex shader
    gl_Position = Position;
}

Fragment Shader如下:

varying lowp vec4 DestinationColor;

void main(void) {
    // must set gl_FragColor for fragment shader
    gl_FragColor = DestinationColor;
}

關於Shader的具體含義,請參考上一篇博客 iOS — OpenGLES之着色器(shader)語法介紹

編譯shader

着色器腳本的編譯過程比較固定,主要是以下步驟:

  1. 獲取shader文件
  2. 創建shader對象
  3. 獲取shader的源碼
  4. 編譯shader腳本
  5. 查詢編譯結果

封裝函數如下:

+ (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
    // 1 查找shader文件
    NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:@"glsl"];
    NSError* error;
    NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
    if (!shaderString) {
        NSLog(@"Error loading shader: %@", error.localizedDescription);
        exit(1);
    }

    // 2 創建一個代表shader的OpenGL對象, 指定vertex或fragment shader
    GLuint shaderHandle = glCreateShader(shaderType);

    // 3 獲取shader的source
    const char* shaderStringUTF8 = [shaderString UTF8String];
    int shaderStringLength = [shaderString length];
    glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);

    // 4 編譯shader
    glCompileShader(shaderHandle);

    // 5 查詢shader對象的信息
    GLint compileSuccess;
    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
    if (compileSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
        NSString *messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"%@", messageString);
        exit(1);
    }

    return shaderHandle;
}

對於Vertex Shader和Fragment Shader都要編譯:

GLuint vertexShader = [ShaderOperations compileShader:shaderVertex withType:GL_VERTEX_SHADER];
GLuint fragmentShader = [ShaderOperations compileShader:shaderFragment withType:GL_FRAGMENT_SHADER];

該函數接收的第二個參數用於指定Vertex或Fragment:

#define GL_FRAGMENT_SHADER                               0x8B30
#define GL_VERTEX_SHADER                                 0x8B31

連接Vertex Shader和Fragment Shader

連接Vertex Shader和Fragment Shader成一個完整的OpenGL Shader Program。

GLuint _glProgram = glCreateProgram();
glAttachShader(_glProgram, vertexShader);
glAttachShader(_glProgram, fragmentShader);

glLinkProgram(_glProgram);

// 檢查link狀態
GLint linkSuccess;
glGetProgramiv(_glProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
    GLchar messages[256];
    glGetProgramInfoLog(_glProgram, sizeof(messages), 0, &messages[0]);
    NSString *messageString = [NSString stringWithUTF8String:messages];
    NSLog(@"%@", messageString);
    exit(1);
}

使用Shader

GLuint _positionSlot;   // 用於綁定shader中的Position參數
GLuint _colorSlot;      // 用於綁定shader中的SourceColor參數

glUseProgram(_glProgram); // 讓OpenGL執行glProgram
_positionSlot = glGetAttribLocation(_glProgram, "Position");
_colorSlot = glGetAttribLocation(_glProgram, "SourceColor");

這樣,通過 _positionSlot 和_colorSlot 就可以向Shader中傳遞所需參數,分別對應Position和SourceColor。如給_positionSlot傳遞數據,即頂點數組數據:

GLfloat vertices[] = {
    0.0f,  0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f,
    0.5f,  -0.5f, 0.0f };

// 給_positionSlot傳遞vertices數據
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices );
glEnableVertexAttribArray(_positionSlot); //使用時要enable

Demo地址

本文的一系列demo都可在github中找到,DemoOpenGL,如有不準確的地方,歡迎指正。

參考資料

以上部分,簡要介紹了着色器(Shader)的基本使用情況。主要參考資料:
OpenGL Tutorial for iOS: OpenGL ES 2.0
iOS — OpenGLES之着色器(shader)語法介紹
OpenGL ES渲染管線與着色器

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章