Materials with transparency (blend) - z-sorting

Continuing the discussion from How to setup materials with transparency (blend) in a way that z-sorting works:

Hi,
when I add a blend (transparency) to a model with multiple meshes, the z-sorting is lost.
If I use Cutoff instead of Blend, as suggested here, it has no effect.

I need to fade the alpha of the entire model.

Unfortunately, this problem has existed since the first GPU and is generally not possible in a normal 3d rendering pipeline. See also:

You can try to switch between two materials, one opaque and one with transparency.

Okay, I found a workaround for my case.

I still have a question about transparency:
When I put a transparent black layer over my scene, the colors under the layer increase in intensity instead of decreasing.
This behaves similar to Photoshop when the layer is set to ‘overlay’ instead of ‘normal’.

How can I create an overlay of black transparent pixels that reduces the luminosity of the underlying colors?

can you post a patch showing this?
this should not happen but it might be the PostFX that do some trickery here.

try deactivating them to see if it makes a difference
grafik

On what render stage are you rendering that quad? Have you tried rendering it AfterScene?

image

thank you @motzi @bjoern!

PostFX have no effect.
AfterScene is already set.

here is a demo patch:
Transparency.vl (20.4 KB)
A sphere of 100% white overlaid with 90% black. The sphere should be rendered with 10% white, but it is 33%.

not sure what you tried, but for me it works.
I had to disable the postfx though, so the default ones don’t get applied.

Transparency.vl (22.9 KB)

the pipette value in vvvv is correct for me too.
but if I screenshot the renderer and measure in photoshop I have 65% with diabled PostFX.
image

I made another renderer in the patch with a circle of 10% black. the pipet says its 0.01 = 1% black
Transparency.vl (32.7 KB)

In your screenshot you’re sampling from the CMYK color model. Have you tried the same with RGB and also making sure your document has the correct color settings before pasting it in?

Another thing might be the whole color thing in Stride, where it might not exactly work as you’re expecting it to work. @motzi was cooking something up on this …

the document is rgb, the K value matters

i had a look and it seems, you have a wonderful clash of sRGB/linear conversion and wrong expectations of AlphaBlending here, but the math is right (as can be seen from the output of the pipet. the problem is: this output is in linear space and not in sRGB space that is shown on screen (which is the origin of the problem).

i can give you only a short answer right now of what i think is happening:

  • overlaying the black texture with alpha in stride happens in linear space. since the color comes from Skia (which works in sRGB space) it will be gamma corrected automatically when converting from Skia to Stride. the problem is: this will only happen for the RGB components, not the alpha. but our RGB components are all zero/black, so no effect of the conversion will be visible.
  • AlphaBlending just does a weighted adding of RGB of the destination (whats there already) and RGB source (what will be painted over it). usually those weights come from the source’s alpha channel or its inverse - but they will manipulate colors. two issues arise:
    • the alpha was not gamma corrected before, the results of the weighting will be wrong
    • your aim is to reduce the destination intensity, however AlphaBlending is about weighing colors and adding them. so standard AlphaBlending might not have been the right method to begin with.

so here is a quirky solution that seemingly produces the right/expected results for sRGB. i’m using a different blend mode here that weighs the destination color with the source alpha (which is what you actually want to achieve, if i’m right). also, i assume the alpha value to be not black with 90% opacity but rather to be the inverse (10%) of the original color that should pass through. i guess this here only works under this assumption (so don’t use colorized overlays, just black with alpha).

grafik

grafik

here you go, sorry i’m too tired now for longer explanations in the patch.
Transparency_2.vl (52.0 KB)

PS: i’d be curious if there is a more elegant solution to this…

That’s what I thought to when seeing the SkiaTexture. But the result is the same when just using a black quad.

image

Can not really be considered a solution but when rendering to a texture one can convert to linear at the end.

BTW if you set the colorspace to Gamma both spheres behave the same “wrong” way.

image

Transparency_ColorSpace.vl (48.5 KB)

that’s what I did initially. however, when looking for a way to only darken where only the overlay texture is visible (in cases where this is a partial mask and not covering the screen fully), this approach fails as it applys it on everything. therefore i wanted to see if there is a “blend only” solution and that’s what I got. (also blend-only should make it cheaper compared to the TFX).

not sure if “wrong” is the right word - i think the math is right. it’s just unexpected considering there are many more things going on here compared to photoshop (which, iirc, also did not blend correctly for a long time).

1 Like

that’s why I put it in quotes :)

indeed, this is where the second unexpected thing kicks in - the way that AlphaBlending works does not fit for this usecase. here’s the formula again:

Color = Src.RGB * Src.A + Dst.RGB * (1 - Src.A)
Alpha = Src.A + Dst.A * (1 - Src.A)

simplified for this case where Src.RGB is black/zero:

Color = Dst.RGB * (1 - Src.A)

so the resulting color will be weight by the inverse of the alpha of the black overlay.
in the end it just means, we’re darkening by some amount (which happens in linear space). however, for the Src.A, no automatic gamma conversion is applied (unlike for Src.RGB), so we have to do this manually to get the expected darkening of the color.

therefore created my own blend mode that looks like this:

Color = ONE* Src.RGB + Dst.RGB * (Src.A)
// ONE* Src.RGB will be zero for black

but Src.A will be gamma2linear(1-Src.A).

this works as the idea is just to darken existing pixels with gamma correction applied to the alpha.

Edit: added link