OS X下使用OpenGL做离屏渲染

本文为转载内容,原地址

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

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

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

1、创建OpenGL绘制上下文,可使用离屏渲染属性,然后可以设置上其它属性。

2、创建framebuffer object

3、绑定创建好的fbo

4、编译、连接、加载着色器并初始化一些基本的OpenGL的上下文

5、生成纹理,并将它绑定到framebuffer中

6、取消framebuffer的绑定,然后就可以做渲染了。

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

下面将给出具体的代码:

//

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

{   

    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);

}

最后给出OS X的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jpa 循环引用_JPA中按身份引用

jpa 循环引用在上一篇文章中 &#xff0c;我提到我选择通过其主键而不是类型来引用其他聚合。 在处理大型或复杂域模型时&#xff0c;我通常使用这种方法&#xff08;也称为断开域模型&#xff09;。 在本文中&#xff0c;让我尝试进一步解释如何在JPA中完成它。 请注意&#x…

自然辩证法小论文选题_自然辨证法论文题目

与《自然辨证法论文题目》相关的范文2010年研究生课程论文 成绩: 题目:_中西医结合的发展前景_ _ 中西医结合的发展前景 [摘要]立足于中西医结合的现状,从方法论角度,就中西医融合的时间进行了探讨.中西医结合,是在我国既有传统的中医药学,又有现代的西医药学的特定环境和条件下…

Leetcode 14.最长公共前缀

原题链接 解题思路: 1.本题使用模拟法 2.取第一个字符串的首元素&#xff0c;与剩余字符串对应位置相比较&#xff0c;如果全部相等将此字符加入结果中&#xff0c;继续到下一个字符一次比较&#xff0c;直至出现不相同的位置&#xff0c;返回结果。 3.需要注意每个字符串是…

aws lambda_带有API网关的AWS Lambda

aws lambda在上一篇文章中&#xff0c;我向您展示了如何创建和部署AWS Lambda。 我们将继续这项工作&#xff0c;并只考虑更新该lambda的代码。 我们还将使用AWS API Gateway将REST端点添加到AWS Lambda。 因此&#xff0c;在继续之前……&#xff08;如果还没有&#xff09;&…

git pull不同步_git回退版本,再返回最新分支git pull失败的解决经验

本文转载自【微信公众号&#xff1a;羽林君&#xff0c;ID&#xff1a;Conscience_Remains】总述一篇解决gti分支切换问题的文章&#xff0c;大家应该都有过这种情况&#xff0c;就是git最新的代码进行编译的时候&#xff0c;发现最新代码有bug&#xff0c;有些不确认问题点&am…

junit5 动态测试_JUnit 5 –动态测试

junit5 动态测试在定义测试时&#xff0c;JUnit 4有一个很大的弱点&#xff1a;它必须在编译时发生。 现在&#xff0c;JUnit 5将解决此问题&#xff01; Milestone 1 刚刚发布 &#xff0c;它带有全新的动态测试&#xff0c;可以在运行时创建测试。 总览 本系列中有关JUnit 5…

ioc spring 上机案例_通过实例解析Spring Ioc项目实现过程

0. Ioc主要是实现一个控制反转&#xff0c;耦合性大大降低。1. 建maven项目建立一个空的maven项目&#xff0c;然后pom.xml添加spring-context的依赖:org.springframeworkspring-context5.2.7.RELEASE2. 创建pojo java对象package com.aca;public class Hello {private String …

C++ 11 深度学习(十)原始字面量

你是否曾经为了各种json格式无法写入string中而烦恼&#xff0c;为了各种转义而烦恼。如下图 c11为我们带来了全新的解决方法 其新特性为使用. R"(xxxxxxxxxxxx)" ,此种形式可以使得以原有形式进行表现出来

java日期时间转日期_Java时间和日期指南

java日期时间转日期长期以来&#xff0c;正确处理日期&#xff0c;时间&#xff0c;时区&#xff0c;夏令时&#xff0c;and年等一直是我的烦恼。 本文并不是一个全面的指南时域&#xff0c;请参阅日期和时间在Java中 -更详细&#xff0c;但略有下降&#xff0c;ekhem&#xff…

