macOS下使用OpenGL做离屏渲染

这篇具有很好参考价值的文章主要介绍了macOS下使用OpenGL做离屏渲染。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

有时,我们想通过GPU做一些视频、图像处理,而处理的结果不需要显示在显示器上,而是直接交给主存,这时候我们可以通过OpenGL的 离屏渲染Offscreen Rendering)来实现。

由于我们不需要将渲染好的像素显示到屏幕上,因此我们可以使用framebuffer object,将像素放到 fbo 上,然后通过 glReadPixels 来获取最终渲染好的像素。

在macOS Lion中做离屏渲染非常简单,基本步骤如下:

  1. 创建OpenGL绘制上下文,可使用离屏渲染属性,然后可以设置上其它属性。
  2. 创建 framebuffer object
  3. 绑定创建好的 fbo
  4. 编译、连接、加载着色器并初始化一些基本的OpenGL的上下文
  5. 生成纹理,并将它绑定到framebuffer中
  6. 取消 framebuffer 的绑定,然后就可以做渲染了。

在使用glDrawArrays等绘制接口之后,可以调用glFlush来确保像素都已经到了指定的 framebuffer,然后通过调用 glReadPixels 将当前 framebuffer 中的像素读取出来。

下面将给出具体的代码:

//
//  MyGLView.h
//  OpenGLShaderBasic
//
//  Created by Zenny Chen on 10/4/10.
//  Copyright 2010 GreenGames Studio. All rights reserved.
//
 
#import <Cocoa/Cocoa.h>
 
@class NSOpenGLContext;
 
@interface MyGLView : NSObject
{
    GLuint program;
    GLuint framebufferID;
    GLuint texName;
     
    NSOpenGLContext *glContext;
}
 
- (void)prepareOpenGL;
- (void)compute;
 
@end
这里尽管给出的Objective-C类叫MyGLView,但它其实不是一个UIView的子类。由于我们不需要将结果显示到屏幕上,因此这里也就不需要用UIView作为父类。

//
//  MyGLView.m
//  OpenGLShaderBasic
//
//  Created by Zenny Chen on 10/4/10.
//  Copyright 2010 GreenGames Studio. All rights reserved.
//
 
#import "MyGLView.h"
#include <OpenGL/gl.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/CGLRenderers.h>
 
#define MY_PIXEL_WIDTH      128
#define MY_PIXEL_HEIGHT     128
 
@implementation MyGLView
 
// uniform index
enum
{
    UNIFORM_SAMPLER,
     
    NUM_UNIFORMS
};
static GLint uniforms[NUM_UNIFORMS];
 
// attribute index
enum {
    ATTRIB_VERTEX,
    ATTRIB_TEXCOORD,
     
    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();
     
    // 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);
     
    // bind attribute locations
    // this needs to be done prior to linking
    glBindAttribLocation(program, ATTRIB_VERTEX, "position");
    glBindAttribLocation(program, ATTRIB_TEXCOORD, "texCoords");
    //glBindFragDataLocationEXT(program, 0, "myFragColor");
     
    // link program
    if (![self linkProgram:program])
    {
        NSLog(@"Failed to link program: %d", program);
        return FALSE;
    }
     
    // get uniform locations
    uniforms[UNIFORM_SAMPLER] = glGetUniformLocation(program, "sampler");
     
    // release vertex and fragment shaders
    if (vertShader)
        glDeleteShader(vertShader);
    if (fragShader)
        glDeleteShader(fragShader);
     
    return TRUE;
}
 
- (void)dealloc
{
    if(texName != 0)
        glDeleteTextures(1, &texName);
     
    if(framebufferID != 0)
        glDeleteFramebuffers(1, &framebufferID);
     
    if(glContext != nil)
    {
        [glContext release];
        glContext = nil;
    }
     
    [super dealloc];
}
 
static GLfloat __attribute__((aligned(16))) my_buffer[MY_PIXEL_WIDTH * MY_PIXEL_HEIGHT * 4];
static GLfloat __attribute__((aligned(16))) checkImage[MY_PIXEL_WIDTH * MY_PIXEL_HEIGHT * 4];
 
static void initCheckImage(void)
{
    for(int row = 0; row < MY_PIXEL_HEIGHT; row++)
    {        
        for(int col = 0; col < MY_PIXEL_WIDTH; col++)
        {
            checkImage[row * MY_PIXEL_WIDTH * 4 + col * 4 + 0] = 0.1f;
            checkImage[row * MY_PIXEL_WIDTH * 4 + col * 4 + 1] = 0.2f;
            checkImage[row * MY_PIXEL_WIDTH * 4 + col * 4 + 2] = 0.3f;
            checkImage[row * MY_PIXEL_WIDTH * 4 + col * 4 + 3] = 0.4f;
        }
    }
}
 
