OpenGL ES _ 入門_01
OpenGL ES _ 入門_02
OpenGL ES _ 入門_03
OpenGL ES _ 入門_04
OpenGL ES _ 入門_05
OpenGL ES _ 入門練習(xí)_01
OpenGL ES _ 入門練習(xí)_02
OpenGL ES _ 入門練習(xí)_03
OpenGL ES _ 入門練習(xí)_04
OpenGL ES _ 入門練習(xí)_05
OpenGL ES _ 入門練習(xí)_06
OpenGL ES _ 著色器 _ 介紹
OpenGL ES _ 著色器 _ 程序
OpenGL ES _ 著色器 _ 語法
OpenGL ES_著色器_紋理圖像
OpenGL ES_著色器_預(yù)處理
OpenGL ES_著色器_頂點著色器詳解
OpenGL ES_著色器_片斷著色器詳解
OpenGL ES_著色器_實戰(zhàn)01
OpenGL ES_著色器_實戰(zhàn)02
OpenGL ES_著色器_實戰(zhàn)03
本節(jié)學(xué)習(xí)目標
- 創(chuàng)建一個完整的OpenGL ES 工程代碼
- 繪制三角形
提醒:代碼你可能看不懂,因為你沒學(xué)過這個東西增显,看完這個只要你知道是什么東西就行了,后續(xù)內(nèi)容馬上跟進!
第一步.創(chuàng)建一個工程
第二步:刪除掉ViewController.h和ViewController.m文件
第三步:創(chuàng)建繼承自GLKViewController 的控制器對象时鸵,我起了一個名字叫OSViewController
第四步.在OSViewController.h文件中引用框架#import <GLKit/GLKit.h>
第五步,將創(chuàng)建的控制器和storyborad的視圖進行綁定
完成以上幾步:我們的配置算是完成了!
第六步,創(chuàng)建一個EAGContext 對象软能,用來跟蹤OpenGL 的狀態(tài)和管理數(shù)據(jù)和命令
// MARK: - 創(chuàng)建一個EAGContext
-(void)createEagContext{
self.eagcontext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.eagcontext];
}
第七步.配置GLKView(剛才創(chuàng)建的控制器的view的類型就是GLKView類型)
// MARK: - 配置GLKView
-(void)configure{
GLKView *view = (GLKView*)self.view;
view.context = self.eagcontext;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
}
第八步.編寫頂點著色器程序(Shader.vsh)
attribute vec4 position; // 屬性,如果綁定了這個屬性举畸,
uniform vec4 color; // 需要從程序中傳入的值查排,一會我們會不斷改變這個值
varying lowp vec4 colorVarying; // 這個值需要和片段著色器的聲明相同
void main()
{
gl_Position = position; // 設(shè)置頂點位置
colorVarying = color; // 設(shè)置頂點顏色
}
第九步.編寫片段著色器程序(Shader.fsh)
和上面的創(chuàng)建類似,文件名字后綴不一樣
varying lowp vec4 colorVarying;
void main()
{
gl_FragColor = colorVarying; // 設(shè)置片段著色器中的顏色
}
第十步. 分別編譯兩個頂點著色器程序和片斷著色器源代碼抄沮。
// 1.創(chuàng)建標示
GLuint vertShader, fragShader;
// 2.獲取文件路徑
NSString *vertShaderPathname, *fragShaderPathname;
vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
// 3.編譯
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
NSLog(@"編譯失敗 vertex shader");
return NO;
}
// 創(chuàng)建 編譯 片斷著色器
fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
NSLog(@"Failed to compile fragment shader");
return NO;
}
編譯代碼封裝了一下,具體代碼如下:
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
//1 獲取文件的內(nèi)容 并進行NSUTF8StringEncoding 編碼
const GLchar *source;
source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
if (!source) {
NSLog(@"Failed to load vertex shader");
return NO;
}
//2 根據(jù)類型創(chuàng)建著色器
*shader = glCreateShader(type);
//3. 獲取著色器的數(shù)據(jù)源
glShaderSource(*shader, 1, &source, NULL);
//4. 開始編譯
glCompileShader(*shader);
// 方便調(diào)試跋核,可以不用
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
NSLog(@"Shader compile log:\n%s", log);
free(log);
}
#endif
//5. 查看是否編譯成功
GLint status;
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return NO;
}
return YES;
}
經(jīng)過上面的代碼 岖瑰,我們就講兩個著色器程序編譯完成
第十一步.創(chuàng)建著一個空的色器程序,把剛才編譯好的兩個著色器目標代碼砂代,連接到這個空的程序中去
_program = glCreateProgram();
// 第九步 將頂點著色器加到程序中
glAttachShader(_program, vertShader);
// 將片斷著色器加到程序中
glAttachShader(_program, fragShader);
第十二步.將著色器程序的屬性綁定到OpenGL 中
// 綁定著色器的屬性
glBindAttribLocation(_program, 0, "position"); // 0代表枚舉位置
第十三步.開始正式鏈接著色器程序
if (![self linkProgram:_program]) {
NSLog(@"Failed to link program: %d", _program);
if (vertShader) {
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (_program) {
glDeleteProgram(_program);
_program = 0;
}
return NO;
}
下面是封裝的鏈接著色器程序
- (BOOL)linkProgram:(GLuint)prog
{
// 1鏈接程序
glLinkProgram(prog);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(@"Program link log:\n%s", log);
free(log);
}
#endif
// 2 檢查鏈接結(jié)果
GLint status;
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status == 0) {
return NO;
}
return YES;
}
第十四步.獲取著色器中輸入變量的索引值
_vertexcolor = glGetUniformLocation(_program, "color");
第十五步. 將頂點數(shù)據(jù)加載到GPU 中去
// 三角形頂點數(shù)據(jù)
static GLfloat vertex[6] = {
-1,-1,// 左下
-1,1, // 左上
1,1 // 右上
};
// 加載數(shù)據(jù)蹋订,具體的參數(shù)說明暫時不寫了,后面會專門講
-(void)loadVertex{
glGenBuffers(1, &_vertexBuffer); // 申請內(nèi)存標識
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);// 綁定
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);// 申請內(nèi)存空間
glEnableVertexAttribArray(GLKVertexAttribPosition);// 開啟頂點數(shù)據(jù)
// 設(shè)置指針
glVertexAttribPointer(GLKVertexAttribPosition,
2,
GL_FLOAT,
GL_FALSE,
8,
0);
}
第十六步. 繪制數(shù)據(jù)
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
static NSInteger count = 0;
// 清除顏色緩沖區(qū)
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
count ++;
if (count > 50 ) {
count = 0;
// 根據(jù)顏色索引值,設(shè)置顏色數(shù)據(jù)刻伊,就是剛才我們從著色器程序中獲取的顏色索引值
glUniform4f(_vertexcolor, arc4random_uniform(255)/225.0, arc4random_uniform(255)/225.0, arc4random_uniform(255)/225.0, 1);
}
// 使用著色器程序
glUseProgram(_program);
// 繪制
glDrawArrays(GL_TRIANGLES, 0, 3);
}
代碼有點多露戒,請按照步驟敲打一遍。
效果是不斷變化顏色的三角形
總結(jié)
OpenGL 是一個很深奧捶箱,又很神奇的東西!想學(xué)技術(shù)的加群:578734141