macOS中如何使用OpenGL 3.2 Core Profile

2023-11-12

从macOS 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)。然后,inout 代替了原来的 attributevarying 关键字。在Fragment shader中,gl_FragColor 内建变量被取消,你可以自己定义一个 out 变量作为最后像素的输出。

下面给出一个比较基本、简洁的代码样例:

以下是 MyGLView.h 头文件的内容

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

 
@interface MyGLView : NSOpenGLView
{
    GLuint program;
     
    GLuint vbo, vao;
}
 
- (void)render;
 
@end

以下是 MyGLView.m 源文件的内容:

//
//  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 == NULL)
    {
        NSLog(@"Failed to load vertex shader");
        return NO;
    }
     
    *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 NO;
    }
     
    return YES;
}
 
- (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 NO;
    
    return YES;
}

- (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 NO;
     
    return YES;
}
 
- (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 NO;
    }
     
    // 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 NO;
    }
     
    // 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 NO;
    }
     
    // release vertex and fragment shaders
    if (vertShader) {
        glDeleteShader(vertShader);
    }
    if (fragShader) {
        glDeleteShader(fragShader);
    }
    return YES;
}

- (instancetype)initWithFrame:(NSRect)frameRect
{
    self = [super initWithFrame:frameRect];
     
    const 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 == nil) {
        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.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(void)
{
    gl_Position = inPos;
}

其次是片段着色器:


//
//  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(void)
{
    //gl_FragColor = vec4(0.1, 0.8, 0.5, 1.0);
    myOutput = vec4(0.1, 0.8, 0.5, 1.0);
}

下面给出 AppDelegate 中对 MyGLView 对象的具体调用。

先是 AppDelegate.h 头文件:

@import Cocoa;
 
@class MyGLView;
 
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
    MyGLView *glComputeObj;
}
 
@property (assign) IBOutlet NSWindow *window;
 
@end

其次是 AppDelegate.m 源文件内容:

//
//  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

由于此篇博文写于2012年,因此用了一些老旧的方式,比如XIB这种基于GUI的拖拽方式,而不是纯代码。不过主要逻辑都在 MyGLView.m 源文件中,各位直接参考这里头的代码即可。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

macOS中如何使用OpenGL 3.2 Core Profile 的相关文章

