2013年3月1日 星期五

OpenGL基本實作(ㄧ)

在IOS上要實作一個OPENGL ES,需要一個使用到一個UIView的Class。因為 OpenGL ES是Core Animation的客戶,要使用OpenGL ES需要創建一個UIView,這個UIView由一個特殊的core animation layer支持,這個特殊的layer是一個CAEAGLLayer對象。 CAEAGLLayer是OpenGLES和core animation聯繫的橋樑當應用程序渲染完一幀後,CAEAGLLayer的內容被呈現並且和其他view的數據組合。

core animation是ios圖形子系統的基礎,UIView對象由core animation layer支持。各種各樣的layer更新他們的內容,由core animation動畫和合成,並向顯示設備呈現。

因此framework需要QuartzCore 及 OpenGLES。



OpenGL ES命令被提交到rendering context。這些命令可以讀取context的狀態,改變context的狀態,創建修改和銷毀OpenGL ES Object,以及提交被渲染的幾何體,幾何體通過流水線處理最終光柵化到framebuffer。


EAGLContext是OpenGL ES RenderingContext的iOS實現。每個程序有自己的EAGLContext,這保證了各個OpenGL ES程序互不干擾。在EAGLContext需要在調用任何OpenGL ES api前創建並初始化。


renderbuffer: 是某種特定格式的2d圖形。格式可以是顏色信息,也可以是深度或模板信息。 renderbuffer一般不單獨使用,而是被收集作為fraembuffer的一部分使用。Framebuffers: 是圖形流水線的最終目的地。一個framebuffer object其實是一個容器,包含了attach上去的紋理和renderbuffer。


drawableProperties可參考的官方資料
http://developer.apple.com/library/ios/#documentation/iPhone/Reference/EAGLDrawable_Ref/EAGLDrawable/EAGLDrawable.html



以下是一個實作的例子,參考http://blog.csdn.net/kesalin/article/details/8221393,並將程式改成UIViewController的模式。

1.首先開啓一個專案

  2. 加入一個UIView的Class檔,用來放置OpenGLES的程式碼

  3. 加入QuartzCore 及 OpenGLES的framework。


 4. 在OpenGLView.h加入程式碼

#import <UIKit/UIKit.h>

#import <QuartzCore/QuartzCore.h>
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>


@interface OpenGLView : UIView {
    CAEAGLLayer* _eaglLayer;
    EAGLContext* _context;
    GLuint _colorRenderBuffer;
    GLuint _frameBuffer;
}

- (void)setupLayer;
- (void)setupContext;
- (void)setupRenderBuffer;
- (void)destoryRenderAndFrameBuffer;
- (void)render;


@end

5. 在OpenGLView.m加入程式碼
#import "OpenGLView.h"

@implementation OpenGLView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self setupLayer];
        [self setupContext];

    }
    return self;
}

/*
 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.
 - (void)drawRect:(CGRect)rect
 {
 // Drawing code
 }
 */

+ (Class)layerClass {
    // 只有 [CAEAGLLayer class] 类型的 layer 才支持在其上描绘 OpenGL 内容。
    return [CAEAGLLayer class];
}

- (void)setupLayer
{
    _eaglLayer = (CAEAGLLayer*) self.layer;
   
    // CALayer 默认是透明的,必须将它设为不透明才能让其可见
    _eaglLayer.opaque = YES;
   
    // 设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8
    _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}

- (void)setupContext {
    // 指定 OpenGL 渲染 API 的版本,在这里我们使用 OpenGL ES 2.0
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
    _context = [[EAGLContext alloc] initWithAPI:api];
    if (!_context) {
        NSLog(@"Failed to initialize OpenGLES 2.0 context");
        exit(1);
    }
   
    // 设置为当前上下文
    if (![EAGLContext setCurrentContext:_context]) {
        _context = nil;
       
        NSLog(@"Failed to set current OpenGL context");
        exit(1);
    }
}

- (void)setupRenderBuffer {
    glGenRenderbuffers(1, &_colorRenderBuffer);
    // 设置为当前 renderbuffer
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
    // 为 color renderbuffer 分配存储空间
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}

- (void)setupFrameBuffer {
    glGenFramebuffers(1, &_frameBuffer);
    // 设置为当前 framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    // 将 _colorRenderBuffer 装配到 GL_COLOR_ATTACHMENT0 这个装配点上
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                              GL_RENDERBUFFER, _colorRenderBuffer);
}

- (void)destoryRenderAndFrameBuffer
{
    glDeleteFramebuffers(1, &_frameBuffer);
    _frameBuffer = 0;
    glDeleteRenderbuffers(1, &_colorRenderBuffer);
    _colorRenderBuffer = 0;
}

- (void)render {
    glClearColor(0, 1.0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
   
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

- (void)layoutSubviews {
    [EAGLContext setCurrentContext:_context];
   
    [self destoryRenderAndFrameBuffer];
   
    [self setupRenderBuffer];
    [self setupFrameBuffer];
   
    [self render];
}


@end

6. 在mainViewController.h加入OpenGL的呼叫變數
#import <UIKit/UIKit.h>
#import "OpenGLView.h"

@interface mainViewController : UIViewController

@property (strong, retain) IBOutlet OpenGLView *glView;

@end

7. 在mainViewController.m加入OpenGL執行程式
#import "mainViewController.h"

@interface mainViewController ()

@end

@implementation mainViewController

@synthesize glView = _glView;

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
   
    //self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   
    //CGRect screenBounds = [[UIScreen mainScreen] bounds];
   
     _glView = [[OpenGLView alloc] initWithFrame:CGRectMake(300, 300, 200, 200)];
    [self.view addSubview:self.glView];
   
    self.view.backgroundColor = [UIColor whiteColor];
    // [self.view makeKeyAndVisible];

   
   
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end


8. 執行結果,劃出一個200x200的區域