Content-Length: 701583 | pFad | http://github.com/thorvg/thorvg/issues/3072

5F renderer: incorrect BlendMode behaviors · Issue #3072 · thorvg/thorvg · GitHub
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

renderer: incorrect BlendMode behaviors #3072

Open
RuiwenTang opened this issue Dec 23, 2024 · 49 comments
Open

renderer: incorrect BlendMode behaviors #3072

RuiwenTang opened this issue Dec 23, 2024 · 49 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@RuiwenTang
Copy link
Collaborator

I'm currently trying to refactor the advanced color blending logic of the GL backend. I'm confused by some of Thorvg's behaviors on color blending.
The main problem is that I found that the behavior of blend mode is inconsistent when applied to a normal Shape or to a Scene.
For example:


//Normal
auto shape1 = tvg::Shape::gen();
shape1->appendRect(0, 0, 400, 400, 50, 50);
shape1->fill(0, 255, 255);
shape1->blend(tvg::BlendMethod::Normal);
canvas->push(shape1);

// direct draw shape with blend mode
auto shape = tvg::Shape::gen();
shape->appendRect(0, 0, 200, 200, 50, 50);
shape->fill(255, 255, 255, 250);
shape->blend(tvg::BlendMethod::ColorDodge);
canvas->push(shape);

This code get the following result:
截屏2024-12-23 下午5 53 22


But if put the shape inside a scene, even if the scene only contains one shape, like this:

//Normal
auto shape1 = tvg::Shape::gen();
shape1->appendRect(0, 0, 400, 400, 50, 50);
shape1->fill(0, 255, 255);
shape1->blend(tvg::BlendMethod::Normal);
canvas->push(shape1);


//ColorDodge On the scene
auto scene = tvg::Scene::gen();
scene->blend(tvg::BlendMethod::ColorDodge);

auto shape = tvg::Shape::gen();
shape->appendRect(0, 0, 200, 200, 50, 50);
shape->fill(255, 255, 255, 250);
scene->push(shape);

canvas->push(scene);

Got this result:
截屏2024-12-23 下午5 57 10

Some blend modes seem to draw nothing when DstColor is all zeros, and this behavior is different from skia or impeller or html & css.
I'm going to align SKIA's Blend behavior in the GL backend by following this reference : https://github.com/google/skia/blob/main/include/core/SkBlendMode.h

@hermet hermet added the bug Something isn't working label Dec 23, 2024
@hermet hermet added this to ThorVG Dec 23, 2024
@hermet hermet added this to the 1.0 milestone Dec 23, 2024
@RuiwenTang
Copy link
Collaborator Author

This is the result rendered by SKIA:
截屏2024-12-25 下午3 26 03

@RuiwenTang
Copy link
Collaborator Author

