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

 

 

 

 

 

转载于:https://www.cnblogs.com/YouXianMing/p/3760742.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用OpenGL ES渲染序列帧时,需要将每一帧的图像作为纹理加载到OpenGL ES中,并设置纹理坐标和顶点坐标来显示每一帧。以下是一些基本的步骤: 1. 将每一帧的图像转换成OpenGL ES所支持的纹理格式,例如RGBA8888。 2. 创建OpenGL ES的纹理对象,将纹理数据加载到纹理对象中。 3. 设置顶点坐标和纹理坐标,以便显示序列帧。 4. 在渲染循环中,每帧更新纹理对象的内容,并绘制序列帧。 以下是一个简单的示例代码: ```java public class FrameRenderer implements GLSurfaceView.Renderer { private int[] textures = new int[10]; // 存储纹理对象的数组 private Bitmap[] bitmaps = new Bitmap[10]; // 存储位图的数组 private int currentFrame = 0; // 当前帧 private final float[] vertices = { // 顶点坐标 -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; private final float[] texCoords = { // 纹理坐标 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }; public FrameRenderer(Context context) { // 加载序列帧 for (int i = 0; i < 10; i++) { bitmaps[i] = BitmapFactory.decodeResource(context.getResources(), R.drawable.frame_0000 + i); } } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // 创建纹理对象 GLES20.glGenTextures(textures.length, textures, 0); // 设置纹理参数 for (int i = 0; i < textures.length; i++) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmaps[i], 0); bitmaps[i].recycle(); // 释放位图内存 } } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); } @Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // 绑定纹理 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[currentFrame]); // 设置顶点坐标和纹理坐标 FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put(vertices); vertexBuffer.position(0); FloatBuffer texCoordBuffer = ByteBuffer.allocateDirect(texCoords.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put(texCoords); texCoordBuffer.position(0); // 绘制序列帧 int positionHandle = GLES20.glGetAttribLocation(program, "aPosition"); GLES20.glEnableVertexAttribArray(positionHandle); GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer); int texCoordHandle = GLES20.glGetAttribLocation(program, "aTexCoord"); GLES20.glEnableVertexAttribArray(texCoordHandle); GLES20.glVertexAttribPointer(texCoordHandle, 2, GLES20.GL_FLOAT, false, 0, texCoordBuffer); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); // 更新帧数 currentFrame = (currentFrame + 1) % textures.length; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值