From dac835fe33b7d6b584ad93e46b8de4c16dfb3bda Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Thu, 28 May 2026 10:29:05 +0300 Subject: [PATCH] fix(viewport): use premultiplied blend on surface blit Geometry passes draw with standard `SrcAlpha / 1-SrcAlpha` into a transparent MSAA target, so AA-edge fragments sit as `(rgb * a, a)` in the resolve texture. The previous straight-alpha blit then multiplied those by `a` a second time, darkening thin lines and curves over the transparent background. `PREMULTIPLIED_ALPHA_BLENDING` matches what is actually in the resolve texture and renders edges at full intensity while still leaving fully-transparent pixels untouched on the surface. Co-Authored-By: Claude Opus 4.7 --- src/scene/pipeline/mod.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/scene/pipeline/mod.rs b/src/scene/pipeline/mod.rs index cac0acd30..26407371f 100644 --- a/src/scene/pipeline/mod.rs +++ b/src/scene/pipeline/mod.rs @@ -772,12 +772,17 @@ impl Pipeline { entry_point: Some("fs_main"), targets: &[Some(wgpu::ColorTargetState { format, - // Alpha-blend the resolve texture onto the surface so a - // transparent shader clear (alpha=0 outside any drawn - // geometry) leaves whatever the underlying widget - // painted — model container bg in a model layout, - // PaperCanvas sheet in a paper layout — visible. - blend: Some(wgpu::BlendState::ALPHA_BLENDING), + // Premultiplied-alpha blend: the geometry passes already + // wrote into a transparent MSAA target with standard + // `SrcAlpha / 1-SrcAlpha` blending, so AA-edge fragments + // sit as `(rgb * a, a)` in the resolve texture. Treating + // that as straight alpha during the surface blit would + // multiply by alpha a second time and darken thin lines + // / curves. `PREMULTIPLIED_ALPHA_BLENDING` uses `One` as + // the source colour factor and leaves the dst weighted + // by `1-SrcAlpha`, which is the correct compositing + // operator for already-premultiplied content. + blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, })], compilation_options: wgpu::PipelineCompilationOptions::default(),