-
Notifications
You must be signed in to change notification settings - Fork 162
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
Transparent GUI's controls are incorrectly blending with the parent GUI #1838
Comments
Also reproduced in 3.6.0, so it's a 3.6.0 bug. |
@AlanDrake Basically, this lets to pass a texture when you call BeginSpriteBatch, and the whole batch and all the nested sprites will be rendered on that texture target instead. You just have to remember that and adjust the transformation parameters for the batch accordingly: that is set batch offset 0,0 instead of gui.X,Y and so on. Made it work with Direct3D for now, next will do for OpenGL, and try to tidy the code. |
I tried it, but I see the GUI transparency is not being applied somehow, though it's being set to the new texture. |
This is strange, it works in a test game I've been using. Can you give an example of how do you test this? |
The 3.6 version of the Test Wretcher project, if you still have it. Current master applies transparency just fine to the gConsole GUI. |
Apparently the 3.5 (or 3.6?) version of the Wretcher had "Classic" gui render style set, which makes GUI draw in software mode, because it uses incorrect alpha blending. I haven't tried the ags4 version yet. But this also means that 3.* version of Wretcher cannot be used to test this change, unless you change "GUI rendering style" to "Proper alpha blending". |
Ah, that explains why I had never noticed the blending working differently on 3.x... I just wasn't using proper alpha blending. |
Updated the test branch with OpenGL supporting render targets; but I'm probably missing something, because the GUI images are now vertically mirrored. Either the sprites are drawn inverted along the y axis on the texture, or the texture is drawn inverted itself, not sure yet. Another thing that's missing is that Direct3D must release these "buffer" textures after window is resized, otherwise IDirect3DDevice9::Reset will fail. On another hand, I'm curious whether there's a way around that. |
Unfortunately current code does not work correctly. This is not seen while only GUI has transparency, because that transparency is applied to the final texture (used as a render target). But if you set transparencies to individual gui controls, this produces a weird effect where the control's image would blend with contents of a main backbuffer, and then pasted on top of the render target texture (or so it seems). Same effect takes place with both Direct3D and OpenGL renderers, which makes me think that I do exact same mistake in both cases, related to the use of the render targets. |
You bind to the framebuffer that is the GUI texture, do the drawing, and later you bind to the framebuffer that is the top on stack (screen). It looks correct following this tutorial. Maybe add an |
@ericoporto have found that there are alpha blend settings that may fix this problem. The code is experimental, but pushed to this branch for a test. It's for Direct3D at the moment, but supposedly similar thing may be done for OpenGL. In regards to the OpenGL inverting GUI, I suspect this may be related to the sprite rendering relying on either native-res surface size or window size when applying positions. This should be rewritten to use sprite batch's matrix instead. |
I believe the equivalent in OpenGL is something like |
Hm, on another hand, I realized that #1708 will be necessary for this regardless, because right now there are some global sprite batch settings being applied in every batch, that will conflict with ones rendered onto a texture. So I will try resolving that first. Hopefully that will also fix the OpenGL inversion problem, or at least make it simpler to deal with. |
So, back at this (after #1708 is resolved). The updated test branch: https://github.com/ivan-mogilko/ags-refactoring/tree/360--guitexturerenderfix3 Fixed inverted GUIs with OpenGL, and few minor things. Remaining problems:
|
I found a source of another error, which I initially attributed to the aforementioned alpha blending settings. But in the end I realized it's not that. The problem was that the GUI background with alpha channel and translucent parts was rendered as if alpha value was additionally decreased (more transparent than necessary). I figured out this is because the GUI background is still being blended with the texture buffer (which has some clear color), while what we need is to get it copied. The solution which I decided to try was to introduce "blend mode" for the sprite, similar to what @AlanDrake did in ags4, only with 1 special blend mode that does plain src copy: ivan-mogilko@c5aa232 So far from what I see there's one issue remaining, which we noticed randomly testing Dave Gilbert's new game "Old Skies". With this branch the options of the main menu appear missing a greenish "glow" (or have less of it); so they appear too sharp, or having more contrast than necessary. Following are two screenshots comparing the original and new look: What's interesting, this does not depend on whether the previous alpha blending settings are done or not. I thought this is too going to be fixed with this latest blend mode fix, but it was not, so there's something else missing or wrong. |
When reading the blending stuff, something that went over my head, but maybe you can make sense of, is the premultiplication of alpha with the colors, I am not sure how it works, but this seems to darken things when done incorrectly, just thought to mention in case it this helps. |
The above appears to be the same problem I was trying to fix with blend mode change; except I was thinking that copying gui background is enough. But same issue reoccurs if gui background is fully transparent while the buttons are translucent. EDIT: everything seem to be fine if the gui background has at least some color, that is - pixels with alpha above 0. |
Does using white vs black makes any difference? I mean because white is all 255, so the blending I think would maintain all range if this is the observed behavior, in case the premultiplication is impacting. |
Do you mean the color which is used to clear the surface? If so, then the white color gives an opposite, "lighter", effect. Overall, the root of the problem is that the sprite's color is blended with the surface, but we don't need it to blend with the surface at all, we need it to plain copy onto the surface. Here's the test game I am using: It has a GUI with a button, both with the same "gradient" sprites. Key 1 toggle the GUI's graphic, Key 2 toggles the button. It's very easy to see the difference between expected and the current branch. |
Uhm, I wonder if it makes sense testing this in AGS4 context, just to see
|
I don't see why rotation would not work, if it would be about rotating a single texture - that is what it currently does easily. |
Correct, one can only do so much with a single pass of blend modes. For perfect implementation we need to turn them into shaders. |
Hmm, I finally realized that was thinking about whole blending of multiple textures in a wrong way (maybe a case of a mental block), and now fully understand what that separate alpha operation setting was about, and possibly what the "premultiplied alpha" case is. So, now I get it, these settings make it so that the render target has the alpha component corresponding to all the sprites summed together, which makes the final alpha applied to the render target's pixels correct. (Assuming the render target itself was cleared to alpha 0.) But, because the sprite colors (RGB component) were combined using sprite's src alphas along the way, including the first pixels getting onto the render target itself, these colors, so to speak, already include alpha factor. This is what "premultiplied alpha" is, if i understand correctly. And that's a problem, because now, when we finally draw the texture, previously used as a render target, on screen itself, then all the colors will be multiplied by the alpha again, even though they were already multiplied by it. Previously I found a solution for this: use a special blend mode for this texture, where the source color is taken as is (not multiplied by its source alpha), but the destination color is still multiplied by inverse of a source alpha:
This works perfectly, but right until you apply GUI's Transparency to this texture: because it was not used when drawing onto the render target, its colors do not have it in them, and basically do not change, while the background colors increase. The result looks like the background begins to shine through the gui... sort of... anyway, it's wrong. Hypothetically, it might work if there were a way to do this:
but I do not know if such method even exists. So, this is where I'm currently at. NOTE: I cannot apply this GUI Transparency to the sprites I draw onto render target, because then they will use it for blending between each other, and I will be back at the problem I am trying to fix with render targets in the first place. |
Oh, wow, looks like this is possible:
EDIT: tested, and this seem to actually work. Updated the branch now: Now only need to code same thing for OpenGL. |
Alright, I updated with fixing OpenGL's blending, and fixing Direct3D failing to reset device when window size/mode changes. I think this resolves the issue, except maybe some minor things that we did not notice yet. I will be tidying the code and making proper PR now. |
Describe the bug
In hardware accelerated rendering, semi-transparent GUIs are being rendered incorrectly because controls are being blended with the underlying GUI graphics.
AGS Version
AGS 3.6 and AGS4 (D3D9 and OpenGL)
To Reproduce
Steps to reproduce the behavior:
Expected behavior

(correct, software rendering)
Screenshots

(wrong, D3D/OGL)
The controls shouldn't be mixing with what's underneath that is part fo the GUI.
The text was updated successfully, but these errors were encountered: