美文网首页
绘制一个金字塔并贴上纹理

绘制一个金字塔并贴上纹理

作者: E术家 | 来源:发表于2020-08-05 16:15 被阅读0次

效果图

shader文件的变化

attribute vec4 position;
attribute vec4 positionColor;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

varying lowp vec4 varyColor;

attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main(){
    varyColor = positionColor;
    varyTextCoord = textCoordinate;
    
    vec4 vPos;
    
    vPos = projectionMatrix * modelViewMatrix * position;
    
    gl_Position = vPos;
}
precision highp float;

varying lowp vec4 varyColor;

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main (){
//    gl_FragColor = varyColor;
    gl_FragColor = texture2D(colorMap, varyTextCoord);
}

核心绘制代码

- (void)renderLayer {
    //设置清屏颜色
    glClearColor(1, 1, 1, 1.0);
    //清除屏幕
    glClear(GL_COLOR_BUFFER_BIT);
    
    //设置视口大小
    CGFloat scale = [[UIScreen mainScreen] scale];
    glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale);
    
    //读取顶点着色程序、片元着色程序
    NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"shaderv.glsl" ofType:nil];
    NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shaderf.glsl" ofType:nil];
    
    //判断self.myProgram是否存在,存在则清空其文件
    if (self.myPrograme) {
        glDeleteProgram(self.myPrograme);
        self.myPrograme = 0;
    }
    
    //加载shader
    self.myPrograme = [self loaderShaders:vertFile withFrag:fragFile];
    
    //Program链接
    glLinkProgram(self.myPrograme);
    
    //获取链接的状态
    GLint linkStatus;
    glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkStatus);
    if (linkStatus == GL_FALSE) {
        //link 失败信息
        GLchar message[512]; //先暂定512 可以更多,也可以更少
        glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
        NSString *messageString = [NSString stringWithUTF8String:message];
        NSLog(@"Programe Link Error: %@",messageString);
        return;
    }
    
    NSLog(@"Program Link Success!");
    
    //使用Program
    glUseProgram(self.myPrograme);
    
    [self setData];
}

