Частково прозоре вікно OpenGL / Win32 - c + +, winapi, opengl

Я прочитав усі існуючі запитання про цю складну (нішу) тему, але я застряг. У мене є вікно Win32 з контекстом OpenGL. Я хочу, щоб моє вікно було частково прозорим.

My result so far is that the entirety of the вікно прозоре Я хочу, щоб лише чорна область була прозорою, щоб я міг намалювати деякі 3D-об'єкти, і вони будуть виглядати так, як вони приходять у вікно.

введіть опис зображення тут

По-перше, у своєму вікні класу я встановив hbrBackground для чорного кольору.

Windows::WindowClass windowClass;
windowClass.cbSize = sizeof(Windows::WindowClass);
windowClass.style = Windows::CS_VREDRAW | Windows::CS_HREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = moduleHandle;
windowClass.hIcon = Windows::LoadIcon(0u, (X*)Windows::IDI_QUESTION);
windowClass.hCursor = Windows::LoadCursor(0u, (X*)Windows::IDC_ARROW);
windowClass.hbrBackground = Windows::CreateSolidBrush(0x00000000);
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = (X*)name;
windowClass.hIconSm = Windows::LoadIcon(0u, (X*)Windows::IDI_QUESTION);

Я створив своє вікно з прапором WS_EX_LAYERED.

windowHandle = Windows::CreateWindow(Windows::WS_EX_LAYERED, (X*)name, "", Windows::WS_POPUP, w / 4, h / 4, w / 2, h / 2, 0u, 0u, moduleHandle, 0u);

У моєму піксельному форматі я включив альфа та композицію.

PixelFormatDescriptor format;
format.nSize = sizeof(PixelFormatDescriptor);
format.nVersion = 1;
format.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_SUPPORT_COMPOSITION;
format.iPixelType = PFD_TYPE_RGBA;
format.cColorBits = 32;
format.cRedBits = 0;
format.cRedShift = 0;
format.cGreenBits = 0;
format.cGreenShift = 0;
format.cBlueBits = 0;
format.cBlueShift = 0;
format.cAlphaBits = 8;
format.cAlphaShift = 0;
format.cAccumBits = 0;
format.cAccumRedBits = 0;
format.cAccumGreenBits = 0;
format.cAccumBlueBits = 0;
format.cAccumAlphaBits = 0;
format.cDepthBits = 24;
format.cStencilBits = 8;
format.cAuxBuffers = 0;
format.iLayerType = PFD_MAIN_PLANE;
format.bReserved = 0;
format.dwLayerMask = 0;
format.dwVisibleMask = 0;
format.dwDamageMask = 0;

Я спробував розмитий регіон "трюк", але це не має ефекту. Мій результат не пов'язаний з цим фрагментом коду.

struct DwmBlurBehind
{
U4 dwFlags;
S4 fEnable;
X* blurRegionHandle;
S4 fTransitionOnMaximized;
};

DwmBlurBehind blurBehind;
blurBehind.dwFlags = Windows::DWM_BB_ENABLE | Windows::DWM_BB_BLURREGION;
blurBehind.fEnable = true;
blurBehind.blurRegionHandle = Windows::CreateRectRgn(0, 0, -1, -1);
blurBehind.fTransitionOnMaximized = false;
Windows::DwmEnableBlurBehindWindow(windowHandle, &blurBehind);

Нарешті, я встановив LWA_COLORKEY іАтрибути LWA_ALPHA. Це дало мені відображений ефект. Однак, кольорова клавіша, здається, не враховується (я теж спробував відмінності від нуля).

Windows::SetLayeredWindowAttributes(windowHandle, 0, 170, Windows::LWA_COLORKEY | Windows::LWA_ALPHA);

Я не забув включити змішування.

GL::Enable(GL::BLEND);
GL::BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA);

Відповіді:

1 для відповіді № 1

Те, що ви хочете зробити, потребує компонування вікон, що існувало з Windows Vista, і, по суті, для кожної версії Windows, що вам потрібно дбати (Windows XP і раніше EoL).

Ключовими кроками, які слід вжити, є, щоб включити DWM компонування вбудованого вікна, увімкнувши "Блакитний за вікном" і використовувати a WM_POPUP вікно; якщо ви не використовуєте WM_POPUP стиль вікна менеджера буде намалювати прикраси, і ваш рендеринг OpenGL буде "наведене" над ним.

        DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = TRUE;
bb.hRgnBlur = NULL;
DwmEnableBlurBehindWindow(hWnd, &bb);

MARGINS margins = {-1};
impl_DwmExtendFrameIntoClientArea(hWnd, &margins);

Далі вам слід створити контекст OpenGL, використовуючи новий API "атрибут", а не використовувати вибір дескриптора pixelformat. За допомогою атрибута API ви можете вибрати a прозорий з альфа формат вікна

int attribs[] = {
WGL_DRAW_TO_WINDOW_ARB, TRUE,
WGL_DOUBLE_BUFFER_ARB, TRUE,
WGL_SUPPORT_OPENGL_ARB, TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_TRANSPARENT_ARB, TRUE,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, 0
};

INT iPF;
UINT num_formats_choosen;
if( !wglChoosePixelFormatARB(
hDC,
attribs,
NULL,
1,
&iPF,
&num_formats_choosen) ) {
fprintf(stderr, "error choosing proper pixel formatn");
return NULL;
}
if( !num_formats_choosen ) {
return NULL;
}

PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd));
/* now this is a kludge; we need to pass something in the PIXELFORMATDESCRIPTOR
* to SetPixelFormat; it will be ignored, mostly. OTOH we want to send something
* sane, we"re nice people after all - it doesn"t hurt if this fails. */
DescribePixelFormat(hDC, iPF, sizeof(pfd), &pfd);

if( !SetPixelFormat(hDC, iPF, &pfd) ) {
fprintf(stderr, "error setting proper pixel formatn");
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);

return NULL;
}

Для цього у мене є повний робочий приклад wglarb Обгортання сховища в GitHub: https://github.com/datenwolf/wglarb/blob/master/test/layered.c


2 для відповіді № 2

Ви можете пропустити дзвінок до UpdateLayeredWindow . IIRC, не викликаючи UpdateLayeredWindow, призводить до деякої дивної поведінки. YMMV

Детальніше тут


0 для відповіді № 3

Згідно з SetLayeredWindowAttributes doc вам потрібно пройти

структура COLORREF, яка визначаєпрозорість кольорова клавіша бути використовується при складанні шаруватих вікон. Усі пікселі, написані в Вікно в цьому кольорі буде прозорим. Щоб створити COLORREF, використовуйте макрос RGB.

Перегляньте другий параметр вашого виклику для цієї функції.


Схожі запитання
Найбільш популярний