【问题标题】:OpenGL drawing to an existing HDC using Texture2DOpenGL 使用 Texture2D 绘制到现有 HDC
【发布时间】:2016-10-25 19:33:15
【问题描述】:

我正在尝试使用 OpenGL 渲染到使用 Windows API 创建的窗口的现有渲染区域。我得到 HDC 并使用 wglCreateContext 和 wglMakeCurrent 创建一个 opengl 上下文。然后我创建一个纹理并绑定它。尽管我可以将缓冲区清除为我选择的任何颜色,但我无法对其进行渲染。下面的代码示例应该清楚我的问题是什么。

void draw(HDC dhdc){


static unsigned char render_on_device_image_once, odd;
static GLuint texture_id;
size_t sz;

odd = (odd + 1) % 2;
if(!render_on_device_image_once){
        // DO ONCE
    render_on_device_image_once = 1;


    GLubyte pixels[] =
    {
        0, 0, 0, 255, 255, 255,
        255, 255, 255, 0, 0, 0,
    };
    glGenTextures(1, &texture_id);
    glBindTexture(GL_TEXTURE_2D, texture_id);
    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);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);


}

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(odd)
    glClearColor(0.0, 0.0, 0.5, 1.0);
else
    glClearColor(0.5, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTranslatef(0, 0, -5);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_id);

glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(0.0, 1.0, 0.0);
glEnd();

glDisable(GL_TEXTURE_2D);

SwapBuffers(dhdc);}

上面的代码,我从this answer 获取(并稍作修改)使窗口区域在红色和蓝色之间变化,但不渲染四边形。有没有人遇到过类似的问题或者可以发现我的错误?

谢谢。

编辑:

为了添加更多信息,我将 HDC 的像素格式设置为:

  static PIXELFORMATDESCRIPTOR window_pixel_format_desc =
{
    sizeof(PIXELFORMATDESCRIPTOR),
    1,
    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,    //Flags
    PFD_TYPE_RGBA,            //The kind of framebuffer. RGBA or palette.
    8,                        //Colordepth of the framebuffer.
    0, 0, 0, 0, 0, 0,
    0,
    0,
    0,
    0, 0, 0, 0,
    32,                        //Number of bits for the depthbuffer
    0,                        //Number of bits for the stencilbuffer
    0,                        //Number of Aux buffers in the framebuffer.
    PFD_MAIN_PLANE,
    0,
    0, 0, 0
};

【问题讨论】:

  • 您的上下文是什么版本的 OpenGL?立即模式渲染在现代 OpenGL 中已被弃用,并且在核心配置文件和 OpenGL ES 中不存在。
  • 另外,对于 RGB,HDC 的颜色深度应该为 24(或 RGBA 为 32),如shown here
  • 嗨,丹,感谢您的 cmets。我使用的 OpenGL 版本是 4.5.0,将颜色深度更改为 24 位并没有解决我的问题,尽管我可以看到这是该字段的正确值。

标签: c opengl


【解决方案1】:

两件事。

首先,你永远不会打电话给glViewport。您需要这样做来设置渲染表面的大小。视口应设置为使用整个窗口,因此您需要使用 Win32 函数来查询窗口的客户端大小。

第二个是:

glTranslatef(0, 0, -5);

为什么会在那里?这没有任何作用,它会导致三角形的 Z 分量变为 -5。这超出了 OpenGL 默认状态的 [-1, 1] Z 范围。

【讨论】:

  • 感谢 Nicol,您的回答让我更接近解决方案,但还不够。所以我添加了带有窗口​​大小的 glViewport,我得到了完全黑色的窗口,所以我尝试使用一半的宽度和高度,我得到的是一个黑色正方形,窗口大小为黑色的四分之一,而其余的区域不断翻转颜色(蓝色和红色)。再次没有任何东西呈现到屏幕上。我怀疑我没有选择正确的缓冲区来绘制和清除。关于如何解决这个问题的任何想法?非常感谢!
  • 忽略我之前的评论,我错过了我正在绘制一个渲染区域大小的黑色方块!
【解决方案2】:

首先,如果您的目标是“将像素从 OpenGL 获取到 DC”,那么通过 Window DC 来实现是非常有问题的。一方面,您完全依赖于窗口像素管理。像素所有权、窗口可见性、窗口裁剪等都会对您的渲染结果产生负面影响。

要考虑的另一件重要事情是,您只能设置窗口的像素格式一次!对于屏幕外渲染,您有 2 个选项(或 3 个,具体取决于主机系统是否支持 EGL 以及 EGL 环境是否为您提供屏幕外渲染):

  • 创建一个隐藏/不可见的帮助窗口,为 OpenGL 提供 DC 并渲染到 帧缓冲区对象。这是目前数据(2016 年)的首选解决方案

  • 创建一个 PBuffer 为 OpenGL 服务 DC 并渲染到该 DC

  • 创建屏幕外 EGL 上下文。离屏 EGL 可以支持直接离屏表面,因此不需要帧缓冲对象。或者没有主表面的屏幕外上下文,因此严格需要帧缓冲区对象。

在上述选项中 PBuffer 方法为您提供了一种在 DC 之间BitBlt 的可靠方式。然而,PBuffers 与创建一个不可见的窗口一样容易/难以创建,并且帧缓冲区对象为您提供了更多的控制权。与 PBuffers 不同的是,帧缓冲区对象目标(纹理或渲染缓冲区)的内容被禁止突然“消失”(PBuffers 可能随时变得无效)。

将图像从 OpenGL 中获取到可以与 DC 操作一起使用的“东西”的最可靠方法是创建一个 DIBSECTION (CreateDIBSection) 并使用 glReadPixels.

【讨论】:

  • 嗨 datenwolf,我已经尝试了选项 2,但失败了。你能详细说明一下选项1吗?隐形窗口是什么意思,它如何连接到 DC?谢谢
  • @vfiskewl:基本上,您遵循创建 Window 所需的所有步骤并为 OpenGL 配置它,但不要在其上调用 ShowWindow,也不要使用 WS_SHOW 样式。重要的一点是使用帧缓冲区对象作为渲染目标。那里有很多帧缓冲区对象教程。
  • @datenwolf:我认为他的问题比这更基本。他说渲染到窗口不起作用。我非常怀疑切换到 FBO 并传输到默认帧缓冲区会突然导致它工作。此外,直接渲染到窗口的默认帧缓冲区没有任何问题
  • @NicolBolas:我的印象是 OP 想要获取帧缓冲区内容以用于 GDI 操作。如果不是这样,我的整个回答自然就没有实际意义。
猜你喜欢
  • 2011-05-02
  • 2011-10-09
  • 1970-01-01
  • 2013-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
相关资源
最近更新 更多