//准备顶点数据/纹理坐标
- (void)setData {
    //创建顶点数组 & 索引数组
    //(1)顶点数组 前3顶点值(x,y,z),后3位颜色值(RGB) 默认透明度1 最后2位是纹理坐标
    GLfloat attrArr[] = {
        -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f,  1.0f,0.0f,   //左上0
        0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f,  1.0f,1.0f,   //右上1
        -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f,  0.0f,0.0f,   //左下2
        
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,  0.0f,1.0f,   //右下3
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,  0.5f,0.5f,   //顶点4
    };
    
    //(2).索引数组
    GLuint indices[] = {
        0, 3, 2,
        0, 1, 3,
        0, 2, 4,
        0, 4, 1,
        2, 3, 4,
        1, 4, 3,
    };
    
    if (self.myVertices == 0) {
        glGenBuffers(1, &_myVertices);
    }
    
    //将attrBuffer绑定到GL_ARRAY_BUFFER标识符上
    glBindBuffer(GL_ARRAY_BUFFER, _myVertices);
    //把顶点数据从CPU内存复制到GPU上
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
    
    //打开通道
    
    //将顶点数据通过myPrograme中的传递到顶点着色程序的position
    //glGetAttribLocation,用来获取vertex attribute的入口的.
    //注意:第二参数字符串必须和shaderv.vsh中的输入变量:position保持一致
    GLuint position = glGetAttribLocation(self.myPrograme, "position");
    //告诉OpenGL ES,通过glEnableVertexAttribArray
    glEnableVertexAttribArray(position);
    //最后数据是通过glVertexAttribPointer传递过去的
    //参数1:index,顶点数据的索引
    //参数2:size,每个顶点属性的组件数量,1,2,3,或者4.默认初始值是4.
    //参数3:type,数据中的每个组件的类型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默认初始值为GL_FLOAT
    //参数4:normalized,固定点数据值是否应该归一化,或者直接转换为固定值。(GL_FALSE)
    //参数5:stride,连续顶点属性之间的偏移量,默认为0;
    //参数6:指定一个指针,指向数组中的第一个顶点属性的第一个组件。默认为0
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);
    
    //打开颜色通道
    GLuint positionColor = glGetAttribLocation(self.myPrograme, "positionColor");
    glEnableVertexAttribArray(positionColor);
    glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (float *)NULL + 3);
    
    //纹理
    GLuint textCoor = glGetAttribLocation(self.myPrograme, "textCoordinate");
    glEnableVertexAttribArray(textCoor);
    glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (float *)NULL + 6);
    
    
    //MVP
    GLuint projectionMatrixSlot = glGetUniformLocation(self.myPrograme, "projectionMatrix");
    GLuint modelViewMatrixSlot = glGetUniformLocation(self.myPrograme, "modelViewMatrix");
    
    float width = self.frame.size.width;
    float height = self.frame.size.height;
    
    //创建4 * 4投影矩阵
    KSMatrix4 _projectionMatrix;
    //(1)获取单元矩阵
    ksMatrixLoadIdentity(&_projectionMatrix);
    //(2)计算纵横比例 = 长/宽
    float aspect = width / height; //长宽比
    //(3)获取透视矩阵
    /*
     参数1:矩阵
     参数2:视角,度数为单位
     参数3:纵横比
     参数4:近平面距离
     参数5:远平面距离
     参考PPT
     */
    ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f); //透视变换,视角30°
    //(4)将投影矩阵传递到顶点着色器
    /*
     void glUniformMatrix4fv(GLint location,  GLsizei count,  GLboolean transpose,  const GLfloat *value);
     参数列表:
     location:指要更改的uniform变量的位置
     count:更改矩阵的个数
     transpose:是否要转置矩阵,并将它作为uniform变量的值。必须为GL_FALSE
     value:执行count个元素的指针,用来更新指定uniform变量
     */
    glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
    
    //创建一个4 * 4 矩阵,模型视图矩阵
    KSMatrix4 _modelViewMatrix;
    //(1)获取单元矩阵
    ksMatrixLoadIdentity(&_modelViewMatrix);
    //(2)平移,z轴平移-10
    ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0);
    //(3)创建一个4 * 4 矩阵,旋转矩阵
    KSMatrix4 _rotationMatrix;
    //(4)初始化为单元矩阵
    ksMatrixLoadIdentity(&_rotationMatrix);
    //(5)旋转
    ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0); //绕X轴
    ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0); //绕Y轴
    ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0); //绕Z轴
    //(6)把变换矩阵相乘.将_modelViewMatrix矩阵与_rotationMatrix矩阵相乘,结合到模型视图
    ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix);
    //(7)将模型视图矩阵传递到顶点着色器
    /*
     void glUniformMatrix4fv(GLint location,  GLsizei count,  GLboolean transpose,  const GLfloat *value);
     参数列表:
     location:指要更改的uniform变量的位置
     count:更改矩阵的个数
     transpose:是否要转置矩阵,并将它作为uniform变量的值。必须为GL_FALSE
     value:执行count个元素的指针,用来更新指定uniform变量
     */
    glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
    
    //正背面剔除
    glEnable(GL_CULL_FACE);
    
    //加载纹理
    [self setTexture:@"Snow.jpeg"];
    
    //设置纹理采样器 sampler2D
    glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
    
    //索引绘制
    /*
    void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices);
    参数列表:
    mode:要呈现的画图的模型
               GL_POINTS
               GL_LINES
               GL_LINE_LOOP
               GL_LINE_STRIP
               GL_TRIANGLES
               GL_TRIANGLE_STRIP
               GL_TRIANGLE_FAN
    count:绘图个数
    type:类型
            GL_BYTE
            GL_UNSIGNED_BYTE
            GL_SHORT
            GL_UNSIGNED_SHORT
            GL_INT
            GL_UNSIGNED_INT
    indices:绘制索引数组

    */
    glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);
    
    //从渲染缓存区显示到屏幕上
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
}

也可以使用GLKView来实现同样的效果

- (void)setupContext {
    //新建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);
}


