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

发布于 2024-10-18 11:39:06 字数 384 浏览 12 评论 0原文

我将 OpenGL 与 C# 结合使用,为我们的项目使用 CSGL12 接口。我正在尝试将许多 4 点自由变换图像绘制到内存中的位图上。

有没有办法:

  1. 直接渲染到内存上的位图,或者
  2. 渲染到离屏实例,然后将其转换为位图?我需要知道如何设置离屏实例以及转换。

任一方法都必须在远程桌面、虚拟机和 Panasonic CF-19 Toughbook(即 OpenGL v1.1)上运行。如果可能的话,提供与之相关的示例代码将会有很大帮助。

I'm using OpenGL with C#, using CSGL12 interface for our project. I'm attempting to draw a number of 4-point free-transformed images onto a bitmap in memory.

Is there a way to either:

  1. Directly render to a bitmap on memory, or,
  2. Render to an off-screen instance, and then convert this to a bitmap? I need to know how to setup an off-screen instance as well as the conversion.

Either method must work on a Remote Desktop, a Virtual Machine, and on a Panasonic CF-19 Toughbook (i.e. OpenGL v1.1). If possible, providing an example code related to it will help tremendously.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜嗑 2024-10-25 11:39:06

要知道,OpenGL-1.1如今确实已经过时了。即使是市场上最蹩脚的 GPU 现在也可以执行 OpenGL-1.4。您首先应该知道的一件事是,OpenGL 被设计用于在屏幕上显示图片,尽管输出后端的性质在规范中保持抽象。如果您想使用 OpenGL 来加速渲染 3D 内容,那么不要渲染为位图。这总是会让您回到软件光栅化模式,该模式非常慢,因此请使用 PBuffer 或 Framebuffer 对象。帧缓冲区对象使用起来很简单。但 PBuffer 有点棘手。

在 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

You know, OpenGL-1.1 is really outdated nowadays. Even the crappiest GPUs on the market can do OpenGL-1.4 now. One thing you should know first is, that OpenGL has been designed for getting pictures on the screen, although the nature of the output backend is keept abstract in the specification. If you want to use OpenGL to render 3D stuff accelerated, then don't render to bitmaps. This will always fall you back into software rasterization mode, which is extremely slow So use a PBuffer or a Framebuffer Object. Framebuffer Objects are straigtforward to use. But PBuffers are a little bit tricky.

In Windows you always need to take a detour over creating a dummy window with some OpenGL context first, so that you can request and use OpenGL extensions. Using X11/GLX one can create a PBuffer without that dummy window. However the usual use for a PBuffer used to be a place where contents for dynamic textures were created.

The following is some code I wrote ages ago, and it silently assumes an existing, validly initialized OpenGL context to be active on the current thread, and will configure the PBuffer context to share its OpenGL objects with the original context. Also it depends on the library 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
国际总奸 2024-10-25 11:39:06

您可以使用 Bitmap.LockBits 和 glCopyPixels 从缓冲区(opengl 调用离屏缓冲区“aux”)中提取位图。

You can pull from a buffer (opengl calls off-screen buffers "aux") into a bitmap using Bitmap.LockBits and glCopyPixels.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文