OS X中如何使用OpenGL 3.2 Core Profile


從OS X Lion(10.7)開始,Apple支持了對OpenGL 3.2 Core Profile的支持。不過Core Profile與Compatible相比有比較大幅度的改變。從主機端的API到OpenGL接口,再到GLSL(OpenGL Shading Language),這些方面都有些變化。

在主機端接口方面,首先,必須用<OpenGL/gl3.h>來代替原來的<OpenGL/gl.h>,這點很重要!

其次,在NSOpenGLPixelFormatAttribute對象中必須增加NSOpenGLPFAOpenGLProfile以及NSOpenGLProfileVersion3_2Core這兩個屬性。

在最后完成繪制后,需要調用CGL庫的CGLFlushDrawable接口將所渲染的圖形結果顯示到視圖或窗口上。

在OpenGL接口使用方面,必須使用VAO和VBO來存放頂點數據。然后,所有與固定功能流水線相關的接口都被移出,無法使用。因此這些被移除的功能只能通過Shader來實現。

在GLSL方面,必須顯式地加上GLSL的版本號,並且至少為140(表示1.40),在基於Sandy Bridge的Intel HD Graphics 3000上默認為150(1.50)。然后,in、out代替了原來的attribute和varying關鍵字。在Fragment shader中,gl_FragColor內建變量被取消,你可以自己定義一個out變量作為最后像素的輸出。

下面給出一個比較基本、簡潔的代碼樣例:

//
//  MyGLView.h
//  OpenGLShaderBasic
//
//  Created by Zenny Chen on 10/4/10.
//  Copyright 2010 GreenGames Studio. All rights reserved.
//

#import <Cocoa/Cocoa.h>


@interface MyGLView : NSOpenGLView
{
    GLuint program;
    
    GLuint vbo, vao;
}

- (void)render;

@end
//
//  MyGLView.m
//  OpenGLShaderBasic
//
//  Created by Zenny Chen on 10/4/10.
//  Copyright 2010 GreenGames Studio. All rights reserved.
//

#import "MyGLView.h"

// 這里必須注意!<gl3.h>頭文件必須被包含並取代<gl.h>,否則VAO接口會調用不正常,從而無法正確顯示圖形!
#import <OpenGL/gl3.h>

#define MY_PIXEL_WIDTH      128
#define MY_PIXEL_HEIGHT     128

@implementation MyGLView

// attribute index
enum
{
    ATTRIB_VERTEX,
    
    NUM_ATTRIBUTES
};


- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
	GLint status;
	const GLchar *source;
	
	source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
	if (!source)
	{
		NSLog(@"Failed to load vertex shader");
		return FALSE;
	}
	
    *shader = glCreateShader(type);
    glShaderSource(*shader, 1, &source, NULL);
    glCompileShader(*shader);
	
	GLint logLength;
    glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(*shader, logLength, &logLength, log);
        NSLog(@"Shader compile log:\n%s", log);
        free(log);
    }
    
    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
    if (status == 0)
	{
		glDeleteShader(*shader);
		return FALSE;
	}
	
	return TRUE;
}

- (BOOL)linkProgram:(GLuint)prog
{
	GLint status;
	
	glLinkProgram(prog);
    
	GLint logLength;
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(prog, logLength, &logLength, log);
        NSLog(@"Program link log:\n%s", log);
        free(log);
    }
    
    glGetProgramiv(prog, GL_LINK_STATUS, &status);
    if (status == 0)
		return FALSE;
	
	return TRUE;
}

- (BOOL)validateProgram:(GLuint)prog
{
	GLint logLength, status;
	
	glValidateProgram(prog);
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(prog, logLength, &logLength, log);
        NSLog(@"Program validate log:\n%s", log);
        free(log);
    }
    
    glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
    if (status == 0)
		return FALSE;
	
	return TRUE;
}

- (BOOL)loadShaders
{
    GLuint vertShader, fragShader;
	NSString *vertShaderPathname, *fragShaderPathname;
    
    // create shader program
    program = glCreateProgram();
    
    // bind attribute locations
    // this needs to be done prior to linking
    glBindAttribLocation(program, ATTRIB_VERTEX, "inPos");
	
    // create and compile vertex shader
	vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
	if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname])
	{
		NSLog(@"Failed to compile vertex shader");
		return FALSE;
	}
	
    // create and compile fragment shader
	fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
	if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname])
	{
		NSLog(@"Failed to compile fragment shader");
		return FALSE;
	}
    
    // attach vertex shader to program
    glAttachShader(program, vertShader);
    
    // attach fragment shader to program
    glAttachShader(program, fragShader);
    
    //glBindFragDataLocationEXT(program, 0, "myOutput");
    
    // link program
	if (![self linkProgram:program])
	{
		NSLog(@"Failed to link program: %d", program);
		return FALSE;
	}
    
    // release vertex and fragment shaders
    if (vertShader)
		glDeleteShader(vertShader);
    if (fragShader)
		glDeleteShader(fragShader);
	
	return TRUE;
}

