做了一个关于立体图形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源码