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

 

 

 

 

相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
目录
相关文章
|
4月前
|
编解码 边缘计算 vr&ar
注视点渲染Foveated rendering是什么
Foveated rendering听起来好像是非常复杂的技术。但实际上注视点(foveation)的底层概念非常直接。使用人注视屏幕的信息,可以减少生成场景的运算资源,方式是使用高分辨率渲染人眼观看的小区哉,而场景外的其它区域(人的四周)采用更小的分辨率和更少的细节。注视点渲染主要用于显示技术,如VR头显和AR眼镜,对些场景资源优化至关重要。
81 1
|
6月前
249Echarts - 3D 曲面(Simple Surface)
249Echarts - 3D 曲面(Simple Surface)
30 0
|
12月前
|
小程序 图形学 C语言
OpenglEs之着色器
Opengl ES连载系列
79 0
Core Animation - 视觉效果<二>
Core Animation - 视觉效果<二>
32 0
|
算法 iOS开发
Core Animation - 视觉效果<三>
Core Animation - 视觉效果<三>
49 0
|
iOS开发
Core Animation - 视觉效果<一>
Core Animation - 视觉效果<一>
74 0
|
API 计算机视觉 索引
|
存储
Renderer.material与Renderer.sharedMaterial的区别
此函数自动实例化材质并使它们对于此渲染器是唯一的。在销毁游戏对象时销毁材料是您的责任。 Resources.UnloadUnusedAssets 也会破坏材质,但通常仅在加载新关卡时调用。
221 0
Renderer.material与Renderer.sharedMaterial的区别
网页视频播放器(easyplayer和vue-video-player的使用)
网页视频播放器(easyplayer和vue-video-player的使用)1. 两种方式实现的网页播放器 2. 支持的视频格式不太相同
网页视频播放器(easyplayer和vue-video-player的使用)
|
JavaScript 开发工具 开发者
解决Electron应用中Lottie动画无法正常显示
我们用Flutter Web开发了一个应用,通过electron进行打包成可执行文件,但是在使用时发现了一个问题,Lottie动画无法显示。 通过console的日志可以看到,提示lottie是undifine的,lottie是sdk提供的一个全局的对象,通过lottie.loadAnimation(options)可以加载显示Lottie动画,但是我们明明在index.html中引入了Lottie的js文件,而且在浏览器上也是可以正常使用的,为什么通过Electron打包后执行就失效了?
307 0