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

Support arbitrary background color with the DistanceField shader #448

Open
fgoujeon opened this issue Jun 9, 2020 · 8 comments
Open

Support arbitrary background color with the DistanceField shader #448

fgoujeon opened this issue Jun 9, 2020 · 8 comments
Milestone

Comments

@fgoujeon
Copy link
Contributor

fgoujeon commented Jun 9, 2020

Hi Mosra,

I get some unwanted, unaesthetic dark outlines when drawing white SDF (glyphs or images) over various colors, although outline range is {0.5, 0.5}:

sdf_current

This is due to the following line of the frag shader (DistanceFieldVector.frag):

/* Fill color */
fragmentColor = smoothstep(outlineRange.x-smoothness, outlineRange.x+smoothness, intensity)*color;

This result isn't surprising, as multiplying the whole color with the smoothstep causes in-between, semi-transparent pixels to be darker (as their R, G and B channels have lower values).

I get a much cleaner result by applying the smoothstep to the alpha channel only:

/* Fill color */
lowp float alpha = smoothstep(outlineRange.x-smoothness, outlineRange.x+smoothness, intensity);
fragmentColor = vec4(color.rgb, color.a*alpha);

Outcome:
sdf_fixed

This fix won't suffice however, because it causes all outlines to be much lighter than wanted (as you can see on the "PURITY ROOM" text at the bottom of the image, or on the corners (which are SDF images as well)). This behavior isn't surprising either, as the outline code consists of adding values to fragment color:

/* Outline */
if(outlineRange.x > outlineRange.y) {
    /* Doing *0.5 instead of /2.0 because the latter causes iOS / WebGL to
        complain that "Overflow in implicit constant conversion, minimum
        range for lowp float is (-2,2)" */
    lowp float mid = (outlineRange.x + outlineRange.y)*0.5;
    lowp float halfRange = (outlineRange.x - outlineRange.y)*0.5;
    fragmentColor += smoothstep(halfRange+smoothness, halfRange-smoothness, distance(mid, intensity))*outlineColor;
}

I've yet to understand this part of the shader (I'm not so fluent in shader coding) to come up with a proper fix. Hopefully you'll be able to find something simple?

@mosra
Copy link
Owner

mosra commented Jun 9, 2020

Hi, this artifact is usually due to a wrongly set up blending. What blending do you use? There's a difference between blending for non-premultiplied alpha and premultiplied alpha, and the change you've done above is basically changing from a premultiplied alpha workflow to a non-premultiplied alpha workflow. Details and sample code here: https://doc.magnum.graphics/magnum/classMagnum_1_1GL_1_1Renderer.html#a42c00dd07d227c8975b07e39ad3f6b09

TL;DR: I assume your blend function is SourceAlpha, OneMinusSourceAlpha; can you change it to One, OneMinusSourceAlpha and compare the result?


Cool graphics btw., is the game public? :)

@mosra mosra added this to the 2020.0a milestone Jun 9, 2020
@fgoujeon
Copy link
Contributor Author

fgoujeon commented Jun 9, 2020

I assume your blend function is SourceAlpha, OneMinusSourceAlpha

You guessed that right.

can you change it to One, OneMinusSourceAlpha and compare the result?

SDF rendering is indeed much better with this setting! However the rendering of my own shaders (here my rounded rectangle frag shader) is all broken:
Screenshot from 2020-06-09 16-11-33

Seems like I have much more to learn about OpenGL than I thought I already had. I'll see what I can do about it.

Sorry for the inconvenience and thank you very much for your kind help, once again.

Cool graphics btw., is the game public? :)

Thank you! Yes, the game is completely free and GPL-licensed. It's a kind of match-three game and you can play it directly here: http://ternarii.com/
I've credited your libraries in the About screen. I hope it's OK.

@mosra
Copy link
Owner

mosra commented Jun 9, 2020

A hack could be to use the non-premultiplied blending for the rectangle and premultiplied for the SDF things; a proper solution would be converting your shader to assume premultiplied alpha also.

Not sure if that helps, but colors with premultiplied alpha never have RGB channels a higher value than the alpha. So check your shader and do something like thing.rgb *= alpha where that's not done already. Useful resource for understanding premultiplied alpha: https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre and also one for understanding blend equations: https://www.andersriggelsen.dk/glblendfunc.php

@mosra
Copy link
Owner

mosra commented Jun 9, 2020

The game is fun, got to 23k before it got all filled up and I lost :D

Will mention it in the list of cool things for the next release if that's okay with you ;)

@fgoujeon
Copy link
Contributor Author

I've finally been able to grasp how premultiplied alpha works. It indeed makes things easier in some cases. Thank you very much for the hints.

The game is fun, got to 23k before it got all filled up and I lost :D

Not bad for a start ;). I'm glad you enjoy the game!

Will mention it in the list of cool things for the next release if that's okay with you ;)

That would be with great pleasure!

@mosra
Copy link
Owner

mosra commented Jun 10, 2020

Great!

I remember I wanted to add support for arbitrary background color in the DistanceField shader (instead of always 0x00000000_rgbaf), which should give the user a flexibility to control whether to use premultiplied alpha or not and also avoid the need for blending in some cases, so I'll keep this open until that's done.

@mosra mosra changed the title Unwanted outlines with Signed Distance Fields (SDF) Support arbitrary background color with the DistanceField shader Jun 10, 2020
@mosra mosra modified the milestones: 2020.0a, 2020.0b Jun 26, 2020
@mosra
Copy link
Owner

mosra commented Jul 2, 2020

@fgoujeon
Copy link
Contributor Author

fgoujeon commented Jul 2, 2020

@mosra Nice! Thanks again :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

No branches or pull requests

2 participants