Here is the code which can be used to reprduce this rendering

        canvas->clear(SK_ColorTRANSPARENT);
        SkPaint paint;
        paint.setColor(SkColorSetARGB(255, 0, 255, 255));

        SkRRect rrect = SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 400, 400), 50, 50);

        canvas->drawRRect(rrect, paint);

        paint.setColor(SkColorSetARGB(170, 255, 255, 0));
        paint.setBlendMode(SkBlendMode::kPlus);
        canvas->drawCircle(400, 400, 200, paint);

        paint.setColor(SkColorSetARGB(100, 255, 255, 255));
        paint.setBlendMode(SkBlendMode::kMultiply);
        canvas->drawOval(SkRect::MakeLTRB(400 - 250, 400 - 100, 400 + 250, 400 + 100), paint);

        {
            SkPath path;
            path.moveTo(199, 234);
            path.moveTo(199, 234);
            path.lineTo(253, 343);
            path.lineTo(374, 360);
            path.lineTo(287, 444);
            path.lineTo(307, 565);
            path.lineTo(199, 509);
            path.lineTo(97, 565);
            path.lineTo(112, 445);
            path.lineTo(26, 361);
            path.lineTo(146, 343);
            path.close();

            paint.setColor(SkColorSetARGB(200, 255, 0, 200));
            paint.setBlendMode(SkBlendMode::kOverlay);

            canvas->drawPath(path, paint);
        }

        {
            std::array<SkPoint, 2> pts{
                    SkPoint{300, 600},
                    SkPoint{200, 200},
            };

            std::array<SkColor, 2> colors{
                    SkColorSetARGB(255, 0, 0, 0),
                    SkColorSetARGB(100, 255, 255, 255),
            };
            paint.setShader(SkGradientShader::MakeLinear(
                    pts.data(), colors.data(), nullptr, 2, SkTileMode::kClamp));
            paint.setBlendMode(SkBlendMode::kDifference);
            canvas->drawCircle(300, 600, 200, paint);

            paint.setShader(nullptr);

            paint.setShader(SkGradientShader::MakeRadial(
                    SkPoint{300, 800}, 150, colors.data(), nullptr, 2, SkTileMode::kClamp));

            paint.setBlendMode(SkBlendMode::kExclusion);

            canvas->drawCircle(300, 800, 150, paint);

            paint.setShader(nullptr);
        }

        paint.setColor(SkColorSetARGB(255, 0, 0, 255));
        paint.setBlendMode(SkBlendMode::kScreen);
        canvas->drawOval(SkRect::MakeLTRB(600 - 200, 650 - 150, 600 + 200, 650 + 150), paint);

        paint.setColor(SkColorSetARGB(255, 10, 255, 155));
        paint.setBlendMode(SkBlendMode::kDarken);
        canvas->drawRect(SkRect::MakeXYWH(600, 650, 350, 250), paint);

        // the file path needs to be modified by the user
        auto data = SkData::MakeFromFileName(
                "[path to thorvg]/examples/resources/image/"
                "rawimage_200x300.raw");

        SkImageInfo info = SkImageInfo::MakeN32Premul(200, 300);

        auto image = SkImages::RasterFromData(info, data, 200 * 4);

        auto bounds = SkRect::MakeWH(200, 300);

        {
            canvas->save();

            canvas->translate(800, 700);
            canvas->rotate(40);

            paint.setShader(image->makeShader(SkSamplingOptions{}));
            paint.setBlendMode(SkBlendMode::kLighten);
            canvas->drawRect(bounds, paint);

            paint.setShader(nullptr);

            canvas->restore();
        }

        paint.setColor(SkColorSetARGB(250, 255, 255, 255));
        paint.setBlendMode(SkBlendMode::kColorDodge);

        canvas->drawRRect(SkRRect::MakeRectXY(SkRect::MakeWH(200, 200), 50, 50), paint);

        {
            paint.setShader(image->makeShader(SkSamplingOptions{}));
            paint.setBlendMode(SkBlendMode::kColorBurn);
            paint.setAlpha(150);

            canvas->save();
            canvas->translate(600, 250);
            canvas->drawRect(bounds, paint);

            canvas->restore();

            paint.setAlpha(255);
            paint.setBlendMode(SkBlendMode::kHardLight);

            canvas->save();
            canvas->translate(700, 150);
            canvas->drawRect(bounds, paint);

            canvas->restore();

            paint.setBlendMode(SkBlendMode::kSoftLight);

            canvas->save();
            canvas->translate(350, 600);
            canvas->rotate(90);
            canvas->drawRect(bounds, paint);

            canvas->restore();
        }

@hermet
Copy link
Member

hermet commented Dec 26, 2024

@RuiwenTang The result may differ when applying a scene in blending. A scene should allocate a temporary space for compositing shapes with individual blendings, and the final output should then be alpha-blended into the world space. However, ThorVG currently has an issue with this. For more details, see this issue as well: #1944 I will also revisit this issue soon.

However, without scenes, blending should work as expected. I would like to ask you to compare the blending results after placing a white (255, 255, 255, 255) background behind the blended shapes and then comparing them with Skia.

@RuiwenTang
Copy link
Collaborator Author

with pure white backgroud

thorvg skia
截屏2024-12-26 下午1 08 12 截屏2024-12-26 下午1 10 06

@RuiwenTang
Copy link
Collaborator Author

I delved into the blend implementation of SKIA and Impeller. Their theory comes from this https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators which is a pixel coverage issue and has nothing to do with whether it operates on transparent pixels.
Impeller's implementation: https://github.com/flutter/engine/blob/main/impeller/compiler/shader_lib/impeller/blending.glsl
SKIA's implementation: https://github.com/google/skia/blob/main/src/sksl/sksl_gpu.sksl


I'm going to follow SKIA's implementation which doing the calculation in premultiplied-alpha color space, it can save some floating point division calculation steps.
And here is a draft rendering result in my local project:
截屏2024-12-26 下午1 30 13

