一、理解 頂點數據存儲在申請的緩衝區中,其由數據匯流排傳遞給著色器(如果是片元著色器,還須將頂點轉換成片元),再由著色器最終渲染到塗層上; 二、思路 1.設置塗層; 2.創建上下文; 3.清空緩存區; 4.創建渲染緩存區和幀緩存區; 5.開始繪製; 三、核心代碼 //最終渲染 四、效果 GitHub ...
一、理解
頂點數據存儲在申請的緩衝區中,其由數據匯流排傳遞給著色器(如果是片元著色器,還須將頂點轉換成片元),再由著色器最終渲染到塗層上;
二、思路
1.設置塗層;
2.創建上下文;
3.清空緩存區;
4.創建渲染緩存區和幀緩存區;
5.開始繪製;
三、核心代碼
//最終渲染
- (void)renderLayer { //設置視窗背景顏色 glClearColor(0.0, 0.0, 0.0, 1.0); //清空顏色緩存 glClear(GL_COLOR_BUFFER_BIT); //設置視口大小 CGFloat scale = [[UIScreen mainScreen] scale]; glViewport(self.frame.origin.x*scale, self.frame.origin.y*scale, self.frame.size.width*scale, self.frame.size.height*scale); //讀取頂點和片元著色器程式 NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"glsl"]; NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"glsl"]; NSLog(@"vertFile:%@", vertFile); NSLog(@"fragFile:%@", fragFile); //判斷myProgram是否存在,存在則清空 if (self.myProgram) { glDeleteProgram(self.myProgram); self.myProgram = 0; } //載入著色器到myProgram中 self.myProgram = [self loadShader:vertFile frag:fragFile]; //創建鏈接 glLinkProgram(self.myProgram); GLint linkSuccess; //獲取鏈接狀態 glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkSuccess); //判斷鏈接是否成功 if (linkSuccess == GL_FALSE) { //獲取失敗信息 GLchar message[256]; glGetProgramInfoLog(self.myProgram, sizeof(message), 0, &message[0]); //c字元串轉換成oc字元串 NSString *messageString = [NSString stringWithUTF8String:message]; NSLog(@"error:%@", messageString); return; } else { //使用myProgram glUseProgram(self.myProgram); } //創建繪製索引數組 GLuint indices[] = { 0, 3, 2, 0, 1, 3, 0, 2, 4, 0, 4, 1, 2, 3, 4, 1, 4, 3 }; //判斷頂點緩存區是否為空,為空則申請一個緩存區標誌符 if (self.myVertices == 0) { glGenBuffers(1, &_myVertices); } //----------處理頂點坐標--------- /*頂點數據 1.前3個坐標值(x、y、z),後3個顏色值(RGB); 2.有先後順序,否則繪製形狀完全不同 */ GLfloat attrArr[] = { -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上 -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //頂點 }; //將_myVertices綁定到GL_ARRAY_BUFFER標誌符上 glBindBuffer(GL_ARRAY_BUFFER, _myVertices); //把頂點坐標數據從CPU複製到GPU上 glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW); //將頂點坐標數據通過myProgram傳遞到頂點著色器程式的position //獲取頂點屬性入口 GLuint position = glGetAttribLocation(self.myProgram, "position"); /*傳遞數據 1.一行6個數據,前3個為坐標,後3個為顏色; 2.NULL開始位置:預設為0,指向數組首地址; */ glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, NULL); //設置合適的格式從緩存區中讀取數據 glEnableVertexAttribArray(position); //處理頂點顏色數據:傳遞到頂點著色器的positionColor GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor"); glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, (float *)NULL +3); glEnableVertexAttribArray(positionColor); //在myProgram中找到透視投影矩陣和模型視圖矩陣 GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectionMatrix"); GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix"); //創建透視投影矩陣並初始化 float width = self.frame.size.width; float height = self.frame.size.height; KSMatrix4 _projectionMatrix; ksMatrixLoadIdentity(&_projectionMatrix); float aspect = width/height; ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f); //設置glsl裡面的投影矩陣 glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat *)&_projectionMatrix.m[0][0]); //開啟剔除功能 glEnable(GL_CULL_FACE); //創建平移矩陣:Z軸平移-10 KSMatrix4 _modelViewMatrix; ksMatrixLoadIdentity(&_modelViewMatrix); ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0); //創建旋轉矩陣 KSMatrix4 _rotationMatrix; ksMatrixLoadIdentity(&_rotationMatrix); ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0); ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0); ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0); //將平移矩陣和旋轉矩陣相乘,結果放到模型視圖矩陣中 ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix); //設置glsl裡面的模型視圖矩陣 glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat *)&_modelViewMatrix.m[0][0]); //設置繪製參數:片元、個數、索引數組 glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_INT, indices); //由頂點著色器將緩存區中的數據渲染到顯示塗層上 [self.myContext presentRenderbuffer:GL_RENDERBUFFER]; }
四、效果
以上是採用GLSL自定義著色器繪製,下麵是採用GLKit框架並添加紋理來繪製
//核心代碼
- (void)renderLayer { //頂點數據:前3個坐標(x、y、z),中間三個顏色(RGB),最後2個坐標(紋理) GLfloat attrArr [] = { -0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 1.0, 0.5, 0.5, 0.0, 0.0, 0.5, 0.0, 1.0, 1.0, -0.5, -0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, -0.5, 0.0, 0.0, 0.0, 0.5, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5 }; //繪圖索引 GLuint indices[] = { 0, 3, 2, 0, 1, 3, 0, 2, 4, 0, 4, 1, 2, 3, 4, 1, 4, 3, }; //頂點個數 self.count = sizeof(indices)/sizeof(GLuint); //頂點數據存入緩存區:CPU->GPU GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW); //索引數據存入緩存區:CPU->GPU 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:@"cTest" ofType:@"jpg"]; 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.1, 10.0); //設置等比縮放 projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0, 1.0, 1.0); self.mEffect.transform.projectionMatrix = projectionMatrix; //設置平移:Z軸負方向平移2.0 GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0, 0.0, -2.0); 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); dispatch_source_set_event_handler(timer, ^{ self.xDegree += 0.1*self.XB; self.yDegree += 0.1*self.YB; self.zDegree += 0.1*self.ZB; }); dispatch_resume(timer); }
效果: