首先是初始化openGL
設置layer
- (void)setupLayer
{
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
// CALayer 默認是透明的,必須將它設為不透明才能讓其可見
eaglLayer.opaque = YES;
// 設置描繪屬性,在這里設置不維持渲染內容以及顏色格式為 RGBA8
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
//設置放大倍數
[self setContentScaleFactor:[[UIScreen mainScreen] scale]];
}
設置上下文
- (void)setupContext{
// 指定 OpenGL 渲染 API 的版本,在這里我們使用 OpenGL ES 2.0
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// 設置為當前上下文
if (!_context || ![EAGLContext setCurrentContext:_context]) {
NSLog(@"Failed to initialize OpenGLES 2.0 context");
exit(1);
}
}
設置緩沖區
- (void)setupBuffer{
glDeleteFramebuffers(1, &_viewFramebuffer);
_viewRenderbuffer = 0;
glDeleteRenderbuffers(1, &_viewRenderbuffer);
_viewRenderbuffer = 0;
glGenFramebuffers(1, &_viewFramebuffer);
glGenRenderbuffers(1, &_viewRenderbuffer);
// 設置為當前 framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, _viewFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _viewRenderbuffer);
// 為 顏色緩沖區 分配存儲空間
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id<EAGLDrawable>)self.layer];
// 將 _colorRenderBuffer 裝配到 GL_COLOR_ATTACHMENT0 這個裝配點上
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _viewRenderbuffer);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
}
著色器配置文件:
#define VSH @"attribute vec4 Position;\
attribute vec4 SourceColor;\
varying vec4 DestinationColor;\
void main(void) {\
DestinationColor = SourceColor;\
gl_Position = Position;\
}"
#define FSH @"varying lowp vec4 DestinationColor;\
void main(void) {\
gl_FragColor = DestinationColor;\
}"
三角形和矩形的渲染
- (void)render {
glClearColor(0, 1.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
CGFloat scale = [[UIScreen mainScreen] scale]; //獲取視圖放大倍數,可以把scale設置為1試試
glViewport(0, 0, self.frame.size.width * scale, self.frame.size.height * scale); //設置視口大小
//加載shader
self.myProgram = [self loadShaders:VSH frag:FSH];
//鏈接
glLinkProgram(self.myProgram);
GLint linkSuccess;
glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) { //連接錯誤
GLchar messages[256];
glGetProgramInfoLog(self.myProgram, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"error:%@", messageString);
return ;
}else {
NSLog(@"link ok");
glUseProgram(self.myProgram); //成功便使用,避免由于未使用導致的的bug
}
GLuint position = glGetAttribLocation(self.myProgram, "Position");
GLuint textCoor = glGetAttribLocation(self.myProgram, "SourceColor");
const GLfloat Vertices[] = {
-0.5f,-0.5f,0,0,0,0,// 左下,黑色
0.5f,-0.5f,0,1,0,0, // 右下,紅色
0.5f,0.5f,0,0,1,0, // 右上,綠色
-0.5f,0.5f,0,0,0,1, // 左上,藍色
};
// 索引數組,指定好了繪制三角形的方式
// 與glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);一樣。
const GLubyte Indices[] = {
0,1,2, // 三角形0
0,2,3 // 三角形1
};
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
// 綁定vertexBuffer到GL_ARRAY_BUFFER目標
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
// 為VBO申請空間,初始化并傳遞數據
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
// 給_positionSlot傳遞vertices數據
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, NULL);
glEnableVertexAttribArray(position);
// 取出Colors數組中的每個坐標點的顏色值,賦給_colorSlot
glVertexAttribPointer(textCoor, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)NULL + 3);
glEnableVertexAttribArray(textCoor);
if (_drawType == 1) {
// Draw triangle
if (_isHollow) glDrawArrays(GL_LINE_LOOP, 0, 4); //GL_LINE_LOOP不帶填充
else glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, Indices);
}else{
glDrawArrays(_isHollow ? GL_LINE_LOOP : GL_TRIANGLES, 0, 3); //GL_LINE_LOOP不帶填充
}
[self.context presentRenderbuffer:GL_RENDERBUFFER];
}
至于圓形,因為要把圓切割成100份,和矩形有些不一樣
- (void)renderCircular {
glClearColor(0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
CGFloat scale = [[UIScreen mainScreen] scale]; //獲取視圖放大倍數,可以把scale設置為1試試
glViewport(0, 0, self.frame.size.width * scale, self.frame.size.height * scale); //設置視口大小
//加載shader
self.myProgram = [self loadShaders:VSH frag:FSH];
//鏈接
glLinkProgram(self.myProgram);
GLint linkSuccess;
glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) { //連接錯誤
GLchar messages[256];
glGetProgramInfoLog(self.myProgram, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"error:%@", messageString);
return ;
}else {
NSLog(@"link ok");
glUseProgram(self.myProgram); //成功便使用,避免由于未使用導致的的bug
}
GLuint position = glGetAttribLocation(self.myProgram, "Position");
GLuint textCoor = glGetAttribLocation(self.myProgram, "SourceColor");
GLint vertCount = 101; //分割份數
Vertex vertext[vertCount];
float delta = 2.0*M_PI/vertCount;
float a = 0.8; //水平方向的半徑
float b = a * self.frame.size.width / self.frame.size.height;
for (int i = 0; i < vertCount; i++) {
GLfloat x = a * cos(delta * i);
GLfloat y = b * sin(delta * i);
GLfloat z = 0.0;
vertext[i] = (Vertex){x, y, z, x, y, x+y};
printf("%f , %f\n", x, y);
}
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
// 綁定vertexBuffer到GL_ARRAY_BUFFER目標
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
// 為VBO申請空間,初始化并傳遞數據
glBufferData(GL_ARRAY_BUFFER, sizeof(vertext), vertext, GL_STATIC_DRAW);
// 給_positionSlot傳遞vertices數據
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, NULL);
glEnableVertexAttribArray(position);
// 取出Colors數組中的每個坐標點的顏色值,賦給_colorSlot
glVertexAttribPointer(textCoor, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)NULL + 3);
glEnableVertexAttribArray(textCoor);
glDrawArrays(_isHollow ? GL_LINE_LOOP : GL_TRIANGLE_FAN, 0, vertCount);//GL_LINE_LOOP 不帶填充
[self.context presentRenderbuffer:GL_RENDERBUFFER];
}
效果圖:
1782258-b1baee1ba0a400e7.png
WechatIMG18.png
1782258-068214f7c72b54c4.png
無填充:
A89F966D-3184-4BEE-AADA-145514F7D367.jpeg
60672747-676A-4282-AB91-0C6CE173B1C6.jpeg
7F588FAD-626C-41BC-940D-442F7B8BE291.jpeg