原文参考地址: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. 开发WP版本的大菠萝英雄榜

    前言 想当年Team有无数人在玩大菠萝,我被忽悠进来做肉盾,选了蛮子,从1.0开始,经历了103.105.108.2.0.2.1.这个游戏对我最大的帮助是学习了不同的技术,比如XAML.比如xcode ...

  2. 曼慧尼特u检验(两个样本数据间有无差异)

    曼-惠特尼U检验(Mann-Whitney检验) How the Mann-Whitney test works Mann-Whitney检验又叫做秩和检验,是比较没有配对的两个独立样本的非参数检验. ...

  3. HttpWebRequest提交(Post)数据

    protected void Page_Load(object sender, EventArgs e) { string sql = "select top 1 * from [user] ...

  4. 关于QString中的arg()函数使用方法

    例:正确做法:ui->label->setText(QString("Processingfile%1").arg(index));错误做法: ui->label ...

  5. 从库查看状态的时候显示“ Last_Error”

    mysql> show slave status\G;*************************** 1. row ***************************         ...

  6. 【转】css布局居中和CSS内容居中区别和对应DIV CSS代码

    原文地址:http://www.divcss5.com/jiqiao/j771.shtml css布局居中和CSS内容居中区别和对应DIV CSS代码教程与图文代码案例篇 对于新手来说DIV CSS布 ...

  7. nginx正向代理,反向代理,透明代理(总结)

    1正向代理 正向代理,也就是传说中的代理,他的工作原理就像一个跳板, 简单的说, 我是一个用户,我访问不了某网站,但是我能访问一个代理服务器 这个代理服务器呢,他能访问那个我不能访问的网站 于是我先连 ...

  8. Struts2+Spring+Mybatis+Junit 测试

    Struts2+Spring+Mybatis+Junit 测试 博客分类: HtmlUnit Junit Spring 测试 Mybatis  package com.action.kioskmoni ...

  9. [转]git在eclipse中的配置

    一_安装EGIT插件 http://download.eclipse.org/egit/updates/ 或者使用Eclipse Marketplace,搜索EGit 二_使用EGIT前的配置 配置个 ...

  10. js-FCC算法-Symmetric Difference

    创建一个函数,接受两个或多个数组,返回所给数组的 对等差分(symmetric difference) (△ or ⊕)数组. 给出两个集合 (如集合 A = {1, 2, 3} 和集合 B = {2 ...