Skip to content

Conversation

@Johni0702
Copy link
Collaborator

Its alpha result part (which isn't specified explicitly, so matches the rgb result part) doesn't make any sense.

dst is the color of the render target / framebuffer, src is the color of the thing being rendered.
BlendState.NORMAL is
result.rgb = src.rgb * src.a + dst.rgb * (1-src.a)
result.a = src.a * src.a + dst.a * (1-src.a)
The rgb part makes sense if you're working with regular alpha blending.
However the alpha part does not because it means that if you e.g. draw a 50% opaque quad (src.a = 0.5) on a fully opaque background (dst.a = 1), you'll suddenly end up with a partially translucent framebuffer (result.a = 0.5 * 0.5 + 1 * (1-0.5) = 0.25 + 0.5 = 0.75), even though we'd expect it to be opaque given the previous background was already opaque.
Similarly you get incorrect results rendering a 50% opaque quad on a 50% opaque background; you'd expect the combination to be 75% opaque (result.a = 0.75) but it's actually just 50% opaque (result.a = 0.5 * 0.5 + 0.5 * (1 - 0.5) = 0.25 + 0.25 = 0.5).

The correct equation to use is result.a = src.a * 1 + dst.a * (1-src.a) (which makes sense if you think of alpha as "how much it obscures the background").
In the first scenario this gives result.a = 0.5 * 1 + 1 * (1-0.5) = 0.5 + 0.5 = 1 as expected.
In the second scenario this gives result.a = 0.5 * 1 + 0.5 * (1-0.5) = 0.5 + 0.25 = 0.75 as expected.

This PR therefore deprecates BlendState.NORMAL in favor of a new BlendState.ALPHA which uses the correct blending (I've called it ALPHA because it's standard "alpha blending"; considered using DEFAULT but that might be confusing because MC only started using it with 1.16, while older versions apparently didn't really know what they were doing either).

This PR also adds a BlendState.PREMULTIPLIED_ALPHA which takes the same equation parameters and also applies them to the rgb part. This is a generally superior way of doing blending (e.g. it works correctly when compositing different partially translucent intermediate render results), despite it being not as well known as conventional blending. See these blog posts for explanations: 1 2 3

@Johni0702 Johni0702 merged commit ea37319 into master Jun 11, 2025
1 check passed
@Johni0702 Johni0702 deleted the feature/blendstate-proper-alpha-result branch June 11, 2025 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants