首页 > 代码库 > OpenGLES渲染

OpenGLES渲染

OpenGLES渲染

OpenGLES使用GPU渲染图片,不占用CPU,但其使用还是挺复杂的.

先用OpenGLES显示一张图片:

//
//  ShowViewController.m
//  OpenGLES
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "ShowViewController.h"
#import <GLKit/GLKit.h>
#import <CoreImage/CoreImage.h>

@interface ShowViewController ()
@property (nonatomic, strong) GLKView   *viewBuffer;
@end

@implementation ShowViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 获取OpenGLES渲染环境
    EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
    // 根据图片获取尺寸
    UIImage *image = [UIImage imageNamed:@"demo.png"];
    CIImage *ciimage = [[CIImage alloc] initWithImage:image];
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
    
    // 初始化GLKView并指定OpenGLES渲染环境
    _viewBuffer = [[GLKView alloc] initWithFrame:rect context:eaglContext];
    [self.view addSubview:_viewBuffer];
    
    // 与OpenGLES绑定
    [_viewBuffer bindDrawable];
    
    // 定义绘制区域(像素描述)
    CGRect rectInPixels =         CGRectMake(0.0, 0.0, _viewBuffer.drawableWidth, _viewBuffer.drawableHeight);
    
    // 初始化CIImage的环境,指定在OpenGLES2上操作(此处只在GPU上操作)
    CIContext *context =         [CIContext contextWithEAGLContext:eaglContext
                                  options:@{kCIContextWorkingColorSpace:[NSNull null]}];
    
    // 开始绘制
    [context drawImage:ciimage
                inRect:rectInPixels
              fromRect:[ciimage extent]];
    
    // 显示
    [_viewBuffer display];
}

@end

只是显示一张图片而已,就需要写这么多的代码-_-!!!!

他有什么优势呢?其实,它的优势是实时渲染图片,不卡的.

//
//  RootViewController.m
//  OpenGLES
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "RootViewController.h"
#import <GLKit/GLKit.h>
#import <CoreImage/CoreImage.h>
#import <QuartzCore/QuartzCore.h>

@interface RootViewController ()

@property (nonatomic, strong) GLKView   *viewBuffer;

@property (nonatomic, strong) CIContext *ciContext;
@property (nonatomic, strong) CIImage   *ciImage;
@property (nonatomic, strong) CIFilter  *ciFilter;

@end

@implementation RootViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 获取OpenGLES2渲染环境
    EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    
    // 初始化一个viewBuffer,并指定在OpenGLES2环境渲染
    CGRect rect = CGRectMake(0, 0,
                             [UIImage imageNamed:@"demo"].size.width,
                             [UIImage imageNamed:@"demo"].size.height);
    _viewBuffer = [[GLKView alloc] initWithFrame:rect
                                         context:eaglContext];
    
    // 绑定将这个view与OpenGLES2绑定
    [_viewBuffer bindDrawable];
    [self.view addSubview:_viewBuffer];
    
    // 初始化CIImage的环境,指定在OpenGLES2上操作(此处只在GPU上操作)
    _ciContext = [CIContext contextWithEAGLContext:eaglContext
                                           options:@{kCIContextWorkingColorSpace:[NSNull null]}];
    
    // 获取CIImage
    _ciImage = [[CIImage alloc] initWithImage:[UIImage imageNamed:@"demo"]];
    
    // 初始化一个CIFilter
    _ciFilter = [CIFilter filterWithName:@"CISepiaTone"];
    [_ciFilter setValue:_ciImage forKey:kCIInputImageKey];
    [_ciFilter setValue:@0 forKey:kCIInputIntensityKey];
    
    // 定义绘制区域(像素描述)
    CGRect rectInPixels =         CGRectMake(0.0, 0.0, _viewBuffer.drawableWidth, _viewBuffer.drawableHeight);
    
    // 开始绘制
    [_ciContext drawImage:_ciImage
                   inRect:rectInPixels
                 fromRect:[_ciImage extent]];
    [_viewBuffer display];
    
    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 400, 320, 20)];
    [self.view addSubview:slider];
    [slider addTarget:self
               action:@selector(event:)
     forControlEvents:UIControlEventValueChanged];
    slider.minimumValue = 0;
    slider.maximumValue = 1;
}

- (void)event:(UISlider *)slider
{
    [_ciFilter setValue:[NSNumber numberWithFloat:slider.value]
                 forKey:kCIInputIntensityKey];
    
    // 定义绘制区域(像素描述)
    CGRect rectInPixels =     CGRectMake(0.0, 0.0, _viewBuffer.drawableWidth, _viewBuffer.drawableHeight);
    
    [_ciContext drawImage:[_ciFilter outputImage]
                 inRect:rectInPixels
               fromRect:[_ciImage extent]];
    [_viewBuffer display];
}

@end

将这个View封装一下吧.

GPUView.h + GPUView.m

//
//  GPUView.h
//  OpenGLES
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#import <CoreImage/CoreImage.h>

@interface GPUView : UIView

- (void)drawCIImage:(CIImage *)ciImage;

@end
//
//  GPUView.m
//  OpenGLES
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "GPUView.h"

@interface GPUView ()

@property (nonatomic, assign)  CGRect     rectInPixels;
@property (nonatomic, strong)  CIContext *context;
@property (nonatomic, strong)  GLKView   *showView;

@end

@implementation GPUView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        // 获取OpenGLES渲染环境
        EAGLContext *eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        
        // 初始化GLKView并指定OpenGLES渲染环境 + 绑定
        _showView = [[GLKView alloc] initWithFrame:frame context:eaglContext];
        [_showView bindDrawable];
        
        // 添加进图层
        [self addSubview:_showView];
        
        // 创建CIContext环境
        _context =             [CIContext contextWithEAGLContext:eaglContext
                                      options:@{kCIContextWorkingColorSpace:[NSNull null]}];
        
        // 定义绘制区域(像素描述)
        _rectInPixels =             CGRectMake(0.0, 0.0, _showView.drawableWidth, _showView.drawableHeight);
    }
    return self;
}

- (void)drawCIImage:(CIImage *)ciImage
{
    // 开始绘制
    [_context drawImage:ciImage
                 inRect:_rectInPixels
              fromRect:[ciImage extent]];
    
    // 显示
    [_showView display];
}

@end

实现同样的效果:

//
//  ShowViewController.m
//  OpenGLES
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "ShowViewController.h"
#import <CoreImage/CoreImage.h>
#import "GPUView.h"

@interface ShowViewController ()
@property (nonatomic, strong) CIFilter  *ciFilter;
@property (nonatomic, strong) GPUView   *gpuView;
@end

@implementation ShowViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 根据图片获取尺寸
    UIImage *image   = [UIImage imageNamed:@"demo.png"];
    CIImage *ciimage = [[CIImage alloc] initWithImage:image];
    CGRect rect      = CGRectMake(0, 0, image.size.width, image.size.height);
    
    // 初始化GPUView
    _gpuView = [[GPUView alloc] initWithFrame:rect];
    [self.view addSubview:_gpuView];
    [_gpuView drawCIImage:ciimage];
    
    // 初始化一个CIFilter
    _ciFilter = [CIFilter filterWithName:@"CISepiaTone"];
    [_ciFilter setValue:ciimage forKey:kCIInputImageKey];
    [_ciFilter setValue:@0 forKey:kCIInputIntensityKey];
    
    // 初始化一个UISlider
    UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 400, 320, 20)];
    [self.view addSubview:slider];
    [slider addTarget:self
               action:@selector(event:)
     forControlEvents:UIControlEventValueChanged];
    slider.minimumValue = 0;
    slider.maximumValue = 1;
}

- (void)event:(UISlider *)slider
{
    [_ciFilter setValue:[NSNumber numberWithFloat:slider.value]
                 forKey:kCIInputIntensityKey];
    [_gpuView drawCIImage:[_ciFilter outputImage]];
}

@end

看起来简洁多了.....

来点复杂点的,同时操作两个滤镜

//
//  ShowViewController.m
//  OpenGLES
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "ShowViewController.h"
#import <CoreImage/CoreImage.h>
#import "GPUView.h"

@interface ShowViewController ()
@property (nonatomic, strong) CIFilter  *ciFilter1;
@property (nonatomic, strong) CIFilter  *ciFilter2;
@property (nonatomic, strong) GPUView   *gpuView;

@property (nonatomic, strong) UISlider  *slider1;
@property (nonatomic, strong) UISlider  *slider2;
@end

@implementation ShowViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // 根据图片获取尺寸
    UIImage *image   = [UIImage imageNamed:@"demo.png"];
    CIImage *ciimage = [[CIImage alloc] initWithImage:image];
    CGRect rect      = CGRectMake(0, 0, image.size.width, image.size.height);
    
    // 初始化GPUView
    _gpuView = [[GPUView alloc] initWithFrame:rect];
    [self.view addSubview:_gpuView];
    [_gpuView drawCIImage:ciimage];
    
    // 初始化一个CIFilter
    _ciFilter1 = [CIFilter filterWithName:@"CISepiaTone"];
    [_ciFilter1 setValue:ciimage forKey:kCIInputImageKey];
    [_ciFilter1 setValue:@0.f forKey:kCIInputIntensityKey];
    
    _ciFilter2 = [CIFilter filterWithName:@"CIHueAdjust"];
    [_ciFilter2 setValue:[_ciFilter1 outputImage] forKeyPath:kCIInputImageKey];
    [_ciFilter2 setValue:@0.f forKeyPath:kCIInputAngleKey];
    
    // 初始化UISlider
    _slider1 = [[UISlider alloc] initWithFrame:CGRectMake(0, 400, 320, 20)];
    [self.view addSubview:_slider1];
    [_slider1 addTarget:self
               action:@selector(event1:)
     forControlEvents:UIControlEventValueChanged];
    _slider1.minimumValue = 0;
    _slider1.maximumValue = 1;
    _slider1.value = 0.5f;
    
    _slider2 = [[UISlider alloc] initWithFrame:CGRectMake(0, 450, 320, 20)];
    [self.view addSubview:_slider2];
    [_slider2 addTarget:self
                action:@selector(event2:)
      forControlEvents:UIControlEventValueChanged];
    _slider2.minimumValue = -3.14f;
    _slider2.maximumValue = +3.14f;
    _slider2.value = 0.f;
}

- (void)event1:(UISlider *)slider
{
    [_ciFilter1 setValue:[NSNumber numberWithFloat:_slider1.value]
                 forKey:kCIInputIntensityKey];
    [_ciFilter2 setValue:[_ciFilter1 outputImage] forKeyPath:kCIInputImageKey];
    [_ciFilter2 setValue:[NSNumber numberWithFloat:_slider2.value] forKeyPath:kCIInputAngleKey];
    [_gpuView drawCIImage:[_ciFilter2 outputImage]];
}

- (void)event2:(UISlider *)slider
{
    [_ciFilter1 setValue:[NSNumber numberWithFloat:_slider1.value]
                  forKey:kCIInputIntensityKey];
    [_ciFilter2 setValue:[_ciFilter1 outputImage] forKeyPath:kCIInputImageKey];
    [_ciFilter2 setValue:[NSNumber numberWithFloat:_slider2.value] forKeyPath:kCIInputAngleKey];
    [_gpuView drawCIImage:[_ciFilter2 outputImage]];
}

@end