Color Blending
ColorBlending 发生在PixelShader的下一个阶段: Output Merger Stage.
默认情况下, 混合功能时被关闭的。
方程
Color = SrcColor * SrcBlend + DestColor * DestBlend
假设4维向量SrcColor=(Rs, Gs, Bs, As), SrcBlend=(S1, S2, S3, S4), DestColor=(Rd, Gd, Bd, Ad),DestBlend(D1, D2, D3, D4),则混合颜色Color可用4维向量表示为: maColor = (Rs * S1 + Rd * D1, Gs * S2 + Gd * D2, Bs * S3 + Bd * D3, As * S4 + Ad * D4)
窗口透明
即使texture已经填好了每个像素点的alpha值, 当提交给swapChain的时候还是不生效的, 因为窗口有”底色”。
应用如下的代码, 可以让dwm阶段应用alpha值:
#include <windows.h>
#include <dwmapo.h>
static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD) {
typedef LONG(WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG);
static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL;
if (RtlVerifyVersionInfoFn == NULL)
if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll"))
RtlVerifyVersionInfoFn =
(PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo");
if (RtlVerifyVersionInfoFn == NULL)
return FALSE;
RTL_OSVERSIONINFOEXW versionInfo = {};
ULONGLONG conditionMask = 0;
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
versionInfo.dwMajorVersion = major;
versionInfo.dwMinorVersion = minor;
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION,
conditionMask) == 0)
? TRUE
: FALSE;
}
#define _IsWindowsVistaOrGreater() \
_IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
#define _IsWindows8OrGreater() \
_IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
#define _IsWindows8Point1OrGreater() \
_IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
#define _IsWindows10OrGreater() \
_IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), \
0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10
void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd) {
if (!_IsWindowsVistaOrGreater())
return;
BOOL composition;
if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)
return;
BOOL opaque;
DWORD color;
if (_IsWindows8OrGreater() ||
(SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque)) {
HRGN region = ::CreateRectRgn(0, 0, -1, -1);
DWM_BLURBEHIND bb = {};
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.hRgnBlur = region;
bb.fEnable = TRUE;
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
::DeleteObject(region);
}
else {
DWM_BLURBEHIND bb = {};
bb.dwFlags = DWM_BB_ENABLE;
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
}
}
特别注意
如果要应用到子窗口上, 子窗口需要指定WS_POPUP属性:
WNDCLASSEX wc;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = "WindowClass1";
// register the window class
RegisterClassEx(&wc);
// create the window and use the result as the handle
HWND hWnd1 =
CreateWindowEx(NULL,
"WindowClass1", // name of the window class
"Our First Windowed Program", // title of the window
NULL, // window style
GetSystemMetrics(SM_CXSCREEN) / 4, GetSystemMetrics(SM_CYSCREEN) / 4,
GetSystemMetrics(SM_CXSCREEN) / 2, GetSystemMetrics(SM_CYSCREEN) / 2,
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
wc.hInstance, // application handle
NULL); // used with multiple windows, NULL
ShowWindow(hWnd1, SW_SHOWNOACTIVATE);
UpdateWindow(hWnd1);
// the handle for the window, filled by a function
HWND hWnd2 =
CreateWindowEx(NULL,
"WindowClass1", // name of the window class
"Child", // title of the window
WS_CHILD | WS_POPUP | WS_CAPTION, // window style
GetSystemMetrics(SM_CXSCREEN) / 4, GetSystemMetrics(SM_CYSCREEN) / 4,
GetSystemMetrics(SM_CXSCREEN) / 2, GetSystemMetrics(SM_CYSCREEN) / 2,
hWnd1, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
wc.hInstance, // application handle
NULL); // used with multiple windows, NULL
参考
- https://weblogs.asp.net/kennykerr/Windows-Vista-for-Developers-_1320-Part-3-_1320-The-Desktop-Window-Manager
- https://github.com/walklang/uilib/issues/4