立體圖形3D動畫和繪製

做了一個關於立體圖形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源碼



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章