OpenGL v1.1:离屏渲染或直接渲染到位图

时间:2011-02-18 00:59:45

标签: c# opengl bitmap rendering remote-desktop

我正在使用带有C#的OpenGL,为我们的项目使用CSGL12接口。我试图在内存中的位图上绘制一些4点自由变换图像。

有没有办法:

  1. 直接渲染到内存上的位图,或
  2. 渲染到屏幕外实例,然后将其转换为位图?我需要知道如何设置屏幕外实例以及转换。
  3. 任何一种方法都必须适用于远程桌面,虚拟机和Panasonic CF-19 Toughbook(即OpenGL v1.1)。如果可能的话,提供与之相关的示例代码将会有很大帮助。

2 个答案:

答案 0 :(得分:2)

你知道,OpenGL-1.1现在已经过时了。即使市场上最疯狂的GPU也可以立即使用OpenGL-1.4。首先应该知道的一点是,OpenGL设计用于在屏幕上获取图片,尽管输出后端的性质在规范中是抽象的。如果您想使用OpenGL来渲染加速的3D内容,那么不会渲染到位图。这将使您回到软件光栅化模式,非常慢因此使用PBuffer或Framebuffer对象。 Framebuffer对象很难使用。但PBuffers有点棘手。

在Windows中,您总是需要先绕过创建一个带有一些OpenGL上下文的虚拟窗口,以便您可以请求和使用OpenGL扩展。使用X11 / GLX可以创建没有该虚拟窗口的PBuffer。然而,PBuffer的常用用途是创建动态纹理内容的地方。

以下是我很久以前编写的一些代码,它默默地假设现有的,有效初始化的OpenGL上下文在当前线程上处于活动状态,并将配置PBuffer上下文以与原始上下文共享其OpenGL对象。它还取决于库 GLEW

pbuffer.h

#ifndef PBUFFER_H
#define PBUFFER_H

#ifdef WIN32
#include <GL/wglew.h>
#endif

#ifdef GLX
#ifdef NOGLEW
#include <GL/glx.h>
#else
#include <GL/glxew.h>
#endif
#endif

class PBuffer
{
public:
    PBuffer(int width, int height);
    virtual ~PBuffer();

    void Use();
    void Release();

    int const get_width() const { return width; }
    int const get_height() const { return height; }

private:
    void Create();
    void Destroy();

protected:
    int width;
    int height;

    bool initialized;

#ifdef WIN32
    HPBUFFERARB hPB;
    HGLRC       hPBRC;
    HDC     hPBDC;

    HDC     hGLDC;
    HGLRC       hGLRC;
#endif

#ifdef GLX
    Display     *dpy;
    int     scrnum;
    GLXContext  PBRC;
    GLXPbuffer  PBDC;

    GLXContext  FBRC;
    GLXDrawable FBDC;
#endif
};

#endif/*PBUFFER_H*/

pbuffer.cpp

#include <stdexcept>
#include <GL/glew.h>
#include "pbuffer.h"

using namespace std;

#ifdef WIN32

PBuffer::PBuffer(int width, int height)
{
    initialized=false;

    this->width=width;
    this->height=height;

    hGLDC = wglGetCurrentDC();
    hGLRC = wglGetCurrentContext();

    Create();
}

PBuffer::~PBuffer()
{
    Destroy();
}

void PBuffer::Use()
{
    // make sure the pbuffer has been initialized
    if (!initialized)
    {
        throw runtime_error("pbuffer is not initialized");
    }
    // make sure we haven't lost our pbuffer due to a display mode change

    int flag = 0;
    wglQueryPbufferARB(hPB, WGL_PBUFFER_LOST_ARB, &flag);
    if (flag)
    {
        throw runtime_error("pbuffer became invalid");
    }

    wglMakeCurrent(hPBDC, hPBRC);

    glViewport(0, 0, width, height);

    glDrawBuffer(GL_FRONT);
        glReadBuffer(GL_FRONT);
}

void PBuffer::Release()
{
    // make sure the pbuffer has been initialized
    if ( !initialized )
    {
        throw runtime_error("pbuffer is not initialized");
    }
    // make sure we haven't lost our pbuffer due to a display mode change
    int flag = 0;
    wglQueryPbufferARB(hPB, WGL_PBUFFER_LOST_ARB, &flag);
    if (flag)
    {
        throw runtime_error("pbuffer became invalid");
    }

    wglMakeCurrent(hGLDC, hGLRC);
}

void PBuffer::Create()
{
    if(initialized)
    {
        Destroy();
    }

    if (hGLDC == NULL)
    {
        throw runtime_error("unable to get device context");
    }
    if (hGLRC == NULL)
    {
        throw runtime_error("unable to get render context");
    }
    // define the minimum pixel format requirements we will need for our pbuffer
    // a pbuffer is just like a frame buffer, it can have a depth buffer associated
    // with it and it can be double buffered.
    int attr[] =
    {
        WGL_SUPPORT_OPENGL_ARB, TRUE, // pbuffer will be used with gl
        WGL_DRAW_TO_PBUFFER_ARB, TRUE, // enable render to pbuffer
        WGL_RED_BITS_ARB, 16, // at least 8 bits for RED channel
        WGL_GREEN_BITS_ARB, 16, // at least 8 bits for GREEN channel
        WGL_BLUE_BITS_ARB, 16, // at least 8 bits for BLUE channel
        WGL_ALPHA_BITS_ARB, 16, // at least 8 bits for ALPHA channel
        WGL_DEPTH_BITS_ARB, 24, // at least 24 bits for depth buffer
        WGL_DOUBLE_BUFFER_ARB, FALSE, // we dont require double buffering
        0 // zero terminates the list
    };

    // choose a pixel format that meets our minimum requirements
    unsigned int count = 0;
    int pixelFormat;
    wglChoosePixelFormatARB(hGLDC,(const int*)attr, NULL, 1,&pixelFormat,&count);
    if(count == 0)
    {
        throw runtime_error("no matching pbuffer pixel format found");
    }

    int attribs[]={0,0};

    // allocate the pbuffer
    hPB = wglCreatePbufferARB(hGLDC, pixelFormat, width, height, attribs);
    hPBDC = wglGetPbufferDCARB(hPB);
    hPBRC = wglCreateContext(hPBDC);

    wglShareLists(hGLRC, hPBRC);

    initialized=true;
}