linux过滤端口抓包_Linux抓包工具tcpdump使用总结,WireShark的过滤用法

tcpdump与WireShark是Linux下的两个常用&#xff0c;功能强大的抓包工具&#xff0c;下面列出这两个工具的简单用法。tcpdump用法tcpdump用法&#xff1a;sudo tcpdump -i ens33 src 192.168.0.19 port 80 -xx -Xs 0 -w test.capsudo tcpdump -i ens33 src port 80 -xx -Xs 0 -…

C++ 11 深度学习(十一)final和override

1. final C 中增加了 final 关键字来限制某个类不能被继承&#xff0c;或者某个虚函数不能被重写&#xff0c;和 Jave 的 final 关键字的功能是类似的。如果使用 final 修饰函数&#xff0c;只能修饰虚函数&#xff0c;并且要把final关键字放到类或者函数的后面。 1.1 修饰函数…

交流伺服系统设计指南_交流设计

交流伺服系统设计指南软件设计至关重要。 它是应用程序的基础。 就像蓝图一样&#xff0c;它为所有背景的聚会提供了一个通用平台。 它有助于理解&#xff0c;协作和发展。 设计不应仅视为开发的要素。 它不应该仅仅存在于开发人员的脑海中&#xff0c;否则团队将发现它几乎无…

【前缀和与差分】

前缀和 前缀和的作用&#xff1a;快速计算数组中某一段区间内的总和 1.需要两个额外的数组&#xff0c;来存储原始数据的数组 和 计算过前缀的数组。其原理为前缀和的数组中每个元素用来保存前i个原数组中的和&#xff0c;下一个元素更新就采用s[i] s[i] - 1 a [i] 来持续更…

allergro音乐术语什么意思_rit(这是音乐术语)什么意思?

是渐慢的意思常用的音乐表情术语&#xff1a;速度标记largo——广板lento——慢板adagio——柔板grave——壮板andante——行板andantino——小行板moderato——中板allegretto——小快板allegro——快板vivo——快速有生气vivace——快速有生气presto——急板常用的音乐表情术…

英文连词_连词我们…讨厌

英文连词最近&#xff0c;我写了与实现相关的名称&#xff0c;并提供了一些示例&#xff0c;这些示例由于方法名称与主体之间的紧密关系而导致方法名称不正确。 有一会儿&#xff0c;我们有以下代码&#xff1a; boolean isComplexOrUnreadableWithTests() { return (complex…

Ubuntu系统手动安装英伟达驱动程序

屏蔽开源驱动nouveau 安装过程会询问是否屏蔽&#xff0c;手动屏蔽也有多种操作方式&#xff0c; sudo gedit /etc/modprobe.d/blacklist.conf 加参数到最底下回车另起一行内容为 blacklist nouveau options nouveau modeset0 保存再终端更新内核命令 sudo update-initr…

workbench拓扑优化教程_workbenchds拓扑优化分析.ppt

workbenchds拓扑优化分析形状优化基础 指定Shape Optimization 将执行形状或拓扑优化 Shape Optimization是一个优化问题,其结构能量在减少结构体积的基础上的最小化 另一种观点就是Shape Optimization尽量得到关于体积比率的最好刚度. Shape Optimization尽可能的找寻可以在对…

maven 父maven_Maven神秘化

maven 父maven由于我的Android开发的背景下&#xff0c;我比较习惯到Gradle &#xff0c;而不是Maven的 。 尽管我知道Gradle基于Maven&#xff0c;但我从未调查过幕后发生的事情。 在过去的一周中&#xff0c;我一直在尝试了解细节并找出Maven的不同组成部分。 什么是Maven M…

【WebRTC---序篇】(一)为什么要使用WebRTC

1.1.1自研直播客户端架构 一个最简单的直播客户端至少应该包括音视频采集模块,音视频编码模块,网络传输模块,音视频解码模块和音视频渲染模块五大部分。如下图所示 1.1.2拆分音视频模块 在实际开发中,音频和视频处理完全是独立的。如下图所示,经过细分后,音频采集与视频…