我们先来看下效果图:

本案例使用了GLKit中的相关控件:GLKView、GLKViewController、GLKTextureInfo、GLKBaseEffect
1、先绘制一个面
1.1、初始化配置
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (!context) {
NSLog(@"EAGLContext Error");
}
[EAGLContext setCurrentContext:context];
GLKView *view = (GLKView *)self.view;
view.context = context;
//配置视图创建的渲染缓冲区
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
glClearColor(1.0f, 0.5f, 0.5f, 1.0f);
该段代码主要功能:1、设置上下文、2、配置GLKView
1.2、设置顶点数据
GLfloat vertexData[] = {
// 前面
-0.5, -0.5, 0.5f, 0.0f, 0.0f, //左下
0.5, -0.5, 0.5f, 1.0f, 0.0f, //右下
0.5, 0.5, 0.5f, 1.0f, 1.0f, //右上
-0.5, -0.5, 0.5f, 0.0f, 0.0f, //左下
0.5, 0.5, 0.5f, 1.0f, 1.0f, //右上
-0.5, 0.5, 0.5f, 0.0f, 1.0f, //左上
};
GLuint bufferID;
glGenBuffers(1, &bufferID);//生成缓冲区
glBindBuffer(GL_ARRAY_BUFFER, bufferID);//绑定缓冲区
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);//设置缓冲区数据
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 0);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 3);
1、glEnableVertexAttribArray()
:
在iOS中, 默认情况下,所有顶点着色器的属性(Attribute
)变量都是关闭的。意味着,顶点数据在着色器端(服务端)是不可用的。即使你已经使用glBufferData
方法,将顶点数据从内存拷贝到顶点缓存区中(GPU显存中)。
所以, 必须由 glEnableVertexAttribArray
方法打开通道。指定访问属性。才能让顶点着色器能够访问到从CPU复制到GPU的数据。
2、glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
:
上传顶点数据到显存的方法:
index
指定要修改的顶点属性的索引值,例如
size
每次读取数量。(如position是由3个(x,y,z)组成,而颜色是4个(r,g,b,a),纹理则是2个.)
type
指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT
,初始值为GL_FLOAT
。
normalized
指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE
)或者直接转换为固定点值(GL_FALSE
)
stride
指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0
ptr
指定一个指针,指向数组中第一个顶点属性的第一个组件。初始值为0
1.3、设置纹理数据
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"scence" ofType:@"png"];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *texInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
effect = [[GLKBaseEffect alloc] init];
effect.texture2d0.enabled = GL_TRUE;
effect.texture2d0.name = texInfo.name;
1.4、绘制
实现GLKViewDelegate
方法:
#pragma mark - glkView:drawInRect:
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClear(GL_COLOR_BUFFER_BIT);
[effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 6);
}
看下效果:

这样一张图片就绘制好了。但是由于视口(视图)宽高比的问题,该图是被拉伸的。
1.5、我们通过设置 透视投影矩阵 和 模型视图矩阵 来解决该问题:
loat fovyRadians = GLKMathDegreesToRadians(35.0f);
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(fovyRadians, aspect, 0.1f, 500.0f);
effect.transform.projectionMatrix = projectionMatrix;
GLKMatrix4 modelviewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -5.0f);
effect.transform.modelviewMatrix = modelviewMatrix;
这样看上去就正常了:

2、绘制立方体
面绘制好了,下面我们在绘制立方体就简单了。
2.1、修改顶点坐标
GLfloat vertexData[] = {
// 前面
-0.5, -0.5, 0.5f, 0.0f, 0.0f, //左下
0.5, -0.5, 0.5f, 1.0f, 0.0f, //右下
0.5, 0.5, 0.5f, 1.0f, 1.0f, //右上
-0.5, -0.5, 0.5f, 0.0f, 0.0f, //左下
0.5, 0.5, 0.5f, 1.0f, 1.0f, //右上
-0.5, 0.5, 0.5f, 0.0f, 1.0f, //左上
//后面
0.5, -0.5, -0.5f, 1.0f, 0.0f,
0.5, 0.5, -0.5f, 1.0f, 1.0f,
-0.5, 0.5, -0.5f, 0.0f, 1.0f,
0.5, -0.5, -0.5f, 1.0f, 0.0f,
-0.5, 0.5, -0.5f, 0.0f, 1.0f,
-0.5, -0.5, -0.5f, 0.0f, 0.0f,
//右面
0.5, -0.5, 0.5f, 0.0f, 0.0f,
0.5, -0.5, -0.5f, 0.0f, 1.0f,
0.5, 0.5, -0.5f, 1.0f, 1.0f,
0.5, -0.5, 0.5f, 0.0f, 0.0f,
0.5, 0.5, -0.5f, 1.0f, 1.0f,
0.5, 0.5, 0.5f, 1.0f, 0.0f,
//左面
-0.5, -0.5, 0.5f, 0.0f, 0.0f,
-0.5, -0.5, -0.5f, 0.0f, 1.0f,
-0.5, 0.5, -0.5f, 1.0f, 1.0f,
-0.5, -0.5, 0.5f, 0.0f, 0.0f,
-0.5, 0.5, -0.5f, 1.0f, 1.0f,
-0.5, 0.5, 0.5f, 1.0f, 0.0f,
//上面
-0.5, 0.5, 0.5f, 0.0f, 0.0f,
0.5, 0.5, 0.5f, 1.0f, 0.0f,
0.5, 0.5, -0.5f, 1.0f, 1.0f,
-0.5, 0.5, 0.5f, 0.0f, 0.0f,
0.5, 0.5, -0.5f, 1.0f, 1.0f,
-0.5, 0.5, -0.5f, 0.0f, 1.0f,
//下面
-0.5, -0.5, 0.5f, 0.0f, 0.0f,
0.5, -0.5, 0.5f, 1.0f, 0.0f,
0.5, -0.5, -0.5f, 1.0f, 1.0f,
-0.5, -0.5, 0.5f, 0.0f, 0.0f,
0.5, -0.5, -0.5f, 1.0f, 1.0f,
-0.5, -0.5, -0.5f, 0.0f, 1.0f,
};
之前是设置一个面的顶底坐标,现在我们需要设置六个面的顶点坐标。
2.2、修改模型视图矩阵
我们需要将模型视图矩阵写在代理方法中设置旋转角度,记得开启深度测试,清空深度缓冲区。
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
angle += 0.05;
// 设置模型视图矩阵
GLKMatrix4 modelviewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -5.0f);
modelviewMatrix = GLKMatrix4Rotate(modelviewMatrix, angle, 0.5, 0.5, 0.0);
effect.transform.modelviewMatrix = modelviewMatrix;
[effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 36);
}
最后完整效果就出来了,完美。
最后再贴出CoreAnimation
实现的方法
- (void)viewDidLoad {
self.contentView = [[UIView alloc] initWithFrame:CGRectMake(100.0, 200.0, 100.0, 100.0)];
self.contentView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.contentView];
//1.前面
CATransform3D transform = CATransform3DMakeTranslation(0.0f, 0.0f, 50.0f);
[self addCubeFace:transform];
//2.右面
transform = CATransform3DMakeTranslation(50.0f, 0.0f, 0.0f);
transform = CATransform3DRotate(transform, M_PI_2, 0.0f, 1.0f, 0.0f);
[self addCubeFace:transform];
//3.上面
transform = CATransform3DMakeTranslation(0.0f, -50.0f, 0.0f);
transform = CATransform3DRotate(transform, M_PI_2, 1.0f, 0.0f, 0.0f);
[self addCubeFace:transform];
//4.下面
transform = CATransform3DMakeTranslation(0.0f, 50.0f, 0.0f);
transform = CATransform3DRotate(transform, -M_PI_2, 1.0f, 0.0, 0.0f);
[self addCubeFace:transform];
//5.左面
transform = CATransform3DMakeTranslation(-50.0f, 0.0f, 0.0f);
transform = CATransform3DRotate(transform, -M_PI_2, 0.0f, 1.0f, 0.0f);
[self addCubeFace:transform];
//6.后面
transform = CATransform3DMakeTranslation(0.0f, 0.0f, -50.0f);
transform = CATransform3DRotate(transform, M_PI, 0.0f, 1.0f, 0.0f);
[self addCubeFace:transform];
__block float step = 0;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
step += 0.02f;
self.contentView.layer.sublayerTransform = CATransform3DMakeRotation(step, -0.5, -0.5, -0.5);
}];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)addCubeFace:(CATransform3D)transform {
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"scence" ofType:@"png"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];
imageView.image = [UIImage imageWithContentsOfFile:filePath];
[self.contentView addSubview:imageView];
imageView.layer.transform = transform;
}
Core Animation
利用layer.transform的数据结构CATransform3D
即可完成3D变换。
Core Animation
中我们不需要为每一个面都专门做变换。我们只需要将它们放在同一个父视图中,利用父视图的layer.sublayerTransform
即可对所有子视图进行统一变换。
网友评论