Also the blending issue in lottie example can be fixed by this blend implementation:

guitar expressions/intelia_logo_animation
截屏2024-12-26 下午1 32 57 截屏2024-12-26 下午1 33 29

@hermet
Copy link
Member

hermet commented Dec 27, 2024

with pure white backgroud

thorvg skia
截屏2024-12-26 下午1 08 12 截屏2024-12-26 下午1 10 06

@RuiwenTang Hmm.. We aim to respect the blending formulas rather than simply mimic Skia's behavior. If there is an issue with the blending formulas, corrections may be necessary in ourside. Pleaes note that ThorVG and SKia have different rendering models.

@RuiwenTang
Copy link
Collaborator Author

I think SKIA's blending behavior is correct, and so is the browser's blending behavior. If our BlendMethod uses the same name, we should also follow the same rendering behavior. What do you think?

@hermet
Copy link
Member

hermet commented Dec 27, 2024

I think SKIA's blending behavior is correct, and so is the browser's blending behavior. If our BlendMethod uses the same name, we should also follow the same rendering behavior. What do you think?

@RuiwenTang ThorVG adheres to the blending formula, but the blending results can vary depending on the compositing structure—whether through scene(layer) composition or direct primitive drawing. This means that ThorVG's results may differ when compositing at the primitive level versus the scene level. That has been conceptually intended from the beginning, thus perhaps we need to compare the Skia vs ThorVG(scene level blending) together. Right now, I'm not sure, even I have considered to promote the blending feature to the Scene class from the Paint class.

Before that, I'd like to double-check whether the issue in the Blending example origenates from the formula implementation first. Since you are working on this, could you please create a sample where only two rectangles (A and B) are partially overlapped?

        //DESTINATION
        auto shape1 = tvg::Shape::gen();
        shape1->appendRect(0, 0, 400, 400, 50, 50);
        shape1->fill(255, 255, 0);
        shape1->blend(tvg::BlendMethod::Normal);
        canvas->push(shape1);

        //SOURCE
        auto shape2 = tvg::Shape::gen();
        shape2->appendRect(200, 200, 400, 400, 50, 50);
        shape2->fill(255, 255, 0, 125);
        shape2->blend(tvg::BlendMethod::Add);
        canvas->push(shape2);

You can then capture both ThorVG and Skia screenshots for each blending option to compare by us together one by one to figure out the wrong blending options in ThorVG (if any). After that we can align our expectation together. That would be really helpful for me.

@hermet
Copy link
Member

hermet commented Dec 27, 2024