随机推荐

  • 人工智能作业homework2--------A*算法解决八数码

    1 启发式搜索算法A 启发式搜索算法A 一般简称为A算法 是一种典型的启发式搜索算法 其基本思想是 定义一个评价函数f 对当前的搜索状态进行评估 找出一个最有希望的节点来扩展 评价函数的形式如下 f n g n h n 其中n是被评价的节点
  • 全网最详细中英文ChatGPT接口文档(五)30分钟快速入门ChatGPT——手把手示例教程:如何建立一个人工智能回答关于您的网站问题,小白也可学

    30分钟开始使用ChatGPT Models模型 How to build an AI that can answer questions about your website 如何建立一个人工智能 回答有关您的网站的问题 Getting
  • 整理了27个Python人工智能库,建议收藏

    为了大家能够对人工智能常用的 Python 库有一个初步的了解 以选择能够满足自己需求的库进行学习 对目前较为常见的人工智能库进行简要全面的介绍 1 Numpy NumPy Numerical Python 是 Python的一个扩展程序库
  • ssd m.2接口详解

    ssd有两种接口 一种是sata 一种是m 2 这里主要深入讲解一下m 2接口的ssd 1 ssd 尺寸与规格 我们在买ssd的时候 商家都会说什么ssd是2280还是2242规格的 这里的规格实际上就是代表的ssd的大小 M 2模组的尺寸
  • pytrch手写数字识别

    使用Pytorch实现手写数字识别 目标 知道如何使用Pytorch完成神经网络的构建 知道Pytorch中激活函数的使用方法 知道Pytorch中torchvision transforms中常见图形处理函数的使用 知道如何训练模型和如何
  • Unity:利用 射线Ray 检测物体

    利用 射线Ray 检测物体 Unity射线 Ray 是通过发射一条射线来检测碰撞体或触发器 不带碰撞器组件的物体时无法检测的 可以在物理设置里取消检测触发器 Edit Project Setting Physics Physics2D Ph
  • Spring Boot中的Dozer和MapStruct比较

    Spring Boot中的Dozer和MapStruct比较 在Java开发中 数据对象之间的转换是一个常见的任务 Spring Boot作为一个流行的Java框架 提供了多种方式来处理对象之间的转换 两个常用的工具是Dozer和MapSt
  • call、apply、bind方法详解

    1 每个函数都包含两个非继承而来的方法 call 方法和apply 方法 2 相同点 这两个方法的作用是一样的 只是传参方式不一样而已 call 方法使用 window msg 1 document msg 2 var log msg 3
  • springboot 如何修改控制台输出的图案

    如图 操作步骤 1 在项目的resource文件夹下 新建一个文件命名为banner txt 2 进入网站 http patorjk com software taag p display h 0 v 0 f Big t SpringBoo
  • Spring WebSocket通信应用

    文章目录 前言 一 客户端 服务端双向通信交互图 二 项目说明 1 引入包 2 项目各模块说明 问题 参考 前言 本文章主要记录项目客户端 服务端双向通信解决方案 基于Spring WebSocket架构实现双向数据通信 以及项目实际应用中
  • 【SQLAlchemy】第二篇——连接失效及连接池

    一 背景 为了节约资源 MySQL会对建立的连接进行监控 当某些连接处于不活跃状态的时间超过一个阈值时 则关闭它们 用户可以执行show variables like wait timeout 来查看这个阈值 可以看到 在默认的情况下 这个
  • 04-8_Qt 5.9 C++开发指南_QTableWidget的使用

    文章目录 1 QTableWidget概述 2 源码 2 1 可视化UI设计 2 2 程序框架 2 3 qwintspindelegate h 2 4 qwintspindelegate cpp 2 5 mainwindow h 2 6 m
  • VisionWorks快速入门--Graph Mode

    VisionWorks快速入门 Graph Mode 从立即模式过渡到图形模式 1 创建新节点 2 向GraphModestabilizer类添加新字段和函数 3 初始化字段 4 执行算法的迭代 5 Release objects 结果 本
  • 解决科研人痛点的大突破:Zotero 6.0 版有哪些亮点?

    痛点 翻了翻日记 发现我第一次使用 Zotero 文献管理器的时间 是 2008 年 12 月 19 日 这中间曾经因为论文写作需要处理中文文献等原因 若干次切换过其他的文献管理器 包括 NoteExpress 和 Mendeley 等 几
  • IIS站点发布log

    1 启用IIS服务 2 打开IIS管理界面 3 添加站点 4 填写站点信息 1 物理路径为发布的log文件目录 2 填写IP地址和端口 5 发布的log文件设置权限 添加Everyone用户 并设置权限 6 启动站点 浏览器访问 此时出错
  • city_picker改造-------五级城市联动控件

    这几天做项目 需要用到城市控件 网上找了个样式不错的控件 基于bootstrap的 具体用法可以参照https blog csdn net bsw451926392 article details 78886965 但是我这边需要精确到村级
  • vscode的vue中出现很多红色波浪线解决办法

    vscode的vue中出现很多红色波浪线 看上去就很烦 如下所示 这么看呢 代码没什么问题 为什么有那么多红色波浪线呢 其实出现这个的原因是代码和vetur插件的格式不对应 解决办法 1 严格遵循vetur的格式去写 不过麻烦 2 关闭ve
  • 区块链系统面临哪些风险以及有哪些防范措施

    区块链是涉及多方的开放系统 早期的应用又与虚拟加密货币相关 由此使得区块链系统所内含的和面对的风险得以暴露 同时各种安全措施也得以被及时使用和验证 但区块链在真实世界的大规模应用尚未展开 因此区块链所内含以及面临的风险暴露尚不完全 预防措施
  • 【linux服务器编程学习】10.多线程编程

    linux中的线程 线程是linux中完成一个独立任务的完整执行序列 即一个可调度的实体 根据运行环境 可分为内核线程和用户线程 分别由内核和程序线程库调度 关于linux多线程编程 需要掌握怎么创建和结束线程 怎么读取和设置线程属性 线程
  • macOS中如何使用OpenGL 3.2 Core Profile

    从macOS Lion 10 7 开始 Apple支持了对OpenGL 3 2 Core Profile的支持 不过Core Profile与Compatible相比有比较大幅度的改变 从主机端的API到OpenGL接口 再到GLSL Op