OpenGLES入门笔记四

原文参考地址:http://www.cnblogs.com/zilongshanren/archive/2011/08/08/2131019.html

一、编译Vertex Shaders和Fragment Shaders

  目前为止,xcode仅仅会把这个两个文件(simple.vertsh和simple.fragsh)copy到application bundle中。我们还需要在运行编译和运行这些Shaders。

  你会很诧异,为什么要在app运行时编译代码?

  这样做的好处是:我们的Shaders不用依赖于某种图形芯片(这样可以跨平台嘛)。

  下面开始加入动态编译的代码(两种方式。1.直接在OpenGLView写入;2.创建工具类)

  我选用第二种方式创建动态编译的代码:

  在Project中,新建继承NSObject的LVApplicationShaderUtils类。

  贴下代码:

- (GLuint)compileShader:(NSString *)shaderFileName withType:(GLenum)shaderType
{
    NSString * shaderName = [[shaderFileName lastPathComponent] stringByDeletingPathExtension];
    NSString * shaderFileType = [shaderFileName pathExtension];
    NSLog(@"文件名称:%@ 文件类型:%@",shaderName,shaderFileType);
    
    //!> 1
    NSString * shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:shaderFileType];
    NSLog(@"文件路径:%@",shaderPath);
    
    NSError * error = nil;
    NSString * shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
    if (!shaderPath)
    {
        NSLog(@"错误加载shader(%@):%@",shaderFileName,error.localizedDescription);
        return 0;
    }
    
    //!> 2
    GLuint shaderHandle = glCreateShader(shaderType);
    
    //!> 3
    const char * shaderStringUTF8 = [shaderString UTF8String];
    GLint shaderStringLength = (GLint)[shaderString length];
    glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
    
    //!> 4
    glCompileShader(shaderHandle);
    
    //!> 5
    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(@"错误编译shader(%@):%@",shaderFileName,messageString);
        return 0;
    }
    
    return shaderHandle;
}

如果你感觉跟入门笔记一中的方法有很多不同,恭喜你。

1.找到.vertsh 和 .fragsh文件路径。

2.调用glCreateShader来创建一个代表shader的OpenGL对象,需要一个参数

/* Shaders */
#define GL_FRAGMENT_SHADER 0x8B30 // 代表片元着色器类型对象
#define GL_VERTEX_SHADER   0x8B31 // 代表顶点着色器类型对象

3.glShaderSource,让OpenGL获取到这个Shader的源代码,把NSString文件内容转换成C-String(null-terminated string)。

4.最后,调用glCompileShader在运行时编译Shader。

5.使用glGetShaderiv和glGetShaderInfoLog打印error日志。

/* Boolean */
#define GL_FALSE                                         0
#define GL_TRUE                                          1
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(@"错误编译shader(%@):%@",shaderFileName,messageString);
        return 0;
    }
判断异常常规写法

这个代码写法一般都是这样写的。可以直接copy~~

二、如果编译好了Vertex Shader和Fragment Shader之后,我们需要把两个Shader关联起来。

typedef NS_ENUM(NSInteger,compileProgramError)
{
    compileProgramErrorShaders = -1101,  //!> Shader创建失败
    compileProgramErrorProgram = -1102,  //!> Program object 创建失败
    compileProgramErrorLink    = -1103   //!> link 失败
};
- (NSInteger)linkProgramHandle
{
    //!> 1
    GLuint vertexShader = [self compileShader:@"Simple.vertsh" withType:GL_VERTEX_SHADER];
    GLuint fragmentShader = [self compileShader:@"Simple.fragsh" withType:GL_FRAGMENT_SHADER];
    if ((vertexShader == 0)||(fragmentShader == 0))
    {
        NSLog(@"错误:错误编译Shaders");
        return compileProgramErrorShaders;
    }
    
    //!> 2
    GLuint programHandle = glCreateProgram();
    if (programHandle == 0)
    {
        NSLog(@"错误:不能创建Program object");
        return compileProgramErrorProgram;
    }
    glAttachShader(programHandle, vertexShader);
    glAttachShader(programHandle, fragmentShader);
    glLinkProgram(programHandle);
    
    //!>3
    GLint linkSuccess;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE)
    {
        GLchar messages[256];
        glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
        NSString * messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"Error link Shaders:%@",messageString);
        return compileProgramErrorLink;
    }
    return programHandle;
}

解析:

1.用compileShader方法动态编译了Vertex Shader和Fragment Shader两个对象。

2.调用glCreateProgram、glAttachShader、glLinkProgram连接Vertex Shader和Fragment Shader形成一个完成的Program。

3.调用glGetProgram、glGetProgramInfoLog方法来检查error,跟动态编译Shader的方法中检查方法类似。

GLint linkSuccess;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE)
    {
        GLchar messages[256];
        glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
        NSString * messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"Error link Shaders:%@",messageString);
        return compileProgramErrorLink;
    }
检查是否有error

常规方法都是这样写的,也是可以直接copy的哦~~

最后准确无误了,就返回programHandle,项目句柄 

三、接下来让OpenGL执行Program,使用的就是programHandle。 

OpenGL示例代码:https://github.com/nLoser/OpenGLES_Study

原文地址:https://www.cnblogs.com/R0SS/p/5093758.html