文档章节

Lesson5 Shader加载二维贴纸

gdxz110
 gdxz110
发布于 2016/10/29 13:15
字数 1949
阅读 24
收藏 0

//  HelloShader

//  Created by gdxz on 16/10/28.

 

#import "LearnView.h"

#import <OpenGLES/ES2/gl.h>

@interface LearnView()

@property (nonatomic, strong) EAGLContext *myContext;

@property (nonatomic, strong) CAEAGLLayer *myEagLayer;

@property (nonatomic, assign) GLuint       myProgram;

 

@property (nonatomic, assign) GLuint myColorRenderBuffer;

@property (nonatomic, assign) GLuint myColorFrameBuffer;

 

- (void)setupLayer;

 

@end

 

@implementation LearnView

 

+ (Class)layerClass {

    return [CAEAGLLayer class];

}

 

- (void)layoutSubviews {

    [self setupLayer];

    [self setupContext];

    [self destoryRenderAndFrameBuffer];

    [self setupRenderBuffer];

    [self setupFrameBuffer];

    [self render];

}

 

- (void)render {

    glClearColor(0, 1.0, 0, 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:@"shader_v" ofType:@"vsh"];

    NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shader_f" ofType:@"fsh"];

    

    //加载shader

    self.myProgram = [self loadShaders:vertFile frag:fragFile];

    

    //连接

    glLinkProgram(self.myProgram);

    GLint linkSuccess;

    glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkSuccess);

    if (linkSuccess == GL_FALSE) {

        GLchar messages[256];

        glGetProgramInfoLog(self.myProgram, sizeof(messages), 0, &messages[0]);

        NSString *messageString = [NSString stringWithUTF8String:messages];

        NSLog(@"error %@",messageString);

        return;

    } else {

        NSLog(@"link success");

        glUseProgram(self.myProgram);//成功便使用

    }

    

    //前三个是顶点坐标,后面两个是纹理坐标

    GLfloat attrArr[] = {

        0.5f, -0.5f, -1.0f,     1.0f, 0.0f,

        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,

        -0.5f, -0.5f, -1.0f,    0.0f, 0.0f,

        0.5f, 0.5f, -1.0f,      1.0f, 1.0f,

        -0.5f, 0.5f, -1.0f,     0.0f, 1.0f,

        0.5f, -0.5f, -1.0f,     1.0f, 0.0f

    };

    

    GLuint attrBuffer;

    glGenBuffers(1, &attrBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);

    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);

    

    GLuint position = glGetAttribLocation(self.myProgram, "position");

    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, NULL);

    glEnableVertexAttribArray(position);//CPU传输到GPU,GPU可见数据跟操作

    

    GLuint textCoor = glGetAttribLocation(self.myProgram, "textCoordinate");

    glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL +3);

    glEnableVertexAttribArray(textCoor);

    

    //加载纹理

    [self setupTexture:@"123.png"];

    //获取shader里面的变量,这里记得要在linkProgram后面

    GLuint rotate = glGetUniformLocation(self.myProgram, "rotateMatrix");

    float radians = 10 * 3.14159f / 180.f;

    float s = sin(radians);

    float c = cos(radians);

    

    //z轴旋转矩阵

    GLfloat zRotation[16] = {

        c, -s, 0, 0.2,

        s,  c, 0, 0,

        0,  0, 1, 0,

        0,  0, 0, 1

    };

    

    //设置旋转矩阵

    glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);

    //glUniformMatrix4fv:将数组以列向量的形式存放到矩阵中的

    /*param

            GLint location          shader uniform变量的位置索引

            GLsizei count           要更新矩阵的数量,可以同事对多个矩阵赋值

            GLboolean transpose     矩阵是行主序还是列主序,默认行主序

            const GLfloat* value    矩阵地址指针

     */

    

    glDrawArrays(GL_TRIANGLES, 0, 6);

    /*glDrawArrays-para

        GLenum  mode        GL_TRIANGLES/GL_TRIANGLE_FAN/GL_TRIANGLE_STRIP

        GLint   first       从顶点数组缓存中哪一位开始绘制

        GLsizei count       顶点数量

     */

    

    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];

    

}

 

/**

 *  c语言编译流程:预编译、编译、汇编、链接

 *  glsl的编译过程主要有glCompileShader、glAttachShader、glLinkProgram三步;

 *  @param vert 顶点着色器

 *  @param frag 片元着色器

 *  @return 编译成功的shaders

 */

- (GLuint)loadShaders:(NSString *)vert frag:(NSString *)frag {

    GLuint verShader,fragShader;

    GLint program = glCreateProgram();

    

    //编译

    [self compileShader:&verShader type:GL_VERTEX_SHADER file:vert];

    [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];

    

    glAttachShader(program, verShader);

    glAttachShader(program, fragShader);

    

    //释放shader

    glDeleteShader(verShader);

    glDeleteShader(fragShader);

    

    return program;

}

- (void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file {

    //读取字符串

    NSString *content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];

    const GLchar *source = (GLchar *)[content UTF8String];

    

    *shader = glCreateShader(type);

    glShaderSource(*shader, 1, &source, NULL);

    glCompileShader(*shader);

}

 

#pragma mark - private method

- (void)setupLayer {

    self.myEagLayer = (CAEAGLLayer *)self.layer;

    //设置放大倍数

    [self setContentScaleFactor:[[UIScreen mainScreen] scale]];

    

    //CALayer默认是透明,必须将其设置为不透明才能看得见

    self.myEagLayer.opaque = YES;

    

    //设置描述属性,在这里设置不为耻渲染内容以及颜色格式为 RGBA8

    self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat,                                          nil];

}

 

- (void)setupContext {

    //指定OpenGL 渲染API版本,在这里我们使用OpenGL ES 2.0

    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;

    EAGLContext *context = [[EAGLContext alloc] initWithAPI:api];

    if (!context) {

        NSLog(@"Failed to initialize OpenGLES 2.0 context");

        exit(1);

    }

    //设置为当前上下文

    if (![EAGLContext setCurrentContext:context]) {

        NSLog(@"Failed to set current OpenGL context");

        exit(1);

    }

    self.myContext = context;

}

 

- (void)destoryRenderAndFrameBuffer {

    glDeleteFramebuffers(1, &_myColorFrameBuffer);

    self.myColorFrameBuffer = 0;

    glDeleteRenderbuffers(1, &_myColorRenderBuffer);

    self.myColorRenderBuffer = 0;

}

 

- (void)setupRenderBuffer {

    GLuint buffer;

    glGenRenderbuffers(1, &buffer);//返回id不能为0,0已经内部保留,id为0标示默认的帧缓冲区,就是”窗口系统提供的“帧缓冲区。

    self.myColorRenderBuffer = buffer;

    glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer);

    [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];

}

 

- (void)setupFrameBuffer {

    //Framebuffer object通常也称为FBO,相当于buffer(color,depth,stencil)的管理者,一个FBO也包含颜色缓冲区,深度缓冲区,模板缓冲区,三大buffer可以附加到一个FBO上

    /*

    颜色缓冲区:就是帧缓冲区(图形设备的内存),需要渲染的场景的每一个像素都最终写入该缓冲区,然后由他渲染到屏幕上显示。

    

    深度缓冲区:与帧缓冲区对应,用于记录上面每个像素的深度值,通过深度缓冲区,我们可以进行深度测试,从而确定像素的遮挡关系,保证渲染正确。(注意区分深度测试和背面剔除)

    

    模板缓冲区:与深度缓冲区类似,通过设置模板缓冲每个像素的值,我们可以在渲染的时候只渲染后写像素,从而可以达到一些特殊的效果。

    模板缓冲区可以为屏幕上的每个像素点保存一个无符号的整数值,在渲染过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值

     */

    GLuint buffer;

    glGenFramebuffers(1, &buffer);

    self.myColorFrameBuffer = buffer;

    glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);

    //附加渲染缓冲区镜像到FBO中

    //void glFramebufferRenderbuffer(GLenum target,GLenum attachmentPoint, GLenum renderbufferTarget,GLuint renderbufferId)

    

}

 

- (GLuint)setupTexture:(NSString *)fileName {

    //获取图片CGImageRef

    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;

    if (!spriteImage) {

        NSLog(@"failed to load image %@",fileName);

        exit(1);

    }

    

    //读取图片大小

    size_t width = CGImageGetWidth(spriteImage);

    size_t height = CGImageGetHeight(spriteImage);

    

    GLubyte *spriteData = (GLubyte *)calloc(width * height *4, sizeof(GLubyte));//rgba,每个像素4个byte

    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);

    /*@param

        data    指向要渲染的绘制内存的地址。这个内存块的大小至少是(bytesPerRow*height)个字节

        width   bitmap的宽度,单位为像素

        height  bitmap的高度,单位为像素

        bitsPerComponent  内存中像素的每个组件的位数.例如,对于32位像素格式和RGB 颜色空间,你应该将这个值设为8.

        bytesPerRow   bitmap的每一行在内存所占的比特数

        colorspace    bitmap上下文使用的颜色空间。

        bitmapInfo    指定bitmap是否包含alpha通道,像素中alpha通道的相对位置,像素组件是整形还是浮点型等信息的字符串。

    */

    //在CGContextRef上绘图

    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);

    CGContextRelease(spriteContext);

    

    //绑定纹理到默认的纹理ID(这里只有一张图片,故而相当于默认于片元着色器里面的colorMap)

    glBindTexture(GL_TEXTURE_2D, 0);

    /*glBindTexture-parameters

        target      指定纹理要绑定到的目标,必须是GL_TEXTURE_2D或者GL_TEXTURE_CUBE_MAP。

        texture     指明纹理的名称。

    */

    

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    

    /*glTexParameteri-parameters

     @target

     @pname     GL_TEXTURE_MIN_FILTER:缩小时,纹理像素处理

                GL_TEXTURE_MAG_FILTER:放大时,纹理像素处理

                GL_TEXTURE_WRAP_S:纹理像素水平方向包裹方式

                GL_TEXTURE_WRAP_T:纹理像素垂直方向包裹方式

     

     @param     /用于S/T方向上的纹素包裹方式/

                GL_LINEAR:线性滤波,上下左右方向取像素,进行加权求像素

                GL_NEAREST:邻近滤波,对像素坐标进行取整,用最佳逼近点获取纹素,这种方式容易导致走样误差,有明显像素块

                

                /用于放大缩小纹素处理方式/

                GL_REPEAT:坐标的整数部分被忽略,重复纹理,这是OpenGL纹理默认的处理方式.

                GL_MIRRORED_REPEAT: 纹理也会被重复,但是当纹理坐标的整数部分是奇数时会使用镜像重复。

                GL_CLAMP_TO_EDGE: 坐标会被截断到[0,1]之间。结果是坐标值大的被截断到纹理的边缘部分,形成了一个拉伸的边缘(stretched edge pattern)。

                GL_CLAMP_TO_BORDER: 不在[0,1]范围内的纹理坐标会使用用户指定的边缘颜色。

     */

    

    float fw = width, fh = height;

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

    /*glTexImage2D-parameters

         GLenum target           纹理目标

         GLint level             纹理等级,0代表原始等级

         GLint internalFormat    纹理存储格式,读取图片格式包含RGBA颜色,所以这里这用GRBA

         GLsizei width           纹理图片宽

         GLsizei height          纹理图片高

         GLint border            历史遗留参数,只能设置0

         GLenum format           原始图片格式

         GLenum type             原始图片数据类型

         const GLvoid * data     原始图片内存地址指针

     */

    

    glBindTexture(GL_TEXTURE_2D, 0);

    

    free(spriteData);

    return 0;

}

 

@end

 

 

shader_v.vsh:

attribute vec4 position;//顶点坐标

attribute vec2 textCoordinate;//uv坐标

uniform   mat4 rotateMatrix;

varying lowp vec2 varyTextCoord;

void main() {

    varyTextCoord = textCoordinate;

    vec4 vPos = position;

    vPos = vPos*rotateMatrix;

    gl_Position = vPos;

}

 

shader_f.fsh

varying lowp vec2 varyTextCoord;

uniform sampler2D colorMap;

void main() {

    gl_FragColor = texture2D(colorMap, varyTextCoord);

}

 

© 著作权归作者所有

gdxz110
粉丝 7
博文 80
码字总数 31663
作品 0
广州
程序员
私信 提问
技术分享连载(六十四)

原文链接:https://blog.uwa4d.com/archives/TechSharing_64.html 我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现...

UWA4D
2017/11/27
0
0
技术分享连载(七十一)

原文链接:https://blog.uwa4d.com/archives/1897.html 我们将从日常技术交流中精选若干个开发相关的问题,建议阅读时间15分钟,认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系...

UWA4D
2017/12/01
0
0
虚幻4渲染笔记【第二卷:不用虚幻4Shader管线使用自己的shader】

先直接上效果: 这个球的颜色是通过自己的shader实现的: 下面就来一步一步实现使用自己的shader吧。 首先我们先创建一个插件。插件其实相当于一个独立的模块,我不想再项目里做,当然再游戏...

qq_16756235
2018/04/23
0
0
Unity5.X打包场景为AssetBundle后,加载场景后烘培灯光贴图不显示

这几天打包时突然出现了场景加载后不显示灯光信息,一开始怀疑是灯光贴图丢失了,于是我就测试了场景有没有灯光贴图信息: 得到的结果是有值的,所以说明贴图是映射是正常的,那只可能是sha...

AngerCow
01/19
0
0
用 glew 来学习 opengles

想系统的学习一下 opengles 就买了一本书《OpenglES 3.0 编程指南》。书中的例子支持在 Windows Linux 安卓等平台运行。因为我的日常开发环境是 Windows ,所以更倾向于在 Windows 上学习,最...

iiRecord
2016/06/01
207
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
5
0
CSS盒子模型

CSS盒子模型 组成: content --> padding --> border --> margin 像现实生活中的快递: 物品 --> 填充物 --> 包装盒 --> 盒子与盒子之间的间距 content :width、height组成的 内容区域 padd......

studywin
今天
7
0
修复Win10下开始菜单、设置等系统软件无法打开的问题

因为各种各样的原因导致系统文件丢失、损坏、被修改,而造成win10的开始菜单、设置等系统软件无法打开的情况,可以尝试如下方法解决 此方法只在部分情况下有效,但值得一试 用Windows键+R打开...

locbytes
昨天
8
0
jquery 添加和删除节点

本文转载于:专业的前端网站➺jquery 添加和删除节点 // 增加一个三和一节点function addPanel() { // var newPanel = $('.my-panel').clone(true) var newPanel = $(".triple-panel-con......

前端老手
昨天
8
0
一、Django基础

一、web框架分类和wsgiref模块使用介绍 web框架的本质 socket服务端 与 浏览器的通信 socket服务端功能划分: 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 根据用户访问...

ZeroBit
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部