美文网首页OpenGL ES
第八节—GLKit立方体纹理

第八节—GLKit立方体纹理

作者: L_Ares | 来源:发表于2020-09-18 16:32 被阅读0次

本文为L_Ares个人写作,包括图片皆为个人亲自操作,如需转载请表明原文出处。

绘制个立方体,这里用结构体来存储顶点数据信息,这样其实更方便一些,尤其是打开顶点属性通道之后,设置顶点的读取方式的时候,明显逻辑上更容易接受。

结果图如下图1.1所示。

//
//  ViewController.m
//  02GLKit立体绘制
//
//  Created by EasonLi on 2020/9/17.
//  Copyright © 2020 EasonLi. All rights reserved.
//



#import "ViewController.h"
#import <GLKit/GLKit.h>



//这里不再用数组来存储顶点坐标和纹理坐标数据
//换成结构体来熟悉一下结构体存储顶点坐标和纹理坐标的话,应该如何设置
typedef struct
{
    GLKVector3 positionCoord;   //顶点坐标向量(x,y,z)
    GLKVector3 textureCoord;    //纹理坐标(str)
} JDVertex;



//立方体6个面,每个面都是一个矩形,每个矩形是2个三角形组成,每个三角形3个顶点,
//而且顶点数在本案例中不发生变化,直接给静态的变量存储一下顶点数
static NSInteger const nVertexCount = 36;



//另外,Controller不再继承GLKViewController,所以把代理写出来
@interface ViewController () <GLKViewDelegate>

//GLKView,绘制和呈现都要在这上面来完成
@property (nonatomic, strong) GLKView *nGlkView;

//GLBaseEffect,实现着色器功能
@property (nonatomic, strong) GLKBaseEffect *nBaseEffect;

//顶点缓存区标识符ID
@property (nonatomic, assign) GLuint nVertexBuffer;

//顶点坐标和纹理坐标的存储结构体
@property (nonatomic, assign) JDVertex *nVertexs;

//立方体每次旋转的角度
@property (nonatomic, assign) NSInteger nAngle;

//利用CoreAnimation中的CADisplayLink让旋转和帧刷新速率挂钩
@property (nonatomic, strong) CADisplayLink *nDisplayLink;

@end



@implementation ViewController



- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    [self showEffect];
    // Do any additional setup after loading the view.
}

#pragma mark - 呈现
- (void)showEffect
{
    
    [self setUpCofig];
    [self setUpTexture];
    [self setUpVertexData];
    [self setUpBufferAndAttr];
    [self setUpDisplayLink];
    
}



#pragma mark - 基本设置

- (void)setUpCofig
{
    
    //设置背景颜色,主要是看的清楚一点view在哪里,GLKView在哪里
    self.view.backgroundColor = [UIColor blueColor];
    
    //创建上下文对象
    EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    //设置当前Context
    [EAGLContext setCurrentContext:context];
    
    
    
    //创建GLKView
    //y往下移动一点,不然一会儿就把顶点坐标都整体下移一点,否则都顶到屏幕上边缘了
    CGRect glkViewRect = CGRectMake(56, 300, 300, 300);
    //创建一个GLKView,并且直接把上下文初始化进去
    self.nGlkView = [[GLKView alloc] initWithFrame:glkViewRect context:context];
    self.nGlkView.backgroundColor = [UIColor yellowColor];
    self.nGlkView.delegate = self;
    
    
    
    //设置深度缓存区大小
    self.nGlkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    //view添加GLKView对象
    [self.view addSubview:self.nGlkView];
    
}