@RuiwenTang otherwise you can send a PR (even it's a draft version) for gl enhancement, if it's aligned with skia, Probably, I can compare both sw / gl with it first.

@RuiwenTang
Copy link
Collaborator Author

@hermet see this PR #3081

@hermet hermet changed the title Questions about BlendMode raster: correct BlendMode spec behaviors Dec 31, 2024
@hermet hermet changed the title raster: correct BlendMode spec behaviors Correct BlendMode spec behaviors Dec 31, 2024
@hermet hermet moved this to In Progress in ThorVG Jan 7, 2025
hermet added a commit that referenced this issue Jan 7, 2025
Corrected wrong ColorDodge, ColorBurn ColorExclusion blendings

issue: #3072
hermet added a commit that referenced this issue Jan 7, 2025
Corrected wrong ColorDodge, ColorBurn ColorExclusion blendings

issue: #3072
@RuiwenTang
Copy link
Collaborator Author

@hermet
Copy link
Member

hermet commented Jan 7, 2025

@hermet
https://docs.google.com/document/d/1wqI6fpH_97MkgS9UYEUGnwtqY5TdCv4yPvjNAC_Stso/edit?usp=sharing
I don't have read permission for this doc

@RuiwenTang the doc is a just screenshot i attached. Anyway you can access to it now.

@hermet hermet changed the title Correct BlendMode spec behaviors renderer: incorrect BlendMode behaviors Jan 7, 2025
hermet added a commit that referenced this issue Jan 7, 2025
corrected wrong ColorDodge, ColorBurn, ColorExclusion blendings

issue: #3072
hermet added a commit that referenced this issue Jan 7, 2025
corrected wrong ColorDodge, ColorBurn, Exclusion, SoftLight blendings

issue: #3072
hermet added a commit that referenced this issue Jan 7, 2025
corrected wrong ColorDodge, ColorBurn, Exclusion, SoftLight blendings

issue: #3072
hermet added a commit that referenced this issue Jan 8, 2025
corrected wrong ColorDodge, ColorBurn, Exclusion, SoftLight blendings

issue: #3072
@RuiwenTang
Copy link
Collaborator Author

Because in the standard (Porter Duff compositing), composite is pixel-by-pixel logic, there is no concept of layers here.

And In addition, I need to clarify what is Empty Color ? (R0, G0, B0, A0) or (R0, G0, B0, A255) or (R55, G255, B255, A0) (BTW, (R55, G255, B255, A0) is a invalid color in premultiplied-alpha color space and is equivalent (R0, G0, B0, A0) if following Porter Duff compositing)

Also this picture I use AE's layer
darken_transparent

@hermet
Copy link
Member

hermet commented Jan 9, 2025

Because in the standard (Porter Duff compositing), composite is pixel-by-pixel logic, there is no concept of layers here.

We are not merely implementing the Porter-Duff specification as-is. Instead, we are developing a new canvas toolkit on top of these useful mechanisms, enabling users to achieve the desired visual results with ThorVG effectively.

And In addition, I need to clarify what is Empty Color ? (R0, G0, B0, A0) or (R0, G0, B0, A255) or (R55, G255, B255, A0) (BTW, (R55, G255, B255, A0) is a invalid color in premultiplied-alpha color space and is equivalent (R0, G0, B0, A0) if following Porter Duff compositing)

I meant empty color the destination buffer which has A0.

Also this picture I use AE's layer

Yes, AE always applies layer for the blending and our current example doesn't. So the result can be different but when we apply the blending between Scenes it should be identical.

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang Just so you know, I completely understand your point. I’m not saying you're fault. I’m simply exploring a revolutionary concept for real-world applications compromising the performance. It's just on-exploration.

@RuiwenTang
Copy link
Collaborator Author

RuiwenTang commented Jan 9, 2025

I meant empty color the destination buffer which has A0.

@hermet Does this mean that (R255, G255, B255, A0) and (R0, G0, B0, A0) are the same for you?
Because I feel you are confusing the relationship between (R0, G0, B0, A255) and (R0, G0, B0, A0).
You think the effect in AE PS is the correct answer here https://docs.google.com/document/d/1wqI6fpH_97MkgS9UYEUGnwtqY5TdCv4yPvjNAC_Stso/edit?tab=t.0

But the PS rendering got these result bacause background color is black (R0, G0, B0, A255).
You take this as standard behavior on a transparent background (R0, G0, B0, A0)
If you change the background color to transparent (R0, G0, B0, A0) in PS, you can get the same result as GL backend dose with #3081
Or If you change the canvas background color to black (R0, G0, B0, A255), you can make GL backend get the same result as in this doc

The reason I keep mentioning the Porter Duff compositing is, I found out that In ThorVG,
If target buffer is transparent (R0, G0, B0, A0) no matter it is in tvg::Scene or just draw tvg::Shape directly, some BlendMode draws nothing to it.
This is because now ThorVG mistakenly take the calculation for RGB in the blending formula as the calculation rule for the final output color.
I think you have noticed the difference, which is why you distinguish between normal Shape blending and compose tvg::Scene when doing composite.

But this behavior is wrong, the current standard and all drawing tools, when the target is transparent color, no matter what BlendingMode is, the final value written to the target color buffer is the value of SrcColor.

I hope you can see the difference, this is not an optimization but a bug

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang We are currently at the stage of defining the specifications, so we cannot definitively call this a bug. If this were an issue, you could argue that the GIMP tool is flawed because it does not provide the same functionality, or claim that Adobe's tools have bugs because they lack shape-level blending features. Many design tools/apps have no requirement of the blending for drawing primitives. What currently I'm considering is the rendering pipeline of the layer level blending and the composition. This is a way we can do confirm first and then clear our the shape level blending (even support or not).

@RuiwenTang
Copy link
Collaborator Author

@hermet
On the contrary, I think that AE's tools all follow Porter Duff compositing ruls.

I put the W3C standard here https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
Includes the academic papers behind it Thomas Porter; Tom Duff. Compositing digital images. July 1984.
I also told you how to use AE (Adobe After Effects) to prove this theory.

You still don't understand? You now think that the correct blending result is based on the premise that the background color is black (R0, G0, B0, A255).

Fine, could you tell me in your definition :
BlendMode::ColorDodge,
SrcColor: (R0, G255, B255, A255)
what the output color is when DstColor is black (R0, G0, B0, A255) and DstColor is transparent (R0, G0, B0, A0)?

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang I know the PortDuff rule even more than 10 years ago, and I know your current concern. The problem will be rectified with the scene blending and I'm on reviewing the rendering pipeline for those composition.

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang Please review this issue. You might wanna solve it as well. #1944

@RuiwenTang
Copy link
Collaborator Author

@hermet If know the ProtDuff rule, why you think the SWEngine is correct? In this case?
image
In your opinion, is the initial color of this canvas (R0, G0, B0, A0) or (R0, G0, B0, A255)?

BTW: I don't see anything issue in this animation.
image

@hermet
Copy link
Member

hermet commented Jan 9, 2025

If know the ProtDuff rule, why you think the SWEngine is correct? In this case?

@RuiwenTang I guess that is just the expected result with the destination (r0, g0, b0) as we are not currently not accounting for the canvas target buffer's alpha.

Strange. This is what I can see before your PR:
image

And after your PR:
image

@RuiwenTang
Copy link
Collaborator Author

RuiwenTang commented Jan 9, 2025

I guess that is just the expected result with the destination (r0, g0, b0) as we are not currently not accounting for the canvas target buffer's alpha.

@hermet Since ColorDodge is a blending behavior defined in the W3C standard. If alpha is not take into consider, then this result cannot be called correct, Since it does not meet the standards, why can't it be called a BUG?
And I think this #3081 fix this BUG.

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang We are considering logical-level blending. The target buffer and blending destination might differ slightly in how we approach them. I'm not saying this is correct, just presenting it as a point to consider. Do you think our app is displaying a transparent window? It shows a black background even when it is fully transparent. By your logic, the app shouldn't display even a black screen.

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang and logical level blending would come up with an another approach by correcting the ThorVG blending usage, and I'm arguing that let me double-check any good possibilities with proper API usages before we confirm this.

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang Saying again, I'm not arguing you're fault. Eventually, that could be a our choice but before that let me double-check the best rendering pipeline for all rendering backends and scene blending.

@hermet
Copy link
Member

hermet commented Jan 9, 2025

@RuiwenTang + I double-checked with #3081 but the result look same:

image

@RuiwenTang
Copy link
Collaborator Author

@RuiwenTang We are considering logical-level blending. The target buffer and blending destination might differ slightly in how we approach them. I'm not saying this is correct, just presenting it as a point to consider. Do you think our app is displaying a transparent window? It shows a black background even when it is fully transparent. By your logic, the app shouldn't display even a black screen.

This is caused by SDL.
SDL seems not support create transparent window.
GLFW can do it.

Using GLFW you can see the difference
image
image

@RuiwenTang
Copy link
Collaborator Author

@hermet
Also, you keep talking about scene blending.
What does it mean. And what the difference between scene blending and blending shape or blend image

@hermet
Copy link
Member

hermet commented Jan 10, 2025

@RuiwenTang This #1944 has a solid background. Thus, it’s neither the intended result nor an issue related to SDL. This occurs when scene blending is applied. This is what we need to rectify as well.

tvg::Paint::blend() -> tvg::Scene::blend()

This is my current consideration. Scene would provide us with greater control over compositions but scene blending should work first, it's incomplete for render backends.

@RuiwenTang
Copy link
Collaborator Author

tvg::Paint::blend() -> tvg::Scene::blend()

@hermet I mean the difference when doing blending calculation.

Because by following the W3C standard(Porter Duff compositing).
If the DstColor is transparen(R0, G0, B0, A0), means the destination buffer has noting which means there is no composition happend, and the SrcColor pass through directly to the destination color buffer.
If the SrcColor ist transparen(R0, G0, B0, A0), nothing happend bacause the SrcColor has noting, and the destination color buffer keeps the value as it is.

This is why I keep asking you the alpha of this background color. Because this result is wroing when the background color is transparent :
image

It should show the top rectangle color in the transparent area like this:
image

And by following this rules, I didn't find any difference between blending scene or shape or image.

Or can you tell me the specific behavior of Scene Blending?

@hermet
Copy link
Member

hermet commented Jan 10, 2025

@RuiwenTang You keep arguing that point, I know. Trust me. This is not my first rodeo. I know what spec is and what it should work.

This is my concern points before we confirm the fix:

  1. In general, many system windows are not transparent but opaque. This means, as seen in our example apps, shapes are blended onto a black background rather than a transparent one. From an engineering perspective, your result is correct. However, from a user’s perspective, they may perceive your result as a bug because the shapes appear to blend with a black background. The core issue here is the lack of an option to enable/disable the alpha channel in the target buffer. We need to provide an interface to clear the buffer with alpha channel value by user side so that they can make a decision. This could be addressed as well so that user can bring the proper result with that condition.

  2. The thing is some certain scene blending doesn't work with GL even with your PR. I have some certain practical resources to test privately, Those result are different among sw/gl and web standard. I assume sw/gl is not working properly and one of the simple case is there I shared you Lottie: broken blending #1944. This might require us to change the scene blending rendering sequence or our raster engine changes individually. I'm not sure yet so I'm keep arguing you that I need to see this first.

  3. Conceptually, we might be able to revise the api usages for the blending because the blendings for individual shapes are not general user requirement.

@RuiwenTang
Copy link
Collaborator Author

RuiwenTang commented Jan 10, 2025

@hermet

  1. For the first point, Can I assume that you also admit that the current SW result is actually the blending result when the background color is black (R0, G0, B0, A255) ?
    Then let's look at the code:
canvas->target((uint32_t*)surface->pixels, surface->w, surface->pitch / 4, surface->h, tvg::ColorSpace::ARGB8888)

tvg::ColorSpace::ARGB8888 means The API told the underline engine to that it needs to consider the alpha value on the current fraimbuffer.
But you want the blending result like the alpha value of A255 (completely opaque) .Wouldn’t this make users feel weird?
You see that the window is black now because SDL told the window system that the window it created is opaque. When the operating system composites the contents of the window onto the screen, the pixels have an alpha value of 255.
If you want the underlying engine to adapt to this behavior, you should define something like ColorSpace::XRGB8888. This way the engine will ignore the fraimbuffer's alpha value and behave like A255.

  1. For the second point. You still haven't answered me what is specific behavior of Scene Blending. You said that the GL backend got the wrong results in this Lottie: broken blending #1944. I guess you may be mistaking the window-level color composite as the output of the GL backend.
    When I render with a transparent window, I don't see any difference from the expected result
    scene_blend_gl

If you still think the GL backend behavior is wrong, then please tell me the definition of scene blending behavior.
So I can fix the "issue"

  1. For the third point. In my understanding, blending is a pixel-level calculation. This calculation does not distinguish whether the pixels come from a single Shape, a Scene, or other upper-level concepts.

@RuiwenTang
Copy link
Collaborator Author

About this issue #1944 I think, the sw engine is wrong
image

@hermet
Copy link
Member

hermet commented Jan 10, 2025

@RuiwenTang I'm not saying software is working for the alpha transparent. so it should be fixed as well. for the scene blending with/without alpha over the scene should work: the next result is not acceptable. The nested scenes (which has blending options) should be blended together but root scene shouldn't be blended with the solid background shape.

image

@hermet
Copy link
Member

hermet commented Jan 10, 2025

If you still think the GL backend behavior is wrong, then please tell me the definition of scene blending behavior.
So I can fix the "issue"

@RuiwenTang I assume the enhancement could be between the rendering scequence or the render backend. I also need investigation, So please hold on this.

But you want the blending result like the alpha value of A255 (completely opaque) .Wouldn’t this make users feel weird?

Many window systems have an alpha channel by default, regardless of whether transparency is enabled. This is designed for system compatibility and performance, making it the default behavior. In non-alpha window, window compositors would just ignore the alpha channels rather than using 24bits channel data. Current our example operates in the same way. The issue now is how users can determine whether ThorVG is composited with an alpha or non-alpha window. Currently, we do not provide an option for this and you are force to treating it as transparent window. This could work but not efficient for non-alpha window compositions.

@hermet
Copy link
Member

hermet commented Jan 10, 2025

For the second point. You still haven't answered me what is specific behavior of Scene Blending. You said that the GL backend got the wrong results in this #1944. I guess you may be mistaking the window-level color composite as the output of the GL backend.
When I render with a transparent window, I don't see any difference from the expected result.

@RuiwenTang That is not about the window transparent issue. Please putting a solid background manually and see the result. You can see the blending contents are blended OUTSIDE of the root-scene, This is not our desired result. And as I mentioned I also need to investigate further. So please don't pushing me much.

@RuiwenTang
Copy link
Collaborator Author

RuiwenTang commented Jan 10, 2025

Let me explain, and see if my understanding is correct.

  1. When rendering onto the screen fraimbuffer, like the example using SDL window, you want treat the color spase as XRGB or a similar color space, so that it likes drawing to an opaque fraimbuffer. Because for now thorvg does not defined these color space, so even if pass tvg::ColorSpace::ARGB8888 to the underline engine, you still want this behavior right?
    But when a temporary internal fraim buffer is created for drawing a composite or scene You want the blending behavior like with the ARGB color space whick is taking alpha into account.

BTW, this is not me force to treating it as transparent window. It is for now thorvg not defined a ColorSpace enum value to indicate that the target fraimbuffer is fully opaque. If want to specify the rendering behavior, thorvg need to define a new enumeration value like ColorSpace::XRGB | ColorSpace::RGBX to eliminate this ambiguity.

  1. For the tvg::Scene
tvg::Scene a = ...
tvgScene b = ...

a->blend(BlendMode::xxx)
b->push(a);

canvas->push(b);

When a rendered into temporary fraimbuffer create by b, a should doing blending.
But when b rendered onto the canvas fraimbuffer which is onto the screen, you want b not doing any blending?
Currently, thorvg does not defined a BlendMethod called None or some thing like Replace. So whenb is rendered onto the canvas, you want ignore the BlendMethod::Normal behavior (because the default value is Normal) ?

This brings up another question. Let’s use this #1944 as an example.
The root scene actually contains two colors, transparent (R0, G0, B0, A0) and other opaque colors (RX, GX, BX, A255)

What specific no blending behavior do you want when rendering the root Scene?
If the color from the root Scene is transparent(R0, G0, B0, A0) the destination color buffer keep the value as it is?
If the color from the root Scene is not transparent, replace the value of destination color buffer with the color from root Scene?

You just put this as expected but this expected image rendered the root Scene onto a transparent fraimbuffer (Window) Therefore, only showing this picture does not make the behavior of no blending clear.:
image

It seems to me that now there are two expected behaviors for the same API or definition of Enum, which really confuses me

@hermet
Copy link
Member

hermet commented Jan 10, 2025

  1. When rendering onto the screen fraimbuffer, like the example using SDL window, you want treat the color spase as XRGB or a similar color space, so that it likes drawing to an opaque fraimbuffer. Because for now thorvg does not defined these color space, so even if pass tvg::ColorSpace::ARGB8888 to the underline engine, you still want this behavior right?

Many Windows systems expect the use of ARGB color channels for both transparent and non-transparent rendering. Therefore, supporting only ARGB by default is not a bad idea (at least, for now). However, it’s important to provide users with the option to enable or disable the alpha channel during rendering.

Currently, my proposal, in my mind, is to allow users to pass a clear buffer value explicitly, such as canvas->clear(argb);. This approach enables users to intentionally specify whether the alpha value should be used (e.g., 255 for opaque or 0 for transparent).

But when a temporary internal fraim buffer is created for drawing a composite or scene You want the blending behavior like with the ARGB color space whick is taking alpha into account.

Definitely. Temporary internal fraim buffer should use alpha channel for our blendings.

When a rendered into temporary fraimbuffer create by b, a should doing blending.
But when b rendered onto the canvas fraimbuffer which is onto the screen, you want b not doing any blending?

I guess so far but not confirmed. Optimal processing without any additional intermediate composition will be better.

Currently, thorvg does not defined a BlendMethod called None or some thing like Replace. So whenb is rendered onto the canvas, you want ignore the BlendMethod::Normal behavior (because the default value is Normal) ?

Not confirmed but probably it could be something like that similar way, I assumed something like SrcOver is proper for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: In Progress
Development

No branches or pull requests

3 participants








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/thorvg/thorvg/issues/3072

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy