系列推薦文章:
OpenGL/OpenGL ES入門:圖形API以及專業名詞解析
OpenGL/OpenGL ES入門:渲染流程以及固定存儲着色器
OpenGL/OpenGL ES入門:圖像渲染實現以及渲染問題
OpenGL/OpenGL ES入門:基礎變換 - 初識向量/矩陣
OpenGL/OpenGL ES入門:紋理初探 - 經常使用API解析
OpenGL/OpenGL ES入門: 紋理應用 - 紋理座標及案例解析(金字塔)
OpenGL/OpenGL ES入門: 頂點着色器與片元着色器(OpenGL過渡OpenGL ES)
OpenGL/OpenGL ES入門: GLKit以及API簡介
OpenGL/OpenGL ES入門: GLKit使用以及案例
OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片
OpenGL/OpenGL ES入門:iOS紋理翻轉策略解析
OpenGL ES入門: 渲染金字塔 - 顏色、紋理、紋理與顏色混合填充以及GLKit實現git
關於圖層設置、上下文設置、清空緩衝區、設置renderBuffer、frameBuffer的代碼,與上一篇:OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片的代碼無異,這裏不過多描述,也會附demo一份,供你們參考。github
因爲要實現的是一個金字塔,並且是可以旋轉的,因此咱們新增了投影矩陣和模型矩陣數組
attribute vec4 position;
attribute vec4 positionColor;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
varying lowp vec4 varyColor;
void main()
{
varyColor = positionColor;
vec4 vPos;
vPos = projectionMatrix * modelViewMatrix * position;
gl_Position = vPos;
}
複製代碼
varying lowp vec4 varyColor;
void main()
{
gl_FragColor = varyColor;
}
複製代碼
設置屏幕(清屏顏色、清除屏幕、視口大小),讀取着色器程序,加載shader、連接以及使用program這些步驟的代碼以前你們都接觸過,這裏再也不展現給你們,由於和上一篇:OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片中的代碼也是一摸同樣的,具體參考demo,下面介紹一下不一樣的。緩存
先看下面這個俯視圖的金字塔,共有5個頂點bash
由6個三角形構成,找出對應三角形的三個頂點,而後放進索引數組裏ide
// 頂點數組 前3頂點值(x,y,z),後3位顏色值(RGB)
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, //左上0
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, //右上1
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, //右下2
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, //左下3
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, //頂點4
};
// 索引數組
GLuint indices[] =
{
0, 1, 2,
0, 2, 3,
0, 4, 1,
1, 4, 2,
2, 4, 3,
3, 4, 0,
};
複製代碼
// 判斷頂點緩存區是否爲空,若是爲空則申請一個緩存區標識符
if (self.myVertices == 0) {
glGenBuffers(1, &_myVertices);
}
//9.-----處理頂點數據-------
//(1).將_myVertices綁定到GL_ARRAY_BUFFER標識符上
glBindBuffer(GL_ARRAY_BUFFER, _myVertices);
//(2).把頂點數據從CPU內存複製到GPU上
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
//(3).將頂點數據經過myPrograme中的傳遞到頂點着色程序的position
//1.glGetAttribLocation,用來獲取vertex attribute的入口的.
//2.告訴OpenGL ES,經過glEnableVertexAttribArray,
//3.最後數據是經過glVertexAttribPointer傳遞過去的。
//注意:第二參數字符串必須和shaderv.vsh中的輸入變量:position保持一致
GLuint position = glGetAttribLocation(self.myProgram, "position");
//(4).打開position
glEnableVertexAttribArray(position);
//(5).設置讀取方式
//參數1:index,頂點數據的索引
//參數2:size,每一個頂點屬性的組件數量,1,2,3,或者4.默認初始值是4.
//參數3:type,數據中的每一個組件的類型,經常使用的有GL_FLOAT,GL_BYTE,GL_SHORT。默認初始值爲GL_FLOAT
//參數4:normalized,固定點數據值是否應該歸一化,或者直接轉換爲固定值。(GL_FALSE)
//參數5:stride,連續頂點屬性之間的偏移量,默認爲0;
//參數6:指定一個指針,指向數組中的第一個頂點屬性的第一個組件。默認爲0
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 8, NULL);
//10.--------處理頂點顏色值-------
//(1).glGetAttribLocation,用來獲取vertex attribute的入口的.
//注意:第二參數字符串必須和shaderv.glsl中的輸入變量:positionColor保持一致
GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
//(2).打開positionColor
glEnableVertexAttribArray(positionColor);
glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 8, (float *)NULL + 3);
複製代碼
//11.找到myProgram中的projectionMatrix、modelViewMatrix 2個矩陣的地址。若是找到則返回地址,不然返回-1,表示沒有找到2個對象。
GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectMatrix");
GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix");
//12.建立4 * 4投影矩陣
KSMatrix4 _projectMat;
//(1)獲取單元矩陣
ksMatrixLoadIdentity(&_projectMat);
//(2)計算縱橫比例
float aspect = self.frame.size.width / self.frame.size.height;
//(3)獲取透視矩陣
/*
參數1:矩陣
參數2:視角,度數爲單位
參數3:縱橫比
參數4:近平面距離
參數5:遠平面距離
*/
ksPerspective(&_projectMat, 35, aspect, 5, 20);
//(4)將投影矩陣傳遞到頂點着色器
/*
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
參數列表:
location:指要更改的uniform變量的位置
count:更改矩陣的個數
transpose:是否要轉置矩陣,並將它做爲uniform變量的值。必須爲GL_FALSE
value:執行count個元素的指針,用來更新指定uniform變量
*/
glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat *)&_projectMat.m[0][0]);
//13.建立一個4 * 4 矩陣,模型視圖矩陣
KSMatrix4 _modelViewMat;
//(1)獲取單元矩陣
ksMatrixLoadIdentity(&_modelViewMat);
//(2)平移,z軸平移-10
ksTranslate(&_modelViewMat, 0, 0, -10);
//(3)建立一個4 * 4 矩陣,旋轉矩陣
KSMatrix4 _rotationMat;
//(4)初始化爲單元矩陣
ksMatrixLoadIdentity(&_rotationMat);
//(5)旋轉 分別繞X、Y、Z軸
ksRotate(&_rotationMat, _xDegree, 1, 0, 0);
ksRotate(&_rotationMat, _yDegree, 0, 1, 0);
ksRotate(&_rotationMat, _zDegree, 0, 0, 1);
//(6)把變換矩陣相乘.將_modelViewMatrix矩陣與_rotationMatrix矩陣相乘,結合到模型視圖
ksMatrixMultiply(&_modelViewMat, &_rotationMat, &_modelViewMat);
//(7)將模型視圖矩陣傳遞到頂點着色器
/*
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
參數列表:
location:指要更改的uniform變量的位置
count:更改矩陣的個數
transpose:是否要轉置矩陣,並將它做爲uniform變量的值。必須爲GL_FALSE
value:執行count個元素的指針,用來更新指定uniform變量
*/
glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat *)&_modelViewMat.m[0][0]);
複製代碼
//14.開啓剔除操做效果
glEnable(GL_CULL_FACE);
//15.使用索引繪圖
/*
void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices);
參數列表:
mode:要呈現的畫圖的模型
GL_POINTS
GL_LINES
GL_LINE_LOOP
GL_LINE_STRIP
GL_TRIANGLES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
count:繪圖個數
type:類型
GL_BYTE
GL_UNSIGNED_BYTE
GL_SHORT
GL_UNSIGNED_SHORT
GL_INT
GL_UNSIGNED_INT
indices:繪製索引數組
*/
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);
//16.從渲染緩衝區顯示到屏幕上
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
複製代碼
實現效果:post
紋理填充,顧名思義,就是使用圖片去填充,聯繫OpenGL/OpenGL ES入門: 使用OpenGL ES 渲染圖片中所說的圖片渲染,若是你們練習了,應該能夠本身寫的出來。下面給出關鍵代碼:ui
紋理座標的添加spa
// 頂點數組 前3頂點值(x,y,z),後3位顏色值(RGB) 後2位紋理座標
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, //左上0
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, //右上1
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, //右下2
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, //左下3
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, //頂點4
};
複製代碼
在繪製過程當中加載紋理,設置紋理採樣器 sampler2D,相信下面兩句代碼,你們並不陌生。3d
//加載紋理
[self setupTexture:@"test"];
//設置紋理採樣器 sampler2D
glUniform1f(glGetAttribLocation(self.myProgram, "colorMap"), 0);
複製代碼
同時須要修改片元着色器代碼
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main ()
{
gl_FragColor = texture2D(colorMap, varyTextCoord);
}
複製代碼
最終效果:
這裏主要是混合,紋理與顏色的混合,在OpenGL系列文章裏說過混合,有相關公式,主要代碼在片元着色器中實現,具體代碼以下:
precision highp float;
varying lowp vec4 varyColor;
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main ()
{
vec4 weakMask = texture2D(colorMap, varyTextCoord);
vec4 mask = varyColor;
float alpha = 0.3;
vec4 tempColor = mask * (1.0 - alpha) + weakMask * alpha;
gl_FragColor = tempColor;
}
複製代碼
最終效果:
//1.新建圖層
- (void)setupContext {
//1.新建OpenGL ES上下文
self.mContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
GLKView *view = (GLKView *)self.view;
view.context = self.mContext;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[EAGLContext setCurrentContext:self.mContext];
glEnable(GL_DEPTH_TEST);
}
複製代碼
//2.渲染圖形
- (void)render {
//1.頂點數據
// 頂點數組 前3頂點值(x,y,z),後3位顏色值(RGB) 後2位紋理座標
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, //左上0
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, //右上1
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, //右下2
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, //左下3
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, //頂點4
};
//2.繪圖索引
GLuint indices[] =
{
0, 1, 2,
0, 2, 3,
0, 4, 1,
1, 4, 2,
2, 4, 3,
3, 4, 0,
};
//頂點個數
self.count = sizeof(indices) /sizeof(GLuint);
//將頂點數組放入數組緩衝區中 GL_ARRAY_BUFFER
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW);
//將索引數組存儲到索引緩衝區 GL_ELEMENT_ARRAY_BUFFER
GLuint index;
glGenBuffers(1, &index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//使用頂點數據
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);
//使用顏色數據
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 3);
//使用紋理數據
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 6);
//獲取紋理路徑
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"timg" ofType:@"jpeg"];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@"1",GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
//着色器
self.mEffect = [[GLKBaseEffect alloc]init];
self.mEffect.texture2d0.enabled = GL_TRUE;
self.mEffect.texture2d0.name = textureInfo.name;
//投影視圖
CGSize size = self.view.bounds.size;
float aspect = fabs(size.width / size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 1000.f);
self.mEffect.transform.projectionMatrix = projectionMatrix;
//模型視圖
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -3.0f);
self.mEffect.transform.modelviewMatrix = modelViewMatrix;
//定時器
double seconds = 0.1;
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC, 0.0);
dispatch_source_set_event_handler(timer, ^{
self.XDegree += 0.1f * self.XB;
self.YDegree += 0.1f * self.YB;
self.ZDegree += 0.1f * self.ZB ;
});
dispatch_resume(timer);
}
複製代碼
- (void)update {
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -3.0f);
modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.XDegree);
modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, self.YDegree);
modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, self.ZDegree);
self.mEffect.transform.modelviewMatrix = modelViewMatrix;
}
複製代碼
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[self.mEffect prepareToDraw];
glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
}
複製代碼
最終實現效果:
該方法實現的代碼,後面整理好以後,也會上傳一份demo給你們參考。