在上一篇咱們學習瞭如何搭建IOS下openGL的開發環境,接下來咱們來學習如何繪製一個多邊形。html
在2.0以前,es的渲染採用的是固定管線,何爲固定管線,就是一套固定的模板流程,局部座標變換 -> 世界座標變換 ->觀察座標變換->背面消除->光照->裁剪->投影->視口計算->光柵化,程序員只須要調用固定的api修改一些配置參數就能夠完成整個渲染流程了。而到了2.0,固定管線改爲了可編程管線,咱們對整個渲染流程能夠再編程,沒有固定的api給你調用,一切都依靠shader來完成。那麼什麼是shader呢:程序員
GLuint _renderBuffer; GLuint _frameBuffer; glGenRenderbuffers(1, &_renderBuffer); glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer); [_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable: (id<EAGLDrawable>)self.layer]; glGenFramebuffers(1, &_frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffer);
在設置緩存以前,最好先清理一次,避免重複設置編程
if (_frameBuffer) { glDeleteFramebuffers(1, &_frameBuffer); _frameBuffer = 0; } if (_renderBuffer) { glDeleteRenderbuffers(1, &_renderBuffer); _renderBuffer = 0; }
設置好緩存以後開始編譯着色器,基本上編譯着色器的步驟都是固定,圖像處理,濾鏡實現基本都是經過着色器來完成。如下是編譯着色器的代碼。api
GLuint _program; GLunit _positionSlot; _program = [MTShaderOperations compileShaders:@"Vertex" shaderFragment:@"Fragment"]; glUseProgram(_program); _positionSlot = glGetAttribLocation(_program, "Position");
glUseProgram(_program);數組
//綁定着色器中的參數緩存
_positionSlot = glGetAttribLocation(_program, "Position");學習
+ (GLuint)compileShaders:(NSString *)shaderVertex shaderFragment:(NSString *)shaderFragment { // 1 vertex和fragment兩個shader都要編譯 GLuint vertexShader = [MTShaderOperations compileShader:shaderVertex withType:GL_VERTEX_SHADER]; GLuint fragmentShader = [MTShaderOperations compileShader:shaderFragment withType:GL_FRAGMENT_SHADER]; // 2 鏈接vertex和fragment shader成一個完整的program GLuint _glProgram = glCreateProgram(); glAttachShader(_glProgram, vertexShader); glAttachShader(_glProgram, fragmentShader); // link program glLinkProgram(_glProgram); // 3 check link status GLint linkSuccess; glGetProgramiv(_glProgram, GL_LINK_STATUS, &linkSuccess); if (linkSuccess == GL_FALSE) { GLchar messages[256]; glGetProgramInfoLog(_glProgram, sizeof(messages), 0, &messages[0]); NSString *messageString = [NSString stringWithUTF8String:messages]; NSLog(@"%@", messageString); exit(1); } return _glProgram; }
+ (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType { // 1 查找shader文件 NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:@"glsl"]; NSError* error; NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error]; if (!shaderString) { NSLog(@"Error loading shader: %@", error.localizedDescription); exit(1); } // 2 建立一個表明shader的OpenGL對象, 指定vertex或fragment shader GLuint shaderHandle = glCreateShader(shaderType); // 3 獲取shader的source const char* shaderStringUTF8 = [shaderString UTF8String]; int shaderStringLength = (int)[shaderString length]; glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength); // 4 編譯shader glCompileShader(shaderHandle); // 5 查詢shader對象的信息 GLint compileSuccess; glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); if (compileSuccess == GL_FALSE) { GLchar messages[256]; glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); NSString *messageString = [NSString stringWithUTF8String:messages]; NSLog(@"%@", messageString); exit(1); } return shaderHandle; }
固然,要編譯着色器,首先咱們要寫好着色器代碼。繪製多邊形的着色器代碼十分簡單,若是有不懂得童鞋能夠參考OpenGL着色語言(GLSL―OpenGL Shading Language)ui
新建一個empty文件,而後將後綴改爲glsh就能夠開始寫着色器代碼了。spa
Vertex Shader代碼以下:3d
attribute vec4 Position; void main(void) { gl_Position = Position; }
Fragment Shader代碼以下
void main(void) { gl_FragColor = vec4(0,1,1, 1.0); }
編譯好着色器以後,咱們就能夠開始繪製圖形了,在這裏要注意的是在openGLES中只能畫三角形,全部的圖形都是由三角形組成的。
還有,在定義頂點時要注意openGL中的座標系不一樣於UIKit。
首先定義頂點數組
const GLfloat vertices[] = { -1, -1, 0, //左下 1, -1, 0, //右下 -1, 1, 0, //左上 1, 1, 0 }; //右上
繪製圖形
//傳入頂點參數
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(_positionSlot);
//繪製多邊形
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
在上面咱們畫出了多邊形,這個多邊形是頂點數組按照順序畫出全部的三角形,在很多狀況下,並不能符合咱們的要求。咱們能夠試着將上面最後一句改爲
glDrawArrays(GL_TRIANGLE_STRIP, 1, 4);
獲得的圖像以下
因爲openGL只能畫三角形,所以在頂點數組中,頂點按照怎樣的順序連接十分重要。所以在openGLES中提供了另外一個方法。
//定義索引數組
const GLubyte indices[] = { 0,1,2, 1,2,3 };
//根據索引數組的順序畫出多邊形
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_BYTE, indices);
這樣咱們就畫出了一個四邊形,其餘多邊形也是同樣的步驟。
下一篇章咱們會講如何傳入一個紋理,敬請期待。