我可以使用 OpenGL 进行离屏渲染吗? [英] Can I use OpenGL for off-screen rendering?

查看:31
本文介绍了我可以使用 OpenGL 进行离屏渲染吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想尝试制作一个简单的程序,该程序采用 3D 模型并将其渲染为图像.有什么方法可以使用 OpenGL 渲染图像并将其放入保存图像而不是显示图像的变量中吗?我不想看到我正在渲染的内容,我只想保存它.有没有办法用 OpenGL 做到这一点?

I want to try to make a simple program that takes a 3D model and renders it into an image. Is there any way I can use OpenGL to render an image and put it into a variable that holds an image rather than displaying an image? I don't want to see what I'm rendering I just want to save it. Is there any way to do this with OpenGL?

推荐答案

我假设您知道如何使用 OpenGL 将内容绘制到屏幕上,并且您编写了一个诸如 drawStuff 之类的函数来这样做.

I'm assuming that you know how to draw stuff to the screen with OpenGL, and you wrote a function such as drawStuff to do so.

首先,您必须决定最终渲染的大小;我在这里选择一个正方形,大小为 512x512.您还可以使用不是 2 的幂的大小,但为了简单起见,让我们暂时坚持这种格式.有时 OpenGL 对这个问题很挑剔.

First of all you have to decide how big you want your final render to be; I'm choosing a square here, with size 512x512. You can also use sizes that are not power of two, but to keep things simple let's stick to this format for now. Sometimes OpenGL gets picky about this issue.

const int width = 512;
const int height = 512;

那么你需要三个对象来创建一个离屏绘图区;正如 user1118321 所说,这被称为帧缓冲对象.

Then you need three objects in order to create an offscreen drawing area; this is called a frame buffer object as user1118321 said.

GLuint color;
GLuint depth;
GLuint fbo;

FBO 存储了一个颜色缓冲区和一个深度缓冲区;您的屏幕渲染区域也有这两个缓冲区,但您不想使用它们,因为您不想绘制到屏幕上.要创建 FBO,您只需要在启动时一次执行以下操作:

The FBO stores a color buffer and a depth buffer; also you screen rendering area has these two buffers, but you don't want to use them because you don't want to draw to the screen. To create the FBO, you need to do something like the following only one time for instance at startup:

glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);

glGenRenderbuffers(1, &depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

首先创建一个内存区域来存储像素颜色,而不是一个存储像素深度(在计算机图形学中用于删除隐藏的表面),最后将它们连接到 FBO,它基本上保存了对两者的引用.以第一个块为例,有 6 个调用:

First you create a memory area to store pixel color, than one to store pixel depth (which in computer graphics is used to remove hidden surfaces), and finally you connect them to the FBO, which basically holds a reference to both. Consider as an example the first block, with 6 calls:

  • glGenTextures 创建纹理名称;OpenGL 中的名称只是一个整数,因为字符串效率太低.
  • glBindTexture 将纹理绑定到一个目标,即GL_TEXTURE_2D;指定相同目标的后续调用将对该纹理进行操作.
  • 第 3 次、第 4 次和第 5 次调用特定于被操作的目标,您应该参阅 OpenGL 文档以了解更多信息.
  • 最后一次调用 glBindTexture 解除纹理与目标的绑定.由于在某些时候您将控制权交给 drawStuff 函数,这反过来又会进行大量 OpenGL 调用,因此您现在需要清除工作区,以避免干扰您创建的对象.
  • glGenTextures creates a name for a texture; a name in OpenGL is simply an integer, because a string would be too inefficient.
  • glBindTexture binds the texture to a target, namely GL_TEXTURE_2D; subsequent calls that specify that same target will operate on that texture.
  • The 3rd, 4th and 5th call are specific to the target being manipulated, and you should refer to the OpenGL documentation for further information.
  • The last call to glBindTexture unbinds the texture from the target. Since at some point you will hand control to your drawStuff function, which in turn will make its whole lot of OpenGL calls, you need to clear you workspace now, to avoid interference with the object that you have created.

要从屏幕渲染切换到离屏渲染,您可以在程序中的某处使用布尔变量:

To switch from screen rendering to offscreen rendering you could use a boolean variable somewhere in your program:

if (offscreen)
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
else
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

drawStuff();

if (offscreen)
    saveToFile();

因此,如果 offscreentrue,您实际上希望 drawStuff 干扰 fbo,因为您想要它在其上渲染场景.

So, if offscreen is true you actually want drawStuff to interfere with fbo, because you want it to render the scene on it.

函数 saveToFile 负责加载渲染结果并转换成文件.这在很大程度上取决于您使用的操作系统和语言.例如,在带有 C 的 Mac OS X 上,它将类似于以下内容:

Function saveToFile is responsible for loading the result of the rendering and converting it to file. This is heavily dependent on the OS and language that you are using. As an example, on Mac OS X with C it would be something like the following:

void saveImage()
{
    void *imageData = malloc(width * height * 4);

    glBindTexture(GL_TEXTURE_2D, color);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);

    CGContextRef contextRef = CGBitmapContextCreate(imageData, width, height, 8, 4 * width, CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), kCGImageAlphaPremultipliedLast);
    CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
    CFURLRef urlRef = (CFURLRef)[NSURL fileURLWithPath:@"/Users/JohnDoe/Documents/Output.png"];
    CGImageDestinationRef destRef = CGImageDestinationCreateWithURL(urlRef, kUTTypePNG, 1, NULL);
    CGImageDestinationAddImage(destRef, imageRef, nil);        
    CFRelease(destRef);

    glBindTexture(GL_TEXTURE_2D, 0);

    free(imageData);
}

这篇关于我可以使用 OpenGL 进行离屏渲染吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