美文网首页
OpenGL ES立方体贴图

OpenGL ES立方体贴图

作者: Maji1 | 来源:发表于2020-07-26 15:59 被阅读0次

我们先来看下效果图:

本案例使用了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即可对所有子视图进行统一变换。

相关文章

网友评论

      本文标题:OpenGL ES立方体贴图

      本文链接:https://www.haomeiwen.com/subject/dtwwlktx.html