#pragma mark - 设置纹理
- (void)setUpTexture
{
    //设置纹理图片路径
    NSString *imageFile = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"image1.jpg"];
    //获取Image
    UIImage *image = [UIImage imageWithContentsOfFile:imageFile];
    //设置图片翻转option,原因还是纹理的原点是左下角,但是view的原点是左上角
    NSDictionary *optionDic = @{GLKTextureLoaderOriginBottomLeft:@(YES)};
    //创建纹理信息
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:image.CGImage options:optionDic error:nil];
    
    
    
    //设置GLKBaseEffect
    self.nBaseEffect = [[GLKBaseEffect alloc] init];
    //就一张图,还是就用第一个纹理
    self.nBaseEffect.texture2d0.enabled = YES;
    self.nBaseEffect.texture2d0.name = textureInfo.name;
    //枚举值,指定不同类型的纹理的,从textureInfo里面获取就行了
    self.nBaseEffect.texture2d0.target = textureInfo.target;
     
}

#pragma mark - 顶点设置

- (void)setUpVertexData
{
    //在设置属性的时候也看到了,用的是结构体,而且是指针类型,这里是要利用malloc返回一个指向被分配的内存的指针
    //指向我们的顶点结构体首地址,开辟这个动态的内存空间,另外记得用完了要free()
    //就是开辟了一个JDVertex结构体类型大小*36个顶点大的空间,和数组一样的。实在不行的去看C语言基础。
    self.nVertexs = malloc(sizeof(JDVertex) * nVertexCount);
    
    //这里顶点顺序是有序的,毕竟这是立方体,有前后面
    //立方体前面顶点设置,结构体赋值,就写一次注释,下面都一样
    self.nVertexs[0] = (JDVertex){ {-0.5f,0.5f,0.5f} /*(x,y,z)*/, {0,1} /*(s,t)*/};
    self.nVertexs[1] = (JDVertex){ {-0.5f,-0.5f,0.5f} , {0,0} };
    self.nVertexs[2] = (JDVertex){ {0.5f,0.5f,0.5f}   , {1,1} };
    
    self.nVertexs[3] = (JDVertex){ {-0.5f,-0.5f,0.5f} , {0,0} };
    self.nVertexs[4] = (JDVertex){ {0.5f,0.5f,0.5f}   , {1,1} };
    self.nVertexs[5] = (JDVertex){ {0.5f,-0.5f,0.5f}  , {0,1} };
    
    // 上面
    self.nVertexs[6] = (JDVertex){{0.5, 0.5, 0.5},    {1, 1}};
    self.nVertexs[7] = (JDVertex){{-0.5, 0.5, 0.5},   {0, 1}};
    self.nVertexs[8] = (JDVertex){{0.5, 0.5, -0.5},   {1, 0}};
    self.nVertexs[9] = (JDVertex){{-0.5, 0.5, 0.5},   {0, 1}};
    self.nVertexs[10] = (JDVertex){{0.5, 0.5, -0.5},  {1, 0}};
    self.nVertexs[11] = (JDVertex){{-0.5, 0.5, -0.5}, {0, 0}};
    
    // 下面
    self.nVertexs[12] = (JDVertex){{0.5, -0.5, 0.5},    {1, 1}};
    self.nVertexs[13] = (JDVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.nVertexs[14] = (JDVertex){{0.5, -0.5, -0.5},   {1, 0}};
    self.nVertexs[15] = (JDVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.nVertexs[16] = (JDVertex){{0.5, -0.5, -0.5},   {1, 0}};
    self.nVertexs[17] = (JDVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    
    // 左面
    self.nVertexs[18] = (JDVertex){{-0.5, 0.5, 0.5},    {1, 1}};
    self.nVertexs[19] = (JDVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.nVertexs[20] = (JDVertex){{-0.5, 0.5, -0.5},   {1, 0}};
    self.nVertexs[21] = (JDVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.nVertexs[22] = (JDVertex){{-0.5, 0.5, -0.5},   {1, 0}};
    self.nVertexs[23] = (JDVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    
    // 右面
    self.nVertexs[24] = (JDVertex){{0.5, 0.5, 0.5},    {1, 1}};
    self.nVertexs[25] = (JDVertex){{0.5, -0.5, 0.5},   {0, 1}};
    self.nVertexs[26] = (JDVertex){{0.5, 0.5, -0.5},   {1, 0}};
    self.nVertexs[27] = (JDVertex){{0.5, -0.5, 0.5},   {0, 1}};
    self.nVertexs[28] = (JDVertex){{0.5, 0.5, -0.5},   {1, 0}};
    self.nVertexs[29] = (JDVertex){{0.5, -0.5, -0.5},  {0, 0}};
    
    // 后面
    self.nVertexs[30] = (JDVertex){{-0.5, 0.5, -0.5},   {0, 1}};
    self.nVertexs[31] = (JDVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    self.nVertexs[32] = (JDVertex){{0.5, 0.5, -0.5},    {1, 1}};
    self.nVertexs[33] = (JDVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    self.nVertexs[34] = (JDVertex){{0.5, 0.5, -0.5},    {1, 1}};
    self.nVertexs[35] = (JDVertex){{0.5, -0.5, -0.5},   {1, 0}};
    
}

#pragma mark - 设置缓存区和属性通道
- (void)setUpBufferAndAttr
{
    //开辟VBO(顶点缓存区)
    glGenBuffers(1, &_nVertexBuffer);
    //设置要绑定哪种缓存区
    glBindBuffer(GL_ARRAY_BUFFER, _nVertexBuffer);
    //定义变量存储要缓存的顶点数据的大小
    GLsizeiptr bufferSizeBytes = sizeof(JDVertex) * nVertexCount;
    //拷贝顶点数据进缓存区
    glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, self.nVertexs, GL_STATIC_DRAW);
    
    //打开顶点属性访问通道
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    //设置顶点坐标的读取方式
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(JDVertex), NULL + offsetof(JDVertex, positionCoord));
    
    //打开纹理属性访问通道
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(JDVertex), NULL + offsetof(JDVertex, textureCoord));
    
}

#pragma mark - 添加并配置CADisplayLink

- (void)setUpDisplayLink
{
    //先把角度初始化
    self.nAngle = 0;
    //初始化CADisplayLink对象,添加处理事件
    self.nDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(selectorUpdate)];
    //把CADisplayLink添加到主循环,这才能以刷新频率为单位,自动执行处理事件
    [self.nDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    
}

#pragma mark - DisplayLink的selector,更新绘制

- (void)selectorUpdate
{
    
    //一圈才360度,所以照着360转就行了
    self.nAngle = (self.nAngle + 5) % 360;
    //角度转成弧度
    float rad = GLKMathDegreesToRadians(self.nAngle);
    //设置发生旋转的模型视图矩阵
    self.nBaseEffect.transform.modelviewMatrix = GLKMatrix4MakeRotation(rad, 0.3, 1.f, 0.6);
    //重新绘制,就像OpenGL里面做完变化后要记得postredisplay啊
    [self.nGlkView display];
    
}

#pragma mark - GLKViewDelegate

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    //开启深度测试
    glEnable(GL_DEPTH_TEST);
    
    //清除缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //准备绘制
    [self.nBaseEffect prepareToDraw];
    
    //开始绘制,这里就先不考虑重复的顶点绘制问题了,后面再说。
    glDrawArrays(GL_TRIANGLES, 0, nVertexCount);
    
}

#pragma mark - Dealloc
//代码中不止是用了OC的类,也使用了C语言对象,OC可以ARC自己搞定释放问题,C在这里不行
//所以要在程序结束后自己释放C的对象
- (void)dealloc {
    
    //先声明要释放的全都是C的。OC的不要管。
    //上下文要释放
    //结构体。存储顶点数据的结构体要释放
    //缓存区要释放
    //CADisplayLink要失效
    
    if ([EAGLContext currentContext] == self.nGlkView.context) {
        [EAGLContext setCurrentContext:nil];
    }
    
    if (_nVertexs) {
        free(_nVertexs);
        _nVertexs = nil;
    }
    
    if (_nVertexBuffer) {
        glDeleteBuffers(1, &_nVertexBuffer);
        _nVertexBuffer = 0;
    }
    
    [self.nDisplayLink invalidate];
    
}


@end

图1.1:

1.1.png

相关文章

网友评论

    本文标题:第八节—GLKit立方体纹理

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