跪拜 Guibai
← All articles
C++

A Pure D3D11 Frosted Glass Effect for Win32, with Zero Dependencies

By JetComXCpp ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Adding a modern frosted-glass UI to a native Win32 app has typically meant dragging in a heavy runtime like UWP, WinUI, Qt, or Electron. This library gives C++ desktop applications a lightweight, framework-free path to the same effect, with full control over the rendering pipeline and no dependency tax.

Summary

A new open-source library, WindowsLiquidGlass, brings macOS-style frosted glass to Win32 applications through a pure D3D11 and HLSL implementation. It requires only three source files and a chainable C++ API to add real-time Gaussian blur, rounded corners, saturation control, refractive distortion, and chromatic dispersion to any window. The effect runs on Windows 10 and 11 with a GPU supporting D3D11 Feature Level 11.0.

Each frame is built from five render passes: background capture, a separable 31-tap Gaussian blur split into horizontal and vertical passes, an SDF-based drop shadow, the core glass body with refraction and dispersion, and final alpha compositing. The blur weights are precomputed on the CPU to avoid millions of GPU-side exponential calculations per frame. Refraction uses a circleMap function to mimic a convex lens, and chromatic dispersion splits a single texture sample into seven offset samples with per-channel energy-conserving weights.

The implementation surfaced several sharp-edged D3D11 realities. HLSL constant-buffer alignment rules caused a 16-element float array to balloon from 64 to 256 bytes, misaligning all subsequent data. The `sign(0) = 0` edge case produced NaN gradients and white artifacts, but only when the glass rectangle had odd pixel dimensions. And D3D11's silent nulling of a shader resource view when a resource is still bound as a render target caused mysterious black-frame bugs.

Takeaways
A 31-tap separable Gaussian blur splits a 961-sample 2D convolution into two 1D passes totaling 62 samples, with identical visual results and an order-of-magnitude speed gain.
Blur weights are precomputed on the CPU and stored in a constant buffer, saving over 100 million GPU-side exp() evaluations per frame at 1080p.
Refractive distortion uses a circleMap function (1 - sqrt(1 - t²)) to map linear distance into a convex-lens curvature, concentrating refraction at the glass edges.
Chromatic dispersion is implemented as seven offset texture samples with per-channel energy-conserving weights, and falls back to a single-sample shader when disabled.
HLSL constant buffers align every array element to a float4 boundary, so a float weights[16] occupies 256 bytes instead of 64, requiring manual packing into float4.
The sign(0) = 0 edge case in HLSL produces a zero SDF gradient on the glass centerline, which normalizes to NaN and renders as white — but only when the glass dimensions are an odd number of pixels.
D3D11 silently sets a shader resource view to NULL if the underlying resource is still bound as a render target, producing a black frame with no error or warning.
Conclusions

The project's real contribution is not the visual effect itself — which is well-understood — but packaging it into a three-file, zero-dependency library that sidesteps the entire UWP/WinUI stack for native Win32 applications.

The chainable API design (`.Blur().Radius().Saturation()`) mirrors modern graphics-library ergonomics and makes the effect trivially adoptable in existing codebases.

The sign(0) bug that only manifests at odd pixel dimensions is a classic graphics gotcha: a mathematically correct edge case that becomes a visual artifact only under specific, non-obvious conditions, making it extremely hard to reproduce and diagnose.

Precomputing Gaussian weights on the CPU is a pragmatic optimization that acknowledges GPU compute is better spent on sampling and blending than on transcendental math, even though modern GPUs could handle the exp() calls.

Concepts & terms
Separable Gaussian blur
A 2D Gaussian blur decomposed into two 1D passes (horizontal then vertical). A 31×31 kernel requiring 961 samples per pixel is reduced to 62 samples, producing identical results with far less computation.
Signed Distance Field (SDF)
A function that returns the signed distance from a point to the nearest surface of a shape. Used here to define rounded-rectangle boundaries and to produce built-in anti-aliasing via smoothstep interpolation across a 2-pixel transition band.
circleMap
A convex mapping function (1 - sqrt(1 - t²)) that transforms a linear distance t into a curved profile. Applied to refraction, it concentrates distortion at the edges of the glass while leaving the center nearly clear, mimicking a convex lens.
Chromatic dispersion
The physical phenomenon where different wavelengths of light refract at slightly different angles. Simulated here by sampling the blurred background at seven offset positions along the refraction direction, with separate red, green, and blue weight distributions that sum to 1.0 per channel.
HLSL constant buffer alignment
HLSL constant buffers align data to float4 (16-byte) boundaries. A float array like weights[16] allocates 16 bytes per element instead of 4, causing the array to occupy 256 bytes and misaligning any data declared after it unless manually packed.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