void PBuffer::Destroy()
{
    // make sure the pbuffer has been initialized
    if ( !initialized )
    {
        throw runtime_error("pbuffer is not initialized");
    }

    Release();

    wglDeleteContext(hPBRC);
    wglReleasePbufferDCARB(hPB, hPBDC);
    wglDestroyPbufferARB(hPB);

    initialized = false;
}
#endif

#ifdef GLX
PBuffer::PBuffer(int width, int height)
{
    initialized=false;

    this->width=width;
        this->height=height;

    dpy = glXGetCurrentDisplay();
    scrnum = DefaultScreen( dpy );
    FBRC = glXGetCurrentContext();
    FBDC = glXGetCurrentDrawable();

    Create();
}

PBuffer::~PBuffer()
{
    Destroy();
}

void PBuffer::Use()
{
    // make sure the pbuffer has been initialized
    if (!initialized)
    {
        throw runtime_error("pbuffer is not initialized");
    }
    // make sure we haven't lost our pbuffer due to a display mode change

    // resize view port. generally you'll want to set this to the
    // size of your pbuffer so that you render to the entire pbuffer
    // but there are cases where you might want to render to just a
    // sub-region of the pbuffer.
    glXMakeContextCurrent(dpy, PBDC, PBDC, PBRC);

    glViewport(0, 0, width, height);

    glDrawBuffer(GL_FRONT);
    glReadBuffer(GL_FRONT);
}

void PBuffer::Release()
{
    // make sure the pbuffer has been initialized
    if ( !initialized )
    {
        throw runtime_error("pbuffer is not initialized");
    }
    // make sure we haven't lost our pbuffer due to a display mode change

    glXMakeContextCurrent(dpy, FBDC, FBDC, FBRC);
}

void PBuffer::Create()
{
    if(initialized)
    {
        Destroy();
    }

    if (dpy == NULL)
    {
        throw runtime_error("unable to get device context");
    }
    if (!FBDC)
    {
        throw runtime_error("unable to get render context");
    }
    // define the minimum pixel format requirements we will need for our pbuffer
    // a pbuffer is just like a frame buffer, it can have a depth buffer associated
    // with it and it can be double buffered.
    /*int attr[] =
    {
        GLX_RENDER_TYPE, GLX_RGBA_BIT,
        GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
        GLX_DOUBLEBUFFER, False,
        GLX_RED_SIZE, 1,
        GLX_GREEN_SIZE, 1,
        GLX_BLUE_SIZE, 1,
        GLX_ALPHA_SIZE, 1,
        GLX_DEPTH_SIZE, 1,
        0 // zero terminates the list
    };*/

    int attrib[] =
    {
        GLX_DOUBLEBUFFER,  False,
        GLX_RED_SIZE,      8,
        GLX_GREEN_SIZE,    8,
        GLX_BLUE_SIZE,     8,
        GLX_ALPHA_SIZE,    8,
        GLX_STENCIL_SIZE,  1,
        GLX_DEPTH_SIZE,    24,
        GLX_RENDER_TYPE,   GLX_RGBA_BIT,
        GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
        None
    };

    int PBattrib[] =
    {
        GLX_PBUFFER_WIDTH,   width,
        GLX_PBUFFER_HEIGHT,  height,
        GLX_LARGEST_PBUFFER, False,
    None
    };

    // choose a pixel format that meets our minimum requirements
    int count = 0;
    //GLXFBConfigSGIX *config=
    //  glXChooseFBConfigSGIX(dpy, scrnum, attrib, &count);

    GLXFBConfig *config=
        glXChooseFBConfig(dpy, scrnum, attrib, &count);

    if(config == NULL || count == 0)
    {
        throw runtime_error("no matching pbuffer pixel format found");
    }

    // allocate the pbuffer
    //PBDC=glXCreateGLXPbufferSGIX(dpy, config[0], width, height, PBattrib);
    //PBRC=glXCreateContextWithConfigSGIX(dpy, config[0], GLX_RGBA_TYPE_SGIX, FBRC, true);

    PBDC=glXCreatePbuffer(dpy, config[0], PBattrib);
    PBRC=glXCreateNewContext(dpy, config[0], GLX_RGBA_TYPE, FBRC, true);

    XFree(config);

    initialized=true;
}

void PBuffer::Destroy()
{
    // make sure the pbuffer has been initialized
    if ( !initialized )
    {
        throw runtime_error("pbuffer is not initialized");
    }

    Release();

    glXDestroyContext(dpy, PBRC);
    glXDestroyPbuffer(dpy, PBDC);

    initialized = false;
}

#endif

答案 1 :(得分:0)

您可以使用Bitmap.LockBitsglCopyPixels从缓冲区(opengl调用屏幕外缓冲区“aux”)拉入位图。

相关问题