做了一個關於立體圖形3D動畫和繪製圖形的例子,效果如下:
這個是參照蘋果官方文檔和例子來寫的,其中茶壺是根據點、顏色渲染、網格結構和燈光效果來繪製出來的。
再說實現步驟前我們需要了解一下概念:
GLKView:作爲OpenGLES內容的呈現目標
GLKViewController: 內容呈現的控制和動畫,視圖管理和維護一個framebuffer,應用只需在framebuffer進行繪畫即可
GLKView 和GLKViewController類提供一個標準的OpenGLES視圖和相關聯的呈現循環
EAGLContext:實現和提供一個呈現環境
GLuint、GLfloat:其實就是typedef int和float的別名,當我們編寫代碼時不要被這些蘋果的別名給嚇到。
GLKTextureLoader:提供從iOS支持的各種圖像格式的源自動加載紋理圖像到OpenGLES 圖像環境的方式,並能夠進行適當的轉換,並支持同步和異步加載方式。
GLKMatrix4:一個unit共用體,是一個4*4的矩陣。
GLKBaseEffect:OpenGL ES 1.1規範中的關鍵的燈光和材料模式。
好了,還有其他的概念性的東西可以下方留言,我將進行回答,也可以自己谷歌。
1.將所需系統庫導入工程
2.創建一個GLKViewController類。
重寫一個繼承類,然後將view改爲GLKView。
@interface PDTeapotViewController : GLKViewController
{
EAGLContext *context; // 實現和提供一個呈現環境
GLuint mode;
// 茶壺
GLfloat rot;
// 正方體
GLfloat cubePos[3];
GLfloat cubeRot;
GLuint cubeTexture;
}
@property (nonatomic, strong) PDTeapotBaseEffect *innerCircle;
@property (nonatomic, strong) PDTeapotBaseEffect *outerCircle;
@property (nonatomic, strong) PDTeapotBaseEffect *teapot;
@property (nonatomic, strong) NSMutableArray *cubeEffectArr;
@property (nonatomic, strong) PDMusicCube *musicCube;
@end
並且分別在類中創建效果路徑、茶壺、正方體、和控制背景音樂。
- (void)viewDidLoad {
[super viewDidLoad];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// 創建環境失敗,或者將當前線程環境設置失敗
if (!context || ![EAGLContext setCurrentContext:context]) {
return;
}
GLKView *glView = (GLKView *)self.view;
glView.context = context;
glView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
mode = 1;
glEnable(GL_DEPTH_TEST);
// 創建效果路徑
self.innerCircle = [PDTeapotBaseEffect makeCircleWithNumOfSegments:circleSegments radius:pathCircleRadius];
self.outerCircle = [PDTeapotBaseEffect makeCircleWithNumOfSegments:circleSegments radius:pathOutCircleRadius];
// 創建茶壺
self.teapot = [PDTeapotBaseEffect makeTeapot];
// 創建正方體
self.cubeEffectArr = [PDTeapotBaseEffect makeCube];
[self setUpCubeEffect];
[self setUpMusicCube];
}
3.創建一個材料和效果類
#import "PDTeapotBaseEffect.h"
用來創建圖形
<span style="font-size:12px;">#define kTeapotScale 1.8
#define kCubeScale 0.12
#define kButtonScale 0.1
#define kButtonLeftSpace 1.1
#define DegreesToRadians(x) ((x) * M_PI / 180.0)
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
static const CGFloat pathCircleRadius = 1.0; // 運動路徑內環
static const CGFloat pathOutCircleRadius = 1.1; // 運動路徑外環
static const GLuint circleSegments = 36;
// 效果類
@interface PDTeapotBaseEffect : NSObject
@property (nonatomic, strong) GLKBaseEffect *effect; // 效果類,燈光和材料模式效果
@property (nonatomic, assign) GLuint vertexArray; // GLuint基礎類型
@property (nonatomic, assign) GLuint vertexBuffer;
@property (nonatomic, assign) GLuint normalBuffer;
/**
* 創建運動軌跡
*/
+ (instancetype)makeCircleWithNumOfSegments:(GLuint)segments radius:(GLfloat)radius;
/**
* 創建茶壺
*/
+ (instancetype)makeTeapot;
/**
* 創建正方體
*/
+ (NSMutableArray *)makeCube;
/**
* 背景音樂的播放
*/
+ (void)musicBack;</span>
例如創建一個茶壺代碼:
PDTeapotBaseEffect *teapot = [[PDTeapotBaseEffect alloc] init];
GLKBaseEffect *effect = [[GLKBaseEffect alloc] init];
// 材料
effect.material.ambientColor = GLKVector4Make(0.4, 0.8, 0.4, 1.0);
effect.material.diffuseColor = GLKVector4Make(1.0, 1.0, 1.0, 1.0);
effect.material.specularColor = GLKVector4Make(1.0, 1.0, 1.0, 1.0);
effect.material.shininess = 100.0;
// 光
effect.light0.enabled = GL_TRUE;
effect.light0.ambientColor = GLKVector4Make(0.2, 0.2, 0.2, 1.0);
effect.light0.diffuseColor = GLKVector4Make(0.2, 0.7, 0.2, 1.0);
effect.light0.position = GLKVector4Make(0.0, 0.0, 1.0, 0.0);
GLuint vertexArray, vertexBuffer, normalBuffer;
glGenVertexArraysOES(1, &vertexArray);
glBindVertexArrayOES(vertexArray);
// 位置
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(teapot_vertices), teapot_vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(teapot_normals), teapot_normals, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glBindVertexArrayOES(0);
teapot.effect = effect;
teapot.vertexArray = vertexArray;
teapot.vertexBuffer = vertexBuffer;
teapot.normalBuffer = normalBuffer;
return teapot;
4.利用glkView:drawInRect:函數做繪製和重繪
關於glkView:drawInRect:我要解釋一下:
使用GLKit視圖繪製OpenGL內容需要三個子步驟:準備OpenGLES基礎;發佈繪製命令;呈現顯示內容到Core Animation。 GLKit類本身已經實現了第一個和第三個步驟,用戶只需實現第二個步驟,在視圖的方法drawRect或視圖的代理對象的glkView:drawInRect:中調用適當的OpenGLES繪製命令進行內容繪製。
代碼如下(由於代碼比較多,我將部分粘貼,其餘部分參照我的github例子 ps:下載時給顆星最好了。。。。):
<span style="font-size:12px;">#pragma mark - 重繪
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.0, 0, 0, 1.0);
glClearDepthf(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLfloat aspectRatio = (GLfloat)(view.drawableWidth) / (GLfloat)(view.drawableHeight);
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(-1.0f, 1.0f, -1.0f/aspectRatio, 1.0f/aspectRatio, -10.0f, 10.0f);
projectionMatrix = GLKMatrix4Rotate(projectionMatrix, DegreesToRadians(-30.0f), 0.0f, 1.0f, 0.0f);
// set the projection matrix
self.innerCircle.effect.transform.projectionMatrix = projectionMatrix;
self.outerCircle.effect.transform.projectionMatrix = projectionMatrix;
self.teapot.effect.transform.projectionMatrix = projectionMatrix;
for (int f=0; f<6; f++)
((PDTeapotBaseEffect *)self.cubeEffectArr[f]).effect.transform.projectionMatrix = projectionMatrix;
glBindVertexArrayOES(self.innerCircle.vertexArray);
[self.innerCircle.effect prepareToDraw];
glDrawArrays (GL_LINE_LOOP, 0, circleSegments);
glBindVertexArrayOES(self.outerCircle.vertexArray);
[self.outerCircle.effect prepareToDraw];
glDrawArrays (GL_LINE_LOOP, 0, circleSegments);
[self drawTeapotAndUpdatePlayback];
[self drawCube];
}</span>
好了,關於整個項目其他不動的地方可以參照,
圖像編程總結下面是大家最想要的 github源碼