- (id)initWithFrame:(NSRect)frameRect
{
    self = [super initWithFrame:frameRect];
    
    NSOpenGLPixelFormatAttribute attrs[] =
	{
        NSOpenGLPFADoubleBuffer,    // 可選地,可以使用雙緩沖
		NSOpenGLPFAOpenGLProfile,   // Must specify the 3.2 Core Profile to use OpenGL 3.2
		NSOpenGLProfileVersion3_2Core,
		0
	};
	
	NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
	
	if (!pf)
	{
		NSLog(@"No OpenGL pixel format");
	}
    
    NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
    
    [self setPixelFormat:pf];
    [pf release];
    
    [self setOpenGLContext:context];
    [context release];
    
    return self;
}

- (void)dealloc
{
    if(vbo != 0)
        glDeleteFramebuffers(1, &vbo);
    if(vao != 0)
        glDeleteRenderbuffers(1, &vao);
    
    [super dealloc];
}

- (void)prepareOpenGL
{
    [super prepareOpenGL];
    
	[[self openGLContext] makeCurrentContext];
	
	// Synchronize buffer swaps with vertical refresh rate
	GLint swapInt = 1;
	[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
    
    // Drawing code here.
    static const GLfloat squareVertices[] = {
        -1.0f,  1.0f, 0.0f, 1.0f,
        -1.0f, -1.0f, 0.0f, 1.0f,
        1.0f,  1.0f, 0.0f, 1.0f,
        1.0f, -1.0f, 0.0f, 1.0f
    };
    
    // In OpenGL 3.2 core profile, vertex buffer object and vertex array object must be used!
    glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);
    
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(squareVertices), squareVertices, GL_STATIC_DRAW);
    
	// Update attribute values
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_VERTEX, 4, GL_FLOAT, 0, 0, (const GLvoid*)0);
    
    // Load shaders and build the program
    if(![self loadShaders])
        return;
    
	// Use shader program
    glUseProgram(program);
    
    glViewport(0, 0, MY_PIXEL_WIDTH, MY_PIXEL_HEIGHT);
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
}


- (void)render
{    
    // render
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glFlush();
	
	CGLFlushDrawable([[self openGLContext] CGLContextObj]);
}

@end

以上兩個文件是主要的使用OpenGL接口的樣例頭文件和源文件。在這個例子中,OpenGL的上下文基於一個視圖(NSOpenGLView的子類)。

下面將給出Shader源代碼:

//
//  Shader.fsh
//  GLSLTest
//
//  Created by Zenny Chen on 4/11/10.
//  Copyright GreenGames Studio 2010. All rights reserved.
//

// 在OpenGL3.2 Core Profile中,版本號必須顯式地給出
#version 150

out vec4 myOutput;

void main()
{
    //gl_FragColor = vec4(0.1, 0.8, 0.5, 1.0);
    myOutput = vec4(0.1, 0.8, 0.5, 1.0);
}

 

//
//  Shader.vsh
//  GLSLTest
//
//  Created by Zenny Chen on 4/11/10.
//  Copyright GreenGames Studio 2010. All rights reserved.
//

// 在OpenGL3.2 Core Profile中,版本號必須顯式地給出
#version 150

in vec4 inPos;

void main()
{
    gl_Position = inPos;
}

下面給出AppDelegate中對MyGLView對象的具體調用。

//
//  AppDelegate.h
//  OpenGL4Compute
//
//  Created by zenny_chen on 12-12-9.
//  Copyright (c) 2012年 zenny_chen. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@class MyGLView;

@interface AppDelegate : NSObject <NSApplicationDelegate>
{
    MyGLView *glComputeObj;
}

@property (assign) IBOutlet NSWindow *window;

@end
//
//  AppDelegate.m
//  OpenGL4Compute
//
//  Created by zenny_chen on 12-12-9.
//  Copyright (c) 2012年 zenny_chen. All rights reserved.
//

#import "AppDelegate.h"
#import "MyGLView.h"

@implementation AppDelegate

- (void)dealloc
{
    [super dealloc];
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    NSView *baseView = self.window.contentView;
    CGSize viewSize = baseView.frame.size;
    
    NSButton *button = [[NSButton alloc] initWithFrame:CGRectMake(20.0f, viewSize.height - 60.0f, 60.0f, 30.0f)];
    [button setButtonType:NSMomentaryPushInButton];
    [button setBezelStyle:NSRoundedBezelStyle];
    [button setTitle:@"Show"];
    [button setTarget:self];
    [button setAction:@selector(computeButtonTouched:)];
    [baseView addSubview:button];
    [button release];
    
    NSLog(@"The view is: %@", [self.window.contentView class]);
}

- (void)computeButtonTouched:(id)sender
{
    if(glComputeObj == nil)
    {
        NSView *baseView = self.window.contentView;
        CGSize viewSize = baseView.frame.size;
        glComputeObj = [[MyGLView alloc] initWithFrame:CGRectMake((viewSize.width - 128.0f) * 0.5f, (viewSize.height - 128.0f) * 0.5f, 128.0f, 128.0f)];
        [baseView addSubview:glComputeObj];
        [glComputeObj release];
    }
    
    [glComputeObj performSelector:@selector(render) withObject:nil afterDelay:0.1];
}

@end


工程代碼可以在以下地址獲取:

http://www.cocoachina.com/bbs/read.php?tid=35895&page=1&toread=1#tpc

OpenGL3_2.zip

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM