OpenGL: glReadPixels "терпит неудачу", хотя glGetError возвращает 0 - PullRequest
0 голосов
/ 21 сентября 2011

Краткое описание проблемы:

Я использую OpenGL glReadPixels, чтобы получить скриншот, но буфер не изменился. Если я использую glGetError, чтобы получить ошибку от последней функции, она возвращает 0, как будто все в порядке.

Я проводил тщательные исследования в Интернете и не нашел никого, кто сталкивался бы с такой проблемой.

Подробнее:

Я использую CsGL.dll, который в основном просто оборачивает OpenGL в C #, и я сделал необходимые инициализации для использования GL: DC от hWnd, выберите PixelFormat для DC с помощью PixelFormatDescriptor и установите его в качестве его формата, создав RC для DC и вызвав wglMakeCurrent (RC, DC).


Обратите внимание, что я использую простые оболочки для функций Windows API. Вот код для этой инициализации, которую я использовал:

public unsafe void Init(IntPtr hWnd)
{
        this.DC = (IntPtr)User.GetDC(this.HWnd = hWnd);

        var pfd = new PIXELFORMATDESCRIPTOR();
        var sizeOf = Marshal.SizeOf(pfd);

        Kernel.ZeroMemory(new IntPtr(&pfd), sizeOf);
        pfd.nSize = (short)sizeOf;
        pfd.nVersion = 1;
        pfd.dwFlags = (int)(PixelFormatDescriptorFlagsEnum.PFD_DRAW_TO_WINDOW |
                            PixelFormatDescriptorFlagsEnum.PFD_SUPPORT_OPENGL |
                            PixelFormatDescriptorFlagsEnum.PFD_DOUBLEBUFFER);
        pfd.iPixelType = PIXELFORMATDESCRIPTOR.PFD_TYPE_RGBA;
        pfd.cColorBits = 24;
        pfd.cDepthBits = 16;
        pfd.iLayerType = PIXELFORMATDESCRIPTOR.PFD_MAIN_PLANE;

        var iFormat = GDI.ChoosePixelFormat(this.DC, ref pfd);
        GDI.SetPixelFormat(this.DC, iFormat, ref pfd);

        this.RC = wglCreateContext(this.DC);

        wglMakeCurrent(this.DC, this.RC);
}

Я отправил User.GetForegroundWindow () как hWnd.

После этой инициализации я пытаюсь вставить скриншот в изображение (и я также попытался прочитать его в простой байтовый массив)

Короткий псевдо-код использования glReadPixels:

var area = new Rectangle(0, 0, 100, 100);
var bmp = new Bitmap(area.Width, area.Height);
var data = bmp.LockBits(area, ILM.WriteOnly, PF.24bppRgb);

glReadBuffer(BACK);
glReadPixels(0, 0, area.Width, area.Height, BGR_EXT /*also tried RGB and RGBA*/, UNSIGNED_BYTE, data.Scan0);

bmp.UnlockBits(data);
bmp.Save(@"C:\Back.bmp");

data = bmp.LockBits(area, ILM.WriteOnly, PF.24bppRgb);

glReadBuffer(FRONT);
glReadPixels(0, 0, area.Width, area.Height, BGR_EXT /*also tried RGB and RGBA*/, UNSIGNED_BYTE, data.Scan0);

bmp.UnlockBits(data);
bmp.Save(@"C:\Front.bmp");

Попытка сделать это простым и маленьким байтом [] была сделана так:

var bytes = new byte[10 * 10 * 3];
glReadPixels(0, 0, 10, 10, RGB, UNSIGNED_BYTE, bytes);

И байт [] был нулевым. Я также пробовал это с большим размером для массива (сохраняя 0, 0, 10, 10), но все еще безрезультатно.


В обоих случаях результат одинаков. Буфер не изменяется вообще, в то время как вызов glGetError возвращает 0 после каждого вызова функции GL.

И Back.bmp, и Front.bmp полностью черные.

Пожалуйста, скажите мне, что я делаю не так? Спасибо

1 Ответ

3 голосов
/ 21 сентября 2011

Вы пытаетесь создать снимок экрана с изображением, которое вы отрисовали, или снимок экрана в целом?

glReadPixels гарантированно работает только для содержимого кадрового буфера OpenGL.Он не подходит для того, чтобы делать скриншоты чего-либо еще (раньше было время, когда это было возможно, но с момента появления композитных оконных менеджеров эти времена прошли).

Так что если вы пытаетесьсделать общий снимок экрана, glReadPixels - неправильный путь.

Если вы пытаетесь сделать скриншот того, что вы рендерили, то вы должны убедиться, что контекст выдаеттакже активен при вызове glReadPixels .

...