美文网首页
OpenGL ES案例02 - 加载正方体

OpenGL ES案例02 - 加载正方体

作者: 卡布奇诺_95d2 | 来源:发表于2020-08-24 00:59 被阅读0次

    案例要求:使用GLKit 加载一个带纹理的正方体,并让该正方体有个旋转的效果。效果图如下:


    Aug-24-2020 00-18-18.gif

    要完成这个效果,主要思路如下:


    image.png
    代码的实现分为4个部分:
    • 准备工作
    • 设置顶点数据,顶点坐标/纹理坐标/法线坐标
    • GLKViewDelegate代理实现
    • 定时旋转

    准备工作

    这是使用GLKit绘制图形的基本步骤,这在前一个OpenGL ES案例01 - 加载纹理已经做过一次,此次复习并加深印象。

    1. 初始化上下文,并设置当前上下文
    EAGLContext* context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    [EAGLContext setCurrentContext:context];
    
    1. 创建GLKView,并设置代理。在前一个案例中直接将self.view的继承由UIView修改成GLKView。在这里换一种写法,创建一个GLKView,并将它以子视图的形式加到self.view中。
    self.glkView = [[GLKView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) context:context];
    self.glkView.backgroundColor = [UIColor blackColor];
    self.glkView.delegate = self;
    [self.view addSubview:self.glkView];
    
    1. 设置深度缓冲区格式,此处若不设置,将采用默认格式GLKViewDrawableDepthFormat24。
    self.glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    glDepthRangef(1, 0);
    
    1. 获取纹理地址
    NSString* path = [[NSBundle mainBundle] pathForResource:@"nn" ofType:@"jpg"];
    UIImage* image = [[UIImage alloc] initWithContentsOfFile:path];
    
    1. 设置纹理参数并加载纹理
    NSDictionary* options = @{GLKTextureLoaderOriginBottomLeft:@(YES)};
    GLKTextureInfo* textureInfo = [GLKTextureLoader textureWithCGImage:[image CGImage] options:options error:nil];
    
    1. 使用effect
    self.baseEffect = [[GLKBaseEffect alloc] init];
    self.baseEffect.texture2d0.enabled = YES;
    self.baseEffect.texture2d0.target = textureInfo.target;
    self.baseEffect.texture2d0.name = textureInfo.name;
    
    1. 开启光照效果,此处若不开启光照效果,会略显不真实
    self.baseEffect.light0.enabled = YES;
    
    1. 设置漫反射颜色,这主要是营造一种光照的效果
    self.baseEffect.light0.diffuseColor = GLKVector4Make(1, 1, 1, 1);
    
    1. 设置光源位置,可将光源放置任何想放置的位置
    self.baseEffect.light0.position = GLKVector4Make(-0.5, -0.5, 5, 1);
    

    至此,准备工作就完成了。

    设置顶点数据

    这部分的工作主要是设置顶点数据(顶点坐标/纹理坐标/法线坐标),并将这些数据从CPU拷贝至GPU。

    1. 设置顶点数据,在本案例中,定义了顶点数据的结构体,通过分别对结构体成员变量赋值的方法来完成每个顶点数据的赋值。
    typedef struct {
        GLKVector3 positionCoord;   //顶点坐标
        GLKVector2 textureCoord;    //纹理坐标
        GLKVector3 normal;          //法线
    } CCVertex;
    
    //初始化--这里数据的初始化方式是c语言中的结构体赋值
    (CCVertex){{-0.5, 0.5, 0.5}, {0, 1}, {0, 0, 1}};
    

    顶点数据设置不是本案例重点,详细代码可参见完整Demo。

    1. 开辟顶点缓冲区,将顶点数据从CPU拷贝至GPU
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(CCVertex)*kCoordCount, self.vertices, GL_STATIC_DRAW);
    
    1. 打开读取通道,指定要访问的属性,才能让顶点着色器访问到从CPU复制到GPU的数据
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL+offsetof(CCVertex, positionCoord));
        
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL+offsetof(CCVertex, textureCoord));
        
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(CCVertex), NULL+offsetof(CCVertex, normal));
    

    至此,完成了顶点数据的设置,并将顶点数据从CPU拷贝至GPU,指定顶点着色器要访问属性,这样顶点着色器就可以访问GPU中的相应数据了。

    实现GLKViewDelegate代理

    这个代理必须实现,否则无法完成绘制,代理方法的主要目的是绘制视图的内容,并根据定时器的旋转变换,重新渲染视图。

    1. 清空颜色/深度缓冲区
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    
    1. 由于在旋转过程加入光照效果,因此需要打开深度测试
    glEnable(GL_DEPTH_TEST);
    
    1. 准备绘制
    [self.baseEffect prepareToDraw];
    
    1. 开始绘制
    glDrawArrays(GL_TRIANGLES, 0, kCoordCount);
    

    启动定时旋转

    要实现效果图,需要启用一个定时器,当定时器被触发时,将整个模型视图矩阵沿某个方向旋转指定度数。

    1. 启动定时器
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    
    1. 指定旋转角度
    self.angle = (self.angle + 5) % 360;
    
    1. 修改模型视图矩阵,进行旋转操作
    self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(self.angle), 0.3, 1, 0.7);
    
    1. 提交重新渲染
    [self.glkView display];
    

    至此,按照思路完成了代码的编写,经过这次案例的实现,加深了使用GLKit加载纹理的步骤印象。
    完整Demo地址

    相关文章

      网友评论

          本文标题:OpenGL ES案例02 - 加载正方体

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