原文参考地址: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. web性能优化——简介

    简介 性能优化的第一准则:加缓存.几乎绝大部分优化都围绕这个来进行的.让用户最快的看到结果. 性能优化的第二准则:最小原则.绝不提供多余的信息.比如,静态资源(图片.css.js)压缩,图片的滚动加载 ...

  2. Bootstrap系列 -- 1. 如何使用Bootstrap

    一. Bootstrap 简介 Bootstrap 是一个前端框架,使用Bootstrap可以做出很多漂亮的页面,中文官网:http://www.bootcss.com/ 二. Bootstrap核心 ...

  3. 欧几里德与扩展欧几里德算法 Extended Euclidean algorithm

    欧几里德算法 欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数. 基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd( ...

  4. poj 1698 Alice‘s Chance

    poj 1698  Alice's Chance 题目地址: http://poj.org/problem?id=1698 题意: 演员Alice ,面对n场电影,每场电影拍摄持续w周,每周特定几天拍 ...

  5. python作为一种胶水和c/c++

    如果需要用 Python 调用 C/C++ 编写的第三方库,只需要一个脚本语言来粘合它们.这个时候,用 Python ctypes 可以很方便地实现调用. StackOverflow 上的 Calli ...

  6. -Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match.

    一, eclipse中使用maven插件的时候,运行run as maven build的时候报错 -Dmaven.multiModuleProjectDirectory system propery ...

  7. dig 常用的域名查询工具

    dig 命令是常用的域名查询工具,可以用来测试域名系统工作是否正常. 语法: dig (选项) (参数) 选项: @<服务器地址>: 指定进行域名解析的域名服务器: -b: 当主机具有多个 ...

  8. HTML5+AJAX原生分块上传文件的关键参数设置

    processData:false 这是jquery.ajax的一个参数.默认值为true,表示会将非字符串对象自动变成k1=v1&k2=v2的形式,例如一个数组参数{d:[1,2]},到服务 ...

  9. Hibernate注解映射联合主键的三种主要方式

    今天在做项目的时候,一个中间表没有主键,所有在创建实体的时候也未加组件,结果报以下错误: org.springframework.beans.factory.BeanCreationException ...

  10. confluence的安装、备份和恢复(wiki)

    还有一种比较不错的wiki工具MediaWiki 安装教程参考 http://pangge.blog.51cto.com/6013757/1560249 我是按照上面的教程搭建的 还有几篇不错的文章 ...