原文参考地址: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 ;
} //!> 2
GLuint shaderHandle = glCreateShader(shaderType); //!> 3
const char * shaderStringUTF8 = [shaderString UTF8String];
GLint shaderStringLength = (GLint)[shaderString length];
glShaderSource(shaderHandle, , &shaderStringUTF8, &shaderStringLength); //!> 4
glCompileShader(shaderHandle); //!> 5
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE)
{
GLchar messages[];
glGetShaderInfoLog(shaderHandle, sizeof(messages), , &messages[]);
NSString * messageString = [NSString stringWithUTF8String:messages];
NSLog(@"错误编译shader(%@):%@",shaderFileName,messageString);
return ;
} 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[];
glGetShaderInfoLog(shaderHandle, sizeof(messages), , &messages[]);
NSString * messageString = [NSString stringWithUTF8String:messages];
NSLog(@"错误编译shader(%@):%@",shaderFileName,messageString);
return ;
}

判断异常常规写法

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

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

typedef NS_ENUM(NSInteger,compileProgramError)
{
compileProgramErrorShaders = -, //!> Shader创建失败
compileProgramErrorProgram = -, //!> Program object 创建失败
compileProgramErrorLink = - //!> 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 == )||(fragmentShader == ))
{
NSLog(@"错误:错误编译Shaders");
return compileProgramErrorShaders;
} //!> 2
GLuint programHandle = glCreateProgram();
if (programHandle == )
{
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[];
glGetProgramInfoLog(programHandle, sizeof(messages), , &messages[]);
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[];
glGetProgramInfoLog(programHandle, sizeof(messages), , &messages[]);
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

OpenGLES入门笔记四的更多相关文章

  1. OpenGLES入门笔记三

    在入门笔记一中比较详细的介绍了顶点着色器和片面着色器. 在入门笔记二中讲解了简单的创建OpenGL场景流程的实现,但是如果在场景中渲染任何一种几何图形,还是需要入门笔记一中的知识:Vertex Sha ...

  2. OpenGLES入门笔记一

    学习地址:http://www.raywenderlich.com/3664/opengl-tutorial-for-ios-opengl-es-2-0 中文翻译:http://www.cnblogs ...

  3. OpenGLES入门笔记二

    #import <UIKit/UIKit.h> #import <QuartzCore/QuartzCore.h> #import <OpenGLES/ES2/gl.h& ...

  4. SpringBoot入门笔记(四)、通常Mybatis项目目录结构

    1.工程启动类(AppConfig.java) 2.实体类(domain) 3.数据访问层(dao) 4.数据服务层(service) 5.前端控制器(controller) 6.工具类(util) ...

  5. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  6. redis入门笔记(2)

    redis入门笔记(2) 上篇文章介绍了redis的基本情况和支持的数据类型,本篇文章将介绍redis持久化.主从复制.简单的事务支持及发布订阅功能. 持久化 •redis是一个支持持久化的内存数据库 ...

  7. redis入门笔记(1)

    redis入门笔记(1) 1. Redis 简介 •Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure serv ...

  8. MySQL入门笔记

    MySQL入门笔记 版本选择: 5.x.20 以上版本比较稳定 一.MySQL的三种安装方式: 安装MySQL的方式常见的有三种: ·          rpm包形式 ·          通用二进制 ...

  9. MySQL入门笔记(一)

    一.数据类型 1. 整型 2. 浮点型 3. 字符型 4. 日期时间型 二.数据库操作 1. 创建库 CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_nam ...

随机推荐

  1. 你能熟练使用Dictionary字典和List列表吗?(转)

    命名空间System.Collections.Generic中有两个非常重要,而且常用的泛型集合类,它们分别是Dictionary<TKey,TValue>字典和List<T> ...

  2. strlen 与 sizeof 的区别

    void ngx_time_init(void) { ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1 ...

  3. [译]用AngularJS构建大型ASP.NET单页应用(二)

    原文地址:http://www.codeproject.com/Articles/808213/Developing-a-Large-Scale-Application-with-a-Single 客 ...

  4. sql 重复数据只保留一条

    用SQL语句,删除掉重复项只保留一条在几千条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复的呢1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 select * ...

  5. Android之Activity跳转

    简述 如果把每个activity看成一个页面的话,那么activity之间的跳转和页面的之间的跳转基本上是一样的.首先需要监听一个事件,当这个事件发生的时候,就进行跳转.html中有个<a sr ...

  6. android开发------第一个android程序

    好吧,现在我们就一起来写第一个android程序,看它带给了我们什么.sdk的使用和虚拟机的创建我就不说了.项目创建过程先略过,不太重要. 那第一个程序我们能学到什么知识呢?一起看吧.^-^ 在IDE ...

  7. A query was run and no Result Maps were found for the Mapped Statement 'user.insertUser!selectKey'. It's likely that neither a Result Type nor a Result Map was specified.

    使用mybatis时出现异常问题: 有如下的错误 Error querying database. Cause: org.apache.ibatis.executor.ExecutorExceptio ...

  8. 【POJ 1279】Art Gallery

    http://poj.org/problem?id=1279 裸的半平面交的模板,按极角排序后维护一个双端队列,不要忘了最后要去除冗余,即最后一条边(或者更多的边)一定在双端队列里,但它不一定构成半平 ...

  9. 【BZOJ 2599】【IOI 2011】Race 点分治

    裸的点分治,然而我因为循环赋值$s$时把$i <= k$写成$i <= n$了,WA了好长时间 #include<cstdio> #include<cstring> ...

  10. mnsday2t1

    枚举每个数的因子,然后该因子数量+1,最后扫描一遍,如果该因子数量小于等于m且该因子在1-n之间就输出 复杂度:枚举因子:O(n^1/2*m) 输出答案 : 大概是O(m*?) 一个不知道的数字 #i ...