iOS开发-OpenGL ES入门教程4

作者: 落影loyinglin | 来源:发表于2016-04-06 10:05 被阅读6178次

    教程

    OpenGL ES入门教程1-Tutorial01-GLKit
    OpenGL ES入门教程2-Tutorial02-shader入门
    OpenGL ES入门教程3-Tutorial03-三维变换
    这次我们用GLKit,更简单的实现图形变换、纹理贴图、着色、深度测试(代码在这)。

    OpenGL ES系列教程在这里
    OpenGL ES系列教程的代码地址 - 你的star和fork是我的源动力,你的意见能让我走得更远。

    效果展示

    核心思路

    使用GLKit来进行图形变换、纹理贴图加载、深度测试,用GLKBaseEffect来管理纹理贴图和进行着色。

    具体细节

    1、顶点属性

    typedef NS_ENUM(GLint, GLKVertexAttrib)
    {
        GLKVertexAttribPosition,
        GLKVertexAttribNormal,
        GLKVertexAttribColor,
        GLKVertexAttribTexCoord0,
        GLKVertexAttribTexCoord1
    } NS_ENUM_AVAILABLE(10_8, 5_0);
    

    GLKEffects用到的顶点属性已经定义好,使用时直接用枚举量赋值。如下图,直接对顶点的位置、颜色、纹理坐标进行赋值。

        glEnableVertexAttribArray(GLKVertexAttribPosition);
        glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL);
        //顶点颜色
        glEnableVertexAttribArray(GLKVertexAttribColor);
        glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, 4 * 8, (GLfloat *)NULL + 3);
        
        glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
        glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 4 * 8, (GLfloat *)NULL + 6);
    

    2、纹理

    在自定义shader中使用纹理,需要用CoreGraphics把图像转换成bitmapdata,再申请纹理内存,把图像数据传进去,最后还要释放bitmapdata。
    在GLKit中,仅仅需要如下三行代码,就可以完成纹理的加载。

        //纹理
        NSString* filePath = [[NSBundle mainBundle] pathForResource:@"for_test" ofType:@"png"];
        NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:@(1), GLKTextureLoaderOriginBottomLeft, nil];
        GLKTextureInfo* textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
    

    GLKTextureLoaderOriginBottomLeft 参数是避免纹理上下颠倒,原因是纹理坐标系和世界坐标系的原点不同。

    最后创建着色器,启用纹理,把刚刚创建的textureInfo的name赋值给着色器。

        //着色器
        self.mEffect = [[GLKBaseEffect alloc] init];
        self.mEffect.texture2d0.enabled = GL_TRUE;
        self.mEffect.texture2d0.name = textureInfo.name;
    

    3、图形变换

    在OpenGL ES里面,图形变换的表现形式就是矩阵操作,GLKit也提供了很多矩阵操作函数。

        //初始的投影
        CGSize size = self.view.bounds.size;
        float aspect = fabs(size.width / size.height);
        GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 10.f);
        projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0f, 1.0f, 1.0f);
        self.mEffect.transform.projectionMatrix = projectionMatrix;
        
        GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);
        self.mEffect.transform.modelviewMatrix = modelViewMatrix;
        
    

    GLKMatrix4MakePerspective是透视投影变换
    GLKMatrix4Translate是平移变换

    /**
     *  场景数据变化
     */
    - (void)update {
        GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);
        
        modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.mDegreeX);
        modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, self.mDegreeY);
        modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, self.mDegreeZ);
        
        self.mEffect.transform.modelviewMatrix = modelViewMatrix;
    }
    

    在场景变换函数里面,GLKMatrix4RotateY是绕Y轴旋转,其他的分分别是绕X、Z轴旋转。

    4、深度测试

    在前面的教程介绍过,开启深度测试需要分配深度测试的缓冲区,并挂载到相应的帧缓冲区。
    在GLKit代码中,深度测试的开启十分简单。
    在新建上下文时调用glEnable(GL_DEPTH_TEST);开启深度测试。

        //新建OpenGL ES 上下文
        self.mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        
        GLKView* view = (GLKView *)self.view;
        view.context = self.mContext;
        view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
        view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
        
        [EAGLContext setCurrentContext:self.mContext];
        glEnable(GL_DEPTH_TEST);
        
    

    在渲染场景时,glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear参数加入GL_DEPTH_BUFFER_BIT即可。

    /**
     *  渲染场景代码
     */
    - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
        glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        
        [self.mEffect prepareToDraw];
        glDrawElements(GL_TRIANGLES, self.mCount, GL_UNSIGNED_INT, 0);
    }
    

    总结

    OpenGL ES的入门已经差不多,后面还有很多很多知识,需要时再学习即可。
    总结这几篇教程花了一个星期左右。
    学习过程中有几部分最难受:

    • 第一部分是OpenGL ES的顶点属性、纹理贴图,对顶点到图形的过程不理解,对OpenGL ES的数据缓存机制不了解,无知容易使人知难而退
    • 第二部分是shader和glsl,glsl无法调试、编译信息不会查看、语法不懂等等,一个1.0 + 1都会报错,自己却莫名其妙,只能通过二分注释代码来定位问题,特别让人泄气;
    • 第三部分是OpenGL ES的三维图形变换和光照等,这部分更多的是数学知识和物理知识,代码一般都很简单;这部分比前面的都难,但是因为知道哪里缺失,虽然不懂,但是不慌,只是有点难受。

    最后的感想,计算机图形学和线性代数毕竟是基础,自己多花点时间学习,培养为核心竞争力非常不错。

    相关文章

      网友评论

      • aKerdi:大哥好,小弟不解,,
        为什么color 的stride 是4 * 8 ?
        最后为了能启动,同时能看懂,再追加了一个Buffer 给color。
        aKerdi:@kevinlishuai 理解了,谢谢大哥,嘿嘿
        kevinlishuai:sizeof(GLfloat) 等于 4
      • littleDad:老哥 ,update 回调的时机是什么 哦
        littleDad:@Little_Dad 懂了 懂了。 这周末把老哥的都撸一遍
        littleDad:GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);这里的修改x和y的偏移量,怎么不起效果,仍是居中呢?
      • Alienchang:你好GLKMatrix4MakePerspective 的近平面和远平面是怎么计算的呢
      • hhjdk:modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, self.mDegreeY);
        我发现在调用点击Y,方法的时候这里self.mDegreeY是一直在增加的,这里不是旋转吗,怎么这个值是一直在增加的,这是什么情况,求指教,谢谢
        hhjdk:我的意思是这里的值不应该是在一个范围的轮回吗
      • 三分慢先森:进行深度测试的作用是什么呢?
      • 3276bfb3f3b1:博主,能加你QQ吗?刚接触OpenGLES,矩阵,顶点,着色器.vsh文件,都搞懵了
      • brother_jia:贴纹理怎么一面只贴一张图
        3276bfb3f3b1:用Xcode自定义shader没有提示吗?是不是新建EmptyFile然后改后缀名?
        落影loyinglin:@brother_jia 什么意思?
      • brother_jia:您好,博客非常好,请问 updata这个方法是怎么调用的
        落影loyinglin:@brother_jia 这个是glkit的回调
      • 7a9468fd08eb:请教一个问题,

        GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 10.f);
        projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0f, 1.0f, 1.0f);
        self.mEffect.transform.projectionMatrix = projectionMatrix;

        GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);

        GLKMatrix4MakePerspective 中的near和far这里为何设置成 0.1和10.f,以及modelview的tz为何又设置成了 -2.f 这两者之间有何联系吗?
        Even3Yu:@落影loyinglin modelview的tz为何又设置成了 -2.f
        落影loyinglin:@CP0000 有联系。一个是调整摄像机位置。一个是移动物体。

      本文标题:iOS开发-OpenGL ES入门教程4

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