- (void)prepareOpenGL
{
    if(glContext != nil)
        return;
     
#if 0
    CGLPixelFormatObj pixObj = NULL;
    GLint nPix = 0;
    CGLChoosePixelFormat((const CGLPixelFormatAttribute[]){kCGLPFAOpenGLProfile, kCGLOGLPVersion_3_2_Core, 0}, &pixObj, &nPix);
    NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithCGLPixelFormatObj:pixObj];
    CGLReleasePixelFormat(pixObj);
     
#else
     
    // 创建pixel format,设置离屏渲染
    NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:(const NSOpenGLPixelFormatAttribute[]){NSOpenGLPFAAllRenderers, NSOpenGLPFAOffScreen, NSOpenGLPFAAllowOfflineRenderers, 0}];
#endif
     
    // 创建OpenGL上下文
    glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
    [pixelFormat release];<br>
    // 将此上下文作为当前上下文
    [glContext makeCurrentContext];
     
    if(![self loadShaders])
        return;
     
    glGenFramebuffers(1, &framebufferID);
    glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
     
    glViewport(0, 0, MY_PIXEL_WIDTH, MY_PIXEL_HEIGHT);
    glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
     
    // Use shader program
    glUseProgram(program);
     
    // Drawing code here.
    static const GLfloat squareVertices[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        -1.0f,  1.0f, 0.0f,
        1.0f,  1.0f, 0.0f
    };
     
    static const GLfloat texCoords[] = {
        0.0f, 0.0f,     // left lower
        1.0f, 0.0f,     // right lower
        0.0f, 1.0f,     // left upper
        1.0f, 1.0f      // right upper
    };
     
    glEnable(GL_CULL_FACE);
     
    // 初始化纹理数据
    initCheckImage();
     
    glClampColorARB(GL_RGBA_FLOAT_MODE_ARB, GL_TRUE);
    glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
    glClampColorARB(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
     
    // 初始化纹理
    glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
     
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MY_PIXEL_WIDTH, MY_PIXEL_HEIGHT, 0, GL_RGBA, GL_FLOAT, checkImage);
     
    // 将纹理绑定到帧缓存
    glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texName, 0);
 
    glUniform1i(uniforms[UNIFORM_SAMPLER], 0);      // Set the sampler value
     
    // Update attribute values
    glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, 0, 0, texCoords);
    glEnableVertexAttribArray(ATTRIB_TEXCOORD);
}
 
- (void)compute
{
    glClear(GL_COLOR_BUFFER_BIT);
     
    // Draw
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
     
    glFlush();
     
    glReadPixels(0, 0, MY_PIXEL_WIDTH, MY_PIXEL_HEIGHT, GL_RGBA, GL_FLOAT, my_buffer);
    NSLog(@"R:%f, G:%f, B:%f, A:%f", my_buffer[0], my_buffer[1], my_buffer[2], my_buffer[3]);
}
 
@end

下面给出Vertex shader和Fragment shader,这两个Shader的代码很简单:

//
//  Shader.vsh
//  GLSLTest
//
//  Created by Zenny Chen on 4/11/10.
//  Copyright GreenGames Studio 2010. All rights reserved.
//
 
#version 120
 
#extension GL_EXT_gpu_shader4 : enable
 
attribute vec4 position;
attribute vec4 texCoords;
 
uniform mat4 translate;
uniform mat4 projection;
 
void main(void)
{    
    gl_Position = position;
    gl_TexCoord[0] = texCoords;
}
//
//  Shader.fsh
//  GLSLTest
//
//  Created by Zenny Chen on 4/11/10.
//  Copyright GreenGames Studio 2010. All rights reserved.
//
 
#version 120
 
uniform sampler2D sampler;
 
void main()
{
    // gl_FragColor
    gl_FragColor = texture2D(sampler, gl_TexCoord[0].st) + vec4(0.4, 0.3, 0.2, 1.1);
}

最后给出macOS Cocoa Framework上的AppDelegate中的实现。各位可以拿这代码自己尝试一下,看看输出结果~

//
//  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, 100.0f, 30.0f)];
    [button setButtonType:NSMomentaryPushInButton];
    [button setBezelStyle:NSRoundedBezelStyle];
    [button setTitle:@"Compute"];
    [button setTarget:self];
    [button setAction:@selector(computeButtonTouched:)];
    [baseView addSubview:button];
    [button release];
}
 
- (void)computeButtonTouched:(id)sender
{
    if(glComputeObj == nil)
    {
        glComputeObj = [[MyGLView alloc] init];
        [glComputeObj prepareOpenGL];
    }
    [glComputeObj compute];
}
 
@end

上述代码基于OpenGL 2.1,用的也是非常古老的GLSL1.2版本的语法。文章来源地址https://www.toymoban.com/news/detail-438540.html

