Skip to content

Commit 5b1e1cb

Browse files
Fix artboards not exporting with transparency using Vello (#3921)
* Fix hide artboard for raster render mode * Desktop: Fix transparent viewport blending * Fix vello render using wrong color space conversion for background * Review
1 parent bf486b4 commit 5b1e1cb

File tree

5 files changed

+26
-38
lines changed

5 files changed

+26
-38
lines changed

desktop/src/render/composite_shader.wgsl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
7171

7272
if (viewport_srgb.a < 0.001) {
7373
viewport_srgb = constants.background_color;
74+
} else if (viewport_srgb.a < 0.999) {
75+
viewport_srgb = blend(viewport_srgb, constants.background_color);
7476
}
7577

7678
if (overlay_srgb.a < 0.001) {

editor/src/node_graph_executor.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,6 @@ impl NodeGraphExecutor {
440440
file_type,
441441
name,
442442
size,
443-
#[cfg(feature = "gpu")]
444-
transparent_background,
445443
artboard_name,
446444
artboard_count,
447445
..
@@ -491,12 +489,7 @@ impl NodeGraphExecutor {
491489

492490
match file_type {
493491
FileType::Png => {
494-
let result = if transparent_background {
495-
image.write_to(&mut cursor, ImageFormat::Png)
496-
} else {
497-
let image: RgbImage = image.convert();
498-
image.write_to(&mut cursor, ImageFormat::Png)
499-
};
492+
let result = image.write_to(&mut cursor, ImageFormat::Png);
500493
if let Err(err) = result {
501494
return Err(format!("Failed to encode PNG: {err}"));
502495
}

node-graph/libraries/no-std-types/src/color/color_types.rs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -879,42 +879,32 @@ impl Color {
879879
)
880880
}
881881

882+
/// Return the all components as a u8 slice, first component is red, followed by green, followed by blue, followed by alpha. Use this if the [`Color`] is in gamma space.
883+
#[inline(always)]
884+
pub fn to_rgba8(&self) -> [u8; 4] {
885+
[(self.red * 255.) as u8, (self.green * 255.) as u8, (self.blue * 255.) as u8, (self.alpha * 255.) as u8]
886+
}
887+
882888
/// Return the all components as a u8 slice, first component is red, followed by green, followed by blue, followed by alpha. Use this if the [`Color`] is in linear space.
883-
///
884-
/// # Examples
885-
/// ```
886-
/// use core_types::color::Color;
887-
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
888-
/// // TODO: Add test
889-
/// ```
890889
#[inline(always)]
891890
pub fn to_rgba8_srgb(&self) -> [u8; 4] {
892-
let gamma = self.to_gamma_srgb();
893-
[(gamma.red * 255.) as u8, (gamma.green * 255.) as u8, (gamma.blue * 255.) as u8, (gamma.alpha * 255.) as u8]
891+
self.to_gamma_srgb().to_rgba8()
892+
}
893+
894+
/// Return the all RGB components as a u8 slice, first component is red, followed by green, followed by blue. Use this if the [`Color`] is in gamma space.
895+
#[inline(always)]
896+
pub fn to_rgb8(&self) -> [u8; 3] {
897+
[(self.red * 255.) as u8, (self.green * 255.) as u8, (self.blue * 255.) as u8]
894898
}
895899

896900
/// Return the all RGB components as a u8 slice, first component is red, followed by green, followed by blue. Use this if the [`Color`] is in linear space.
897-
///
898-
/// # Examples
899-
/// ```
900-
/// use core_types::color::Color;
901-
/// let color = Color::from_rgbaf32(0.114, 0.103, 0.98, 0.97).unwrap();
902-
/// // TODO: Add test
903-
/// ```
904901
#[inline(always)]
905902
pub fn to_rgb8_srgb(&self) -> [u8; 3] {
906-
let gamma = self.to_gamma_srgb();
907-
[(gamma.red * 255.) as u8, (gamma.green * 255.) as u8, (gamma.blue * 255.) as u8]
903+
self.to_gamma_srgb().to_rgb8()
908904
}
909905

910906
// https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
911907
/// Convert a [Color] to a hue, saturation, lightness and alpha (all between 0 and 1)
912-
///
913-
/// # Examples
914-
/// ```
915-
/// use core_types::color::Color;
916-
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.).to_hsla();
917-
/// ```
918908
pub fn to_hsla(&self) -> [f32; 4] {
919909
let min_channel = self.red.min(self.green).min(self.blue);
920910
let max_channel = self.red.max(self.green).max(self.blue);

node-graph/libraries/rendering/src/renderer.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -522,18 +522,21 @@ impl Render for Artboard {
522522
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
523523
use vello::peniko;
524524

525-
// Render background
526-
let color = peniko::Color::new([self.background.r(), self.background.g(), self.background.b(), self.background.a()]);
527525
let [a, b] = [self.location.as_dvec2(), self.location.as_dvec2() + self.dimensions.as_dvec2()];
528526
let rect = kurbo::Rect::new(a.x.min(b.x), a.y.min(b.y), a.x.max(b.x), a.y.max(b.y));
529527

530-
scene.push_layer(peniko::Fill::NonZero, peniko::Mix::Normal, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
531-
scene.fill(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), color, None, &rect);
532-
scene.pop_layer();
528+
// Render background
529+
if !render_params.hide_artboards {
530+
let color = peniko::Color::new([self.background.r(), self.background.g(), self.background.b(), self.background.a()]);
531+
scene.push_layer(peniko::Fill::NonZero, peniko::Mix::Normal, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
532+
scene.fill(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), color, None, &rect);
533+
scene.pop_layer();
534+
}
533535

534536
if self.clip {
535537
scene.push_clip_layer(peniko::Fill::NonZero, kurbo::Affine::new(transform.to_cols_array()), &rect);
536538
}
539+
537540
// Since the content's transform is right multiplied in when rendering the content, we just need to right multiply by the artboard offset here.
538541
let child_transform = transform * DAffine2::from_translation(self.location.as_dvec2());
539542
let mut render_params = render_params.clone();

node-graph/libraries/wgpu-executor/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl WgpuExecutor {
129129
if let Some(target_texture) = output.as_mut() {
130130
target_texture.ensure_size(&self.context.device, size);
131131

132-
let [r, g, b, a] = background.unwrap_or(Color::TRANSPARENT).to_rgba8_srgb();
132+
let [r, g, b, a] = background.unwrap_or(Color::TRANSPARENT).to_rgba8();
133133
let render_params = RenderParams {
134134
base_color: vello::peniko::Color::from_rgba8(r, g, b, a),
135135
width: size.x,

0 commit comments

Comments
 (0)