-(void)render {
    //顶点数据
    //前3个元素,是顶点数据;中间3个元素,是顶点颜色值,最后2个是纹理坐标
    GLfloat attrArr[] = {
        -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f,  1.0f,0.0f,   //左上0
        0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f,  1.0f,1.0f,   //右上1
        -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f,  0.0f,0.0f,   //左下2
        
        0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,  0.0f,1.0f,   //右下3
        0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,  0.5f,0.5f,   //顶点4
    };
    
    //绘图索引
    GLuint indices[] = {
        0, 3, 2,
        0, 1, 3,
        0, 2, 4,
        0, 4, 1,
        2, 3, 4,
        1, 4, 3,
    };
    
    //顶点个数
    self.count = sizeof(indices) /sizeof(GLuint);

    //将顶点数组放入数组缓冲区中 GL_ARRAY_BUFFER
    GLuint buffer;
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW);
    
    //将索引数组存储到索引缓冲区 GL_ELEMENT_ARRAY_BUFFER
    GLuint index;
    glGenBuffers(1, &index);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
    //使用顶点数据
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);
    
    //使用颜色数据
    glEnableVertexAttribArray(GLKVertexAttribColor);
    glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 3);
    
    //使用纹理
    //载入图片
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"Snow.jpeg" ofType:nil];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    
    //纹理转换 GLKit
    NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft:@(YES)};
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:image.CGImage options:options error:nil];
    //打开通道
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 6);

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

    //投影视图
    CGSize size = self.view.bounds.size;
    float aspect = fabs(size.width / size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 100.0);
    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;
    
    
    //定时器
    double seconds = 0.1;
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC, 0.0);
    dispatch_source_set_event_handler(timer, ^{
       
        self.XDegree += 0.1f * self.XB;
        self.YDegree += 0.1f * self.YB;
        self.ZDegree += 0.1f * self.ZB ;
        
    });
    dispatch_resume(timer);

}

//场景数据变化
-(void)update {
    GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.5);
    
    modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.XDegree);
    modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, self.YDegree);
    modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, self.ZDegree);
    
    self.mEffect.transform.modelviewMatrix = modelViewMatrix;
    
}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    glClearColor(1, 1, 1, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    
    [self.mEffect prepareToDraw];
    glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
}

相关文章

  • 绘制一个金字塔并贴上纹理

    效果图 shader文件的变化 核心绘制代码 也可以使用GLKView来实现同样的效果

  • OpenGL ES案例- 实现颜色和纹理的混合

    这个案例是在上个案例的基础上,在金字塔上贴上纹理,并实现纹理和颜色的混合。最终效果: 一、使用GLSL实现 结合我...

  • 实现金字塔纹理

    在一个金字塔图形贴上纹理,示例程序代码如下: 运行效果如下:

  • 八、OpenGL - 纹理金字塔

    一 初始化数据 生成纹理对象 绑定纹理 读取纹理文件 设置纹理参数 载入纹理 创建金字塔并设置纹理顶点映射 二 渲...

  • OpenGL案例02

    绘制一个带纹理的金字塔模型,通过本案例来加深对纹理的理解,案例执行结果如下效果图: 搭建框架 SetupRC函数 ...

  • libGdx使用mesh画线

    使用mesh画线,并贴上纹理。画线类 控制顶点 效果:

  • OpenGL-ES 学习示例

    OpenGL-ES 学习示例 描述:1、GLKit 绘制图片和正方体2、GLSL 绘制金字塔、颜色纹理混合3、GL...

  • OpenGL ES 3.0纹理映射-绘制一张图片

    本篇博客了解一下2D纹理,并完成一个绘制显示一张图片的Renderer。 2D纹理 2D纹理是OpenGL ES中...

  • GLSL实现渲染立体图形

    通过GLSL实现一个自动旋转的金字塔,并对金字塔进行 颜色和纹理 的混合。效果如下: 整体流程与GLSL实现对Sh...

  • OpenGL纹理综合练习

    球体 金字塔 隧道 针对以上三种立体图形添加纹理后的效果图,其绘制流程均是一下流程: 主要针对纹理添加过程作出分析...

网友评论

      本文标题:绘制一个金字塔并贴上纹理

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