Closed CryZe closed 2 years ago
The PR got reverted because people abuse the wrong alpha blending on text as a fake text border. Obligatory xkcd:
I don't mind it being broken on the text as much (though it bothers me every time I see it on someones stream), but game capture is majorly affected by this problem, where it probably shouldn't have been reverted. (Also apparently the image source is broken too)
I noticed you copied the image from your old PR. Are you sure this is still happening? From 27.1.3:
You did not zoom in / scale it up far enough, it only happens on the transparent pixels (however there's different text sources on the different operating systems, so maybe your OS is unaffected).
That weird rectangle inside the e
is an image source going from white on the left to transparent on the right... it does not look white to me.
Also someone somewhat confirmed that the vtuber application that people seem to be using is affected by this bug (through game capture) as well:
Here the white whiskers appear much darker when they are above the white background (where OBS does the blending) as opposed to when they are in front the cat (where the application does the blending).
And here LiveSplit being game captured (which is configured to not use any shadows or text border here) is having the same problem:
Sorry, I though you meant scale outside OBS, i.e. look closely.
I looked at the text source example, and the problem there is that the source image is in straight alpha, e.g. 1/1/1/0.5 instead of 0.5/0.5/0.5/0.5, so the Default bilinear filtering will not be mathematically correct. You should be able to work around this by enabling a scale filter on the source, which samples the text texture texels 1:1 and writes to a render target with premultiplied alpha, then scales into the canvas filtering with premultiplied colors. Any scale filter will fix the edge darkening, but Bilinear will match Default behavior in terms of filtering.
Hopefully the same workaround will work for game capture, but I haven't tested.
Making this work properly for the Default case seems like a drag. For game capture, it would mean running a full screen shader to convert from straight to premultiplied, which we don't want to pay for by default since most games are completely opaque. We could add a toggle, but every checkbox is more complexity.
EDIT: Could also do manual bilinear filtering in the shader to avoid the extra fullscreen pass, but the last time I tried that, it was even slower IIRC.
In theory, LiveSplit could render to a DXGI swapchain with premultiplied colors, and specify DXGI_ALPHA_MODE_PREMULTIPLIED, assuming it works as advertised since I've never tried it.
For game capture, it would mean running a full screen shader to convert from straight to premultiplied, which we don't want to pay for by default since most games are completely opaque.
There already is a checkbox for whether the source is even captured transparently in the first place, so it could just be tied to whether that is active.
Also are you sure this has anything to do with bilinear filtering? It seems to happen if it's a 1:1 transform too:
(Also consider the background behind the text, which is also various levels of semi transparent white, which shouldn't look like this)
In theory, LiveSplit could render to a DXGI swapchain with premultiplied colors, and specify DXGI_ALPHA_MODE_PREMULTIPLIED, assuming it works as advertised since I've never tried it.
I believe it does that, but I can check again.
Any scale filter will fix the edge darkening, but Bilinear will match Default behavior in terms of filtering.
The scale filter does nothing:
There already is a checkbox for whether the source is even captured transparently in the first place, so it could just be tied to whether that is active.
We don't want to pay an extra cost if they don't rescale the image though.
Also are you sure this has anything to do with bilinear filtering? It seems to happen if it's a 1:1 transform too:
There's the larger issue that OBS blends in linear space, which is what GPU/PNG specs want. Others cheat, e.g. web/GDI, either out of ignorance or power savings. Ultimately, we chose to be linear-correct going forward. A toggle to blend naively in sRGB-encoded space isn't impossible, but it's not just a few lines of code. Significant plumbing would be involved.
EDIT: This may or may not contribute to the issue, but I can dig a bit if you can share your LiveSplit files.
The scale filter does nothing:
You need to set a resolution other than None for that filter to work, but I meant the "Scale Filtering" setting if you right-click on the source itself. Either way should trigger an extra draw that avoids filtering colors with straight alpha though.
Also, is this regular LiveSplit? If you can share the splits/layout, I can try debugging that.
I am seeing similar issues with any sources containing alpha channels, including the edges of chroma keyed sources using the OBS Chroma key filter. Here is an exaggerated example using StreamFX Dynamic mask plugin. My scene sources are ordered as follows:
Since I am placing the same image on top of itself (with the top copy masked a bit), I would expect to not see the mask at all- it should just look like the original image. Instead I am getting a grey halo around the mask, in the area where alpha is "fuzzy" (neither 0 nor 1) as seen below:
In order to make sure the problem isn't in the dynamic mask plugin, I wrote a simple OBS shader to do exactly what this scene is doing- pick a top source that is masked, and a bottom source that is not, and combine them. And the result is exactly what I would expect- you cant see the mask at all. Here is a snippet of the shader code I am using, where InputA
is the dynamic-masked source (1. above) and Background
is the background source that we're putting InputA
over (2. above):
float4 pixel = InputA.Sample(maskSamplerA, v_in.uv);
float3 pixelRGB = float3(pixel[0], pixel[1], pixel[2]);
float4 bgPixel = Background.Sample(maskSamplerB, v_in.uv);
float3 bgPixelRGB = float3(maskPixel[0], maskPixel[1], maskPixel[2]);
float3 outputRGB = pixelRGB + bgPixelRGB * (1.0 - pixel[3]);
I've noticed that if the last line of my shader is:
float3 outputRGB = pixelRGB * pixel[3] + bgPixelRGB * (1.0 - pixel[3]);
I get the exact same result as using OBS to compose everything- the exact same fuzzy halo.
I've got a similar problem with browser source. I have a website which is transparent. It contains a div with css like this: {color: #000000; background: #ffffff33;} I expected it apperanced fully white background when the background is white and a little bit white when the background is black. But is get gray when background is white...
I see three issues here.
We should probably just close this out. If anyone still has an issue, please file a clean ticket, ideally with clear, minimal repro steps/assets.
No, the issue still exists and I still want it fixed. I'll try to create an executable for you to reproduce it.
Windows 10
27.1.1, 27.1.3
No black edge around text (27.1.1)
OBS produces a black edge around text (since 27.1.3)
Load the html page provided below as a browser source. Put a whilte color source below the browser source
Similar issue happed in browser source with transparency.
<html>
<body style="background-color: transparent; padding-top: 20px">
<span style="background-color: #fff; border-radius: 30px; padding: 20px">test</span>
</body>
</html>
A browser source loads this simple webpage with transparent background, over a white color source. Results shouldn't produce a black edge around the span element.
PS: The problem wasn't there at 27.1.1
There have a lot of changes in color handling with all the HDR work, is this issue still present?
If it is, please provide as close to exact reproduction steps as possible so that we can test if this is an expectation, if there is a workaround, or is a bug.
I just checked and with v28.0.3 the issue still exists:
Neither the foreground nor the background consist of any other color than white, there's no reason that there should be any darker pixels. This is an alpha blending bug that exists with almost all sources in OBS other than the browser source (where I guess it was so apparent that it got fixed a very long time ago). This may seem like a "minor issue", but this essentially means that only the browser source and other custom plugins can correctly visualize anything that's transparent. Game / window capturing a semi transparent window is essentially broken, which is a major blocker in me releasing support for semi transparent windows for LiveSplit.
Also the fix is super trivial, I could easily rebase my code and do a PR again, but I'm not sure "you want me to do a PR".
Could you try to right click the text source > Blending Method > SRGB Off?
~That somehow solves it?!~ I really don't think it should've though. That has nothing to do with sRGB and everything with how alpha is blended.
HOWEVER the problem still applies to game capture and toggling the blending method does not fix the problem there (this really suggests that all these code paths diverge a lot and none of the sources are at all consistent with each other).
everything with how alpha is blended.
Well honestly it's both things, but they are orthogonal, technically you could interpret the alpha as linear or sRGB and on top of that as premultiplied or "straight". Browsers and games / transparent windows are typically premultiplied (it's much faster to work with that and they never have a reason to do a pass to turn it back straight, also your window manager will assume them to be premultiplied too), which is what OBS incorrectly assumes to be straight alpha.
If I could guess I would say OBS internally has it exactly backwards where it does all blending in straight alpha even though premultiplied would be faster and almost all sources should be premultiplied anyway (and the only source where that's not the case, i.e. the image source, can easily do it once).
As the original report is resolved, marking as fixed.
No it's not??? Only if you activate some obscure unrelated feature it essentially bugs out even more and happens to start being correct by complete accident. If anything it's even more bugged now and nothing is resolved at all.
Also this issue wasn't even about the text source at all, that was just an easy example of how to reproduce it. Only the text source now bugs out enough with this unrelated workaround to remotely "work".
I could either update the opening post and you reopen this issue or I can open a new issue with more details I guess (though honestly you really don't need more details as the OP still reproduces just fine).
Operating System Info
Other
Other OS
All of them
OBS Studio Version
27.1.3
OBS Studio Version (Other)
No response
OBS Studio Log URL
No
OBS Studio Crash Log URL
No response
Expected Behavior
White Text on a white background shouldn't ever yield black pixels.
Current Behavior
There's lots of black / greyish pixels showing up on semi transparent pixels.
Steps to Reproduce
Anything else we should know?
THIS AFFECTS ALL SOURCES EXCEPT THE BROWSER SOURCE, EVEN IF THE TEXT SOURCE HAPPENS TO BEHAVE (IN SOME CIRCUMSTANCES) IT'S STILL A BUG WITH ALL OTHER SOURCES.
This was the original PR that fixed this: https://github.com/obsproject/obs-studio/pull/1578
It unfortunately got reverted.