open gl 加载图片

作者: 程一刀 | 来源:发表于2020-12-15 14:37 被阅读0次
    本文主要记录 如何使用 glsl 加载一张图片
    1.创建图层
    +(Class)layerClass
    {
        return [CAEAGLLayer class];
    }
    -(void)setupLayer
    {
        self.myEagLayer = (CAEAGLLayer *)self.layer;
        [self setContentScaleFactor:[[UIScreen mainScreen]scale]];
        self.myEagLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false,kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat,nil];
    }
    
    2.创建上下文
    -(void)setupContext
    {
        EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
        EAGLContext *context = [[EAGLContext alloc]initWithAPI:api];
        if (!context) {
            NSLog(@"falied!");
            return;
        }
        if (![EAGLContext setCurrentContext:context]) {
            NSLog(@"setCurrentContext failed!");
            return;
        }
        self.myContext = context;
    }
    
    
    3.清空缓存区域
    -(void)deleteRenderAndFrameBuffer
    {
        glDeleteBuffers(1, &_myColorRenderBuffer);
        self.myColorRenderBuffer = 0;
        glDeleteBuffers(1, &_myColorFrameBuffer);
        self.myColorFrameBuffer = 0;
    }
    
    
    4.设置 renderBuffer
    -(void)setupRenderBuffer
    {
        GLuint buffer;
        glGenRenderbuffers(1, &buffer);
        self.myColorRenderBuffer = buffer;
        glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer);
        [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];
    }
    
    
    5.设置 frameBuffer,绑定renderBuffer
    -(void)setupFrameBuffer
    {
        GLuint buffer;
        glGenRenderbuffers(1, &buffer);
        self.myColorFrameBuffer = buffer;
        glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
    }
    
    
    6.绘制图形
    -(void)renderLayer
    {
        glClearColor(0.3f, 0.45f, 0.5f, 1.0f);
        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" ofType:@"vsh"];
        NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"];
        self.myPrograme = [self loadShaders:vertFile Withfrag:fragFile];
        glLinkProgram(self.myPrograme);
        GLint linkStatus;
        //获取链接状态
        glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkStatus);
        if (linkStatus == GL_FALSE) {
            GLchar message[512];
            glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
            NSString *messageString = [NSString stringWithUTF8String:message];
            NSLog(@"Program Link Error:%@",messageString);
            return;
        }
        NSLog(@"Program Link Success!");
        glUseProgram(self.myPrograme);
        //前3个是顶点坐标,后2个是纹理坐标
        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.myPrograme, "position");
        glEnableVertexAttribArray(position);
        glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL);
        GLuint textCoor = glGetAttribLocation(self.myPrograme, "textCoordinate");
        glEnableVertexAttribArray(textCoor);
        glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL + 3);
        [self setupTexture:@"kunkun"];
        glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
        glDrawArrays(GL_TRIANGLES, 0, 6);
        [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
    }
    
    
    
    7.加载图片
    - (GLuint)setupTexture:(NSString *)fileName {
        
        //1、将 UIImage 转换为 CGImageRef
        CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
        
        //判断图片是否获取成功
        if (!spriteImage) {
            NSLog(@"Failed to load image %@", fileName);
            exit(1);
        }
        
        //2、读取图片的大小,宽和高
        size_t width = CGImageGetWidth(spriteImage);
        size_t height = CGImageGetHeight(spriteImage);
        
        //3.获取图片字节数 宽*高*4(RGBA)
        GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
        
        //4.创建上下文
        /*
         参数1:data,指向要渲染的绘制图像的内存地址
         参数2:width,bitmap的宽度,单位为像素
         参数3:height,bitmap的高度,单位为像素
         参数4:bitPerComponent,内存中像素的每个组件的位数,比如32位RGBA,就设置为8
         参数5:bytesPerRow,bitmap的没一行的内存所占的比特数
         参数6:colorSpace,bitmap上使用的颜色空间  kCGImageAlphaPremultipliedLast:RGBA
         */
        CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
        
    
        //5、在CGContextRef上--> 将图片绘制出来
        /*
         CGContextDrawImage 使用的是Core Graphics框架,坐标系与UIKit 不一样。UIKit框架的原点在屏幕的左上角,Core Graphics框架的原点在屏幕的左下角。
         CGContextDrawImage 
         参数1:绘图上下文
         参数2:rect坐标
         参数3:绘制的图片
         */
        CGRect rect = CGRectMake(0, 0, width, height);
       
        //6.使用默认方式绘制
        CGContextDrawImage(spriteContext, rect, spriteImage);
       
        //7、画图完毕就释放上下文
        CGContextRelease(spriteContext);
        
        //8、绑定纹理到默认的纹理ID(
        glBindTexture(GL_TEXTURE_2D, 0);
        
        //9.设置纹理属性
        /*
         参数1:纹理维度
         参数2:线性过滤、为s,t坐标设置模式
         参数3:wrapMode,环绕模式
         */
        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);
        
        float fw = width, fh = height;
        
        //10.载入纹理2D数据
        /*
         参数1:纹理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
         参数2:加载的层次,一般设置为0
         参数3:纹理的颜色值GL_RGBA
         参数4:宽
         参数5:高
         参数6:border,边界宽度
         参数7:format
         参数8:type
         参数9:纹理数据
         */
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
        
        //11.释放spriteData
        free(spriteData);   
        return 0;
    }
    
    
    8.加载shader
    //加载shader
    -(GLuint)loadShaders:(NSString *)vert Withfrag:(NSString *)frag
    {
        //1.定义2个零时着色器对象
        GLuint verShader, fragShader;
        //创建program
        GLint program = glCreateProgram();
        
        //2.编译顶点着色程序、片元着色器程序
        //参数1:编译完存储的底层地址
        //参数2:编译的类型,GL_VERTEX_SHADER(顶点)、GL_FRAGMENT_SHADER(片元)
        //参数3:文件路径
        [self compileShader:&verShader type:GL_VERTEX_SHADER file:vert];
        [self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];
        
        //3.创建最终的程序
        glAttachShader(program, verShader);
        glAttachShader(program, fragShader);
        
        //4.释放不需要的shader
        glDeleteShader(verShader);
        glDeleteShader(fragShader);
        
        return program;
    }
    
    //编译shader
    - (void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file{
        
        //1.读取文件路径字符串
        NSString* content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
        const GLchar* source = (GLchar *)[content UTF8String];
        
        //2.创建一个shader(根据type类型)
        *shader = glCreateShader(type);
        
        //3.将着色器源码附加到着色器对象上。
        //参数1:shader,要编译的着色器对象 *shader
        //参数2:numOfStrings,传递的源码字符串数量 1个
        //参数3:strings,着色器程序的源码(真正的着色器程序源码)
        //参数4:lenOfStrings,长度,具有每个字符串长度的数组,或NULL,这意味着字符串是NULL终止的
        glShaderSource(*shader, 1, &source,NULL);
        
        //4.把着色器源代码编译成目标代码
        glCompileShader(*shader);
        
        
    }
    
    
    9. 顶点着色器,片元着色器代码
    attribute vec4 position;
    attribute vec2 textCoordinate;
    varying lowp vec2 varyTextCoord;
    
    void main()
    {
        varyTextCoord = textCoordinate;
        gl_Position = position;
    }
    
    
    varying lowp vec2 varyTextCoord;
    uniform sampler2D colorMap;
    
    void main()
    {
        gl_FragColor = texture2D(colorMap, varyTextCoord);
        
    }
    
    
    对比于GLKit 加载图片,glsl 加载图片更琐碎

    1.传递顶点数据 纹理数据的差异
    2.加载纹理图片

    相关文章

      网友评论

        本文标题:open gl 加载图片

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