到了这里,关于macOS下使用OpenGL做离屏渲染的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • iOS知识点 ---- 离屏渲染

    iOS 中的离屏渲染(Off-Screen Rendering)是指在绘制某些复杂图形或特殊效果时,系统无法直接在当前屏幕缓冲区进行绘制,而是需要先在额外的离屏缓冲区(Off-Screen Buffer)中完成渲染工作,然后再将结果混合到屏幕缓冲区的过程。离屏渲染往往发生在需要进行特定图形操作(

    2024年04月16日
    浏览(43)
  • libVLC 提取视频帧使用OpenGL渲染

    在上一节中,我们讲解了如何使用QWidget渲染每一帧视频数据。 由于我们不停的生成的是QImage对象,因此对 CPU 负荷较高。其实在绘制这块我们可以使用 OpenGL去绘制,利用 GPU 减轻 CPU 计算负荷,本节讲解使用OpenGL来绘制每一帧视频数据。 libVLC 提取视频帧使用QWidget渲染-CSDN博

    2024年04月10日
    浏览(36)
  • 使用OpenGL 和 opengl ES 渲染YUV图片文件的QT示例

    头文件:CPlayWidget.h cpp文件:CPlayWidget.cpp 默认打开 ./test.yuv文件 头文件:CPlayWidget.h  与上面没有差别 cpp文件:只替换了着色器代码:

    2024年01月20日
    浏览(33)
  • 使用Python和OpenGL渲染PS2存档3D图标

    经过前面一系列文章的铺垫,PS2存档3D图标的文件已经全部解析完毕。本篇开始将介绍使用如下工具将3D图标渲染出来,并尽可能接近PS2主机原生的效果。 Python3 PyGame Numpy ModernGL PyGLM 第一步先初始化 PyGame ,设置窗口大小为 640x480 , FPS 为 60 。开启 OpenGL 渲染模式, OpenGL 的版

    2024年02月03日
    浏览(32)
  • 使用 .NET 8.0 和 OpenGL 创建一个简易的渲染器

    前言 我个人对三维渲染领域的开发有着浓厚的兴趣,尽管并未在相关行业工作过,我的了解还很片面。去年,在与群友聊天时,他们推荐了一本《Unity Shader入门精要》,说适合像我这样想自学的新人,于是我打开了通往新世界的大门。这本书涵盖了很多基础的渲染知识,如光

    2024年02月19日
    浏览(30)
  • ffmpeg cuda硬件解码后处理使用opengl渲染,全硬件流程

    使用硬件解码后不要transfer到内存,使用cuda转化nv12 - bgr24 转化完毕后cuda里面存了一份bgr24 如果需要opencv gpumat直接使用cuda内存,则可以手动构造gpumat 可以使用gpumat的各种函数 ptr(0)、ptr(1)和ptr(2)分别获取了R、G、B三个通道的数据指针。 使用reinterpret_cast将uchar 指针转换为ucha

    2024年04月12日
    浏览(37)
  • 【NET 7.0、OpenGL ES】使用Silk.NET渲染MMD,并实时进行物理模拟。

    有关mmd播放器,网上也有许多非常漂亮的实现,如 pmxeditor、saba、blender_mmd_tools等等。。 首先我想先介绍下我参考实现的仓库: sselecirPyM/Coocoo3D: Experimental MMD renderer using DX12 and DXR. (github.com),这是sselecirPyM大神使用NET 6.0和DX12实现的mmd渲染器,支持自定义渲染管线、光照等,感

    2024年02月08日
    浏览(30)
  • 图片链接或pdf链接通过浏览器打开时,有时可以直接预览,有时却是下载,为什么?

    在前端开发中,有时候需要对一些文件链接进行特殊处理,比如对于一些图片链接或者PDF链接,有时我们需要通过浏览器打开进行预览,有时又不希望通过浏览器进行打开,而是希望能够直接下载到本地。但现实效果却往往跟我们相反,我们希望浏览器打开时,他却直接下载

    2024年02月10日
    浏览(47)
  • 【OpenGL】读取视频并渲染

    😏 ★,° :.☆( ̄▽ ̄)/$: .°★ 😏 这篇文章主要介绍opencv读取视频并在opengl渲染增加3D图形。 学其所用,用其所学。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更新不迷路🥞 编译: g++ -o video_rendering main.cpp -lglut -lGL -lGLU pkg-config -

    2024年02月12日
    浏览(37)
  • 4.OpenGL学习笔记——渲染到纹理

    写作之处的初衷是作为learnopengl的解释文档,或者代码库来用,不过我慢慢发现这样做挺没意思的,因为learnopengl已经足够详细了,并且随着逐代的更新,我们这个代码库可能还会过时,因此我想还是把一些重要的概念加以巩固,突出,来形成我们自己的特色。 (实际上你看

    2023年04月08日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包