WIP: UI: Automatic Text Contrast for Overlays #121239

Closed
Harley Acheson wants to merge 1 commits from Harley/blender:TextShadowContrast into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Member

Automatic text color and shadows to give contrast for text overlays.


This PR changes a few simple things:

BLF_shadow currently sets both the shadow strength and color. This PR alters it so that the shadow_color is optional, and is only set if is supplied. This means we can call this function to only change the strength without affecting the current shadow color.

BLF_draw_default_shadowed is altered similarly. It gains an optional shadow_color that is null by default, and this is what is passed to BLF_shadow. This way we can set the shadow color once and then later call BLF_draw_default_shadowed and have it use the same shadow color. The text color is already like this: we set it once and it stays like that until we change it.

With the above changes it means we can manufacture a text color and shadow color once and it will be used by all the overlay functions. These colors are picked based on the brightness of the 3DView background color, obtained from ED_view3d_background_color_get. If dark it uses white as text color with black shadow, if light is uses dark text with shadow color the same as the background color.

Set to WIP as I haven't tested this much yet.

image

Separately, because of a similar change in #121222, this PR also alters draw_vertical_scale_indicators. This is used to draw the text in the vertical axis of Graph Editor. This PR changes it to use the background color as shadow rather than a hard-coded black.

Automatic text color and shadows to give contrast for text overlays. --- This PR changes a few simple things: `BLF_shadow` currently sets both the shadow strength and color. This PR alters it so that the `shadow_color` is optional, and is only set if is supplied. This means we can call this function to only change the strength without affecting the current shadow color. `BLF_draw_default_shadowed` is altered similarly. It gains an optional `shadow_color` that is null by default, and this is what is passed to `BLF_shadow`. This way we can set the shadow color once and then later call `BLF_draw_default_shadowed` and have it use the same shadow color. The text color is already like this: we set it once and it stays like that until we change it. With the above changes it means we can manufacture a text color and shadow color once and it will be used by all the overlay functions. These colors are picked based on the brightness of the 3DView background color, obtained from `ED_view3d_background_color_get`. If dark it uses white as text color with black shadow, if light is uses dark text with shadow color the same as the background color. Set to WIP as I haven't tested this much yet. ![image](/attachments/8263af35-ae64-4525-bc92-9dc75ed74512) Separately, because of a similar change in #121222, this PR also alters `draw_vertical_scale_indicators`. This is used to draw the text in the vertical axis of Graph Editor. This PR changes it to use the background color as shadow rather than a hard-coded black.
Harley Acheson added 1 commit 2024-04-30 03:05:58 +02:00
9a75b82ec4 WIP: UI: Automatic Text Contrast for Overlays
Automatic text color and shadows to give contrast for text overlays.
Harley Acheson added this to the User Interface project 2024-04-30 03:10:13 +02:00
Harley Acheson requested review from Aras Pranckevicius 2024-04-30 03:10:44 +02:00
Aras Pranckevicius reviewed 2024-04-30 09:14:09 +02:00
@ -273,3 +273,3 @@
* Take care that shadow need to be enable using #BLF_enable!
*/
void BLF_shadow(int fontid, int level, const float rgba[4]) ATTR_NONNULL(3);
void BLF_shadow(int fontid, int level, const float rgba[4] = nullptr) ATTR_NONNULL(3);

You probably want to remove ATTR_NONNULL(3) since the argument very much allows and defaults to null now :)

You probably want to remove `ATTR_NONNULL(3)` since the argument very much allows and defaults to null now :)

Overall nice, except I'm not quite sold on the white shadow color (I tried that in my other PR initially too, but the brain does not equate "bright color" as "this is a shadow", it looks more like "this is some glow").

In this PR, it does have some bright shadows which also looks similarly strange to me
image

I'm thinking that to be "really nice", maybe when the shadow color is brighter than the text color, it should actually try to do an "outline", not "a blur". But that sounds like a somewhat more involved change that would need a shader side change as well.

Overall nice, except I'm not quite sold on the white shadow color (I tried that in my other PR initially too, but the brain does not equate "bright color" as "this is a shadow", it looks more like "this is some glow"). In this PR, it does have some bright shadows which also looks similarly strange to me ![image](/attachments/bb9cfc8b-ff8a-4d69-8fe4-0babf9294377) I'm thinking that to be "really nice", maybe when the shadow color is brighter than the text color, it should actually try to do an "outline", not "a blur". But that sounds like a somewhat more involved change that would need a shader side change as well.
124 KiB
Author
Member

I'm thinking that to be "really nice", maybe when the shadow color is brighter than the text color, it should actually try to do an "outline", not "a blur". But that sounds like a somewhat more involved change that would need a shader side change as well.

Yes, a solid outline does always work better, but I (personally) don't have any good solutions for that.

I have tried that at the glyph creation stage. One attempt used FreeTypes "embolden" to expand out in all directions without otherwise changing the spacing. This worked well enough for this purpose. I also tried "stroking" (LOL), which involves adding a wider line around the glyph parts. This worked better, but both ways meant that I had to draw twice for each letter. Yes, I know we are now drawing twice with each letter but it is at least the exact same glyph, where this was something else that needed to be created and cached on its own (the same way if the letters differed in boldness, etc).

But when testing it there was in increase in contrast versus our shadowing, and it didn't look like a glow when lighter.

Could we do similar on the shader? Fairly certain that we have the ability to draw the characters at a different size than they are actually rendered (FontBLF ->aspect), although not sure I've seen us use this anywhere good (we do bad things with it in Geometry Node frame titles). But maybe just drawing the glyph at a larger size on the shader, with some magical left shift, could get us a solid version to use as a base for the regular glyph?

> I'm thinking that to be "really nice", maybe when the shadow color is brighter than the text color, it should actually try to do an "outline", not "a blur". But that sounds like a somewhat more involved change that would need a shader side change as well. Yes, a solid outline does always work better, but I (personally) don't have any good solutions for that. I have tried that at the glyph creation stage. One attempt used FreeTypes "embolden" to expand out in all directions without otherwise changing the spacing. This worked _well enough_ for this purpose. I also tried "stroking" (LOL), which involves adding a wider line around the glyph parts. This worked better, but both ways meant that I had to draw twice for each letter. Yes, I know we are now drawing twice with each letter but it is at least the exact same glyph, where this was something else that needed to be created and cached on its own (the same way if the letters differed in boldness, etc). But when testing it there was in increase in contrast versus our shadowing, and it didn't look like a glow when lighter. Could we do similar on the shader? Fairly certain that we have the ability to draw the characters at a different size than they are actually rendered (FontBLF ->aspect), although not sure I've seen us use this anywhere good (we do bad things with it in Geometry Node frame titles). But maybe just drawing the glyph at a larger size on the shader, with some magical left shift, could get us a solid version to use as a base for the regular glyph?

I could try implementing an "outline" part of the text shader, which is not that different from a 5x5 blur, just with somewhat different weights. I'll play around with that and will report back, ok?

I could try implementing an "outline" part of the text shader, which is not that different from a 5x5 blur, just with somewhat different weights. I'll play around with that and will report back, ok?
Author
Member

I could try implementing an "outline" part of the text shader, which is not that different from a 5x5 blur, just with somewhat different weights. I'll play around with that and will report back, ok?

That would be awesome! Although my (possibly wrong) reading is that we communicate the shadow size in a weird way to the shader. We pass a glyph-size int[2] where if both items are positive there is no shadow, but negative x and it is the 3pixel shadow, negative both to get the 5pixel shadow.

So maybe we could just make the current 3x3 shadow be an unblurred outline?

Or better we could add a new shadow level of "1" that uses positive x with negative y. If done well enough we could use this alone for all overlays and we'd no longer need my dumb BLF_draw_default_shadowed at all.

> I could try implementing an "outline" part of the text shader, which is not that different from a 5x5 blur, just with somewhat different weights. I'll play around with that and will report back, ok? That would be awesome! Although my (possibly wrong) reading is that we communicate the shadow size in a weird way to the shader. We pass a glyph-size int[2] where if both items are positive there is no shadow, but negative x and it is the 3pixel shadow, negative both to get the 5pixel shadow. So maybe we could just make the current 3x3 shadow be an unblurred outline? Or better we could add a new shadow level of "1" that uses positive x with negative y. If done well enough we could use this alone for all overlays and we'd no longer need my dumb BLF_draw_default_shadowed at all.

is that we communicate the shadow size in a weird way to the shader

Yes it is weird, and could be done in a much nicer way. All that "pass extra bits via negative numbers" sounds like very dubious optimization, if you ask me. Possibly makes the shader a tiny bit slower, in fact :) What I would do, is to stop all that and just pass an integer to the shader for "shadow mode enum".

> is that we communicate the shadow size in a weird way to the shader Yes it is weird, and could be done in a much nicer way. All that "pass extra bits via negative numbers" sounds like very dubious optimization, if you ask me. Possibly makes the shader a tiny bit slower, in fact :) What I would do, is to stop all that and just pass an integer to the shader for "shadow mode enum".
Author
Member

I mentioned earlier that using FreeType embolden "worked well enough for this purpose." I found an old capture of those tests:

image

As shown it definitely worked good enough as a sharp outline. Blown up large you can see a defect with the "D" because of the way it moves the vector points.

And reversed it looks better than having a soft shadow:

image

I mentioned earlier that using FreeType embolden "worked _well enough_ for this purpose." I found an old capture of those tests: ![image](/attachments/cf206ff4-ec11-40b5-bcb1-029c89e2941f) As shown it definitely worked good enough as a sharp outline. Blown up large you can see a defect with the "D" because of the way it moves the vector points. And reversed it looks better than having a soft shadow: ![image](/attachments/21ecdb92-c0ff-4b07-9fad-983fe09e0c3a)

What I have now looks like this:

image
image
image

i.e. this is based on the color choosing logic of this PR, but instead of various shadowing combinations, the "shadow" is actually a 1px outline by doing 3x3 dilation in the text shader (I tried 5x5 dilation too, but that feels "too much").

Is your thinking that the whole BLF_draw_default_shadowed thing (where it draws two shadows - 3x3 centered and 5x5 slightly offset) could/should be replaced by just a single outline?

What I have now looks like this: ![image](/attachments/673a6e3f-3a1e-48fd-8d18-b77de49e0a93) ![image](/attachments/8ad8dbfc-78fe-4185-9291-9aad111418e5) ![image](/attachments/2f46c5f2-0a43-4997-8abe-bdfa2a7a6066) i.e. this is based on the color choosing logic of this PR, but instead of various shadowing combinations, the "shadow" is actually a 1px outline by doing 3x3 dilation in the text shader (I tried 5x5 dilation too, but that feels "too much"). Is your thinking that the whole `BLF_draw_default_shadowed` thing (where it draws _two_ shadows - 3x3 centered and 5x5 slightly offset) could/should be replaced by just a single outline?
Author
Member

What I have now looks like this:

Wow, that looks as good as when I was was (attempting) to make outlined glyphs in Freetype. My results were good still required drawing twice and with different glygh caches so not worth it.

the "shadow" is actually a 1px outline by doing 3x3 dilation in the text shader (I tried 5x5 dilation too, but that feels "too much")

That’s what found as well.

Is your thinking that the whole BLF_draw_default_shadowed thing (where it draws two shadows - 3x3 centered and 5x5 slightly offset) could/should be replaced by just a single outline?

At the very least that default_shadowed thing could go away but unsure of how. Using our current shadow width would simple - using this a “1”?

> What I have now looks like this: Wow, that looks as good as when I was was (attempting) to make outlined glyphs in Freetype. My results were good still required drawing twice and with different glygh caches so not worth it. > the "shadow" is actually a 1px outline by doing 3x3 dilation in the text shader (I tried 5x5 dilation too, but that feels "too much") That’s what found as well. > Is your thinking that the whole `BLF_draw_default_shadowed` thing (where it draws _two_ shadows - 3x3 centered and 5x5 slightly offset) could/should be replaced by just a single outline? At the very least that default_shadowed thing could go away but unsure of how. Using our current shadow width would simple - using this a “1”?

At the very least that default_shadowed thing could go away but unsure of how. Using our current shadow width would simple - using this a “1”?

Right now in my hacky code it is "6". TBH I don't quite like the current "level" where the only valid options are 0, 3 or 5, that feels more like enum and less like "shadow level". In my mind, ideally it would be changed to something like:

  • C++ code: instead of "int level", it would take an enum ShadowType { Simple, Blur3x3, Blur5x5, Outline }
  • Python API: continues to accept integer 0, 3, 5 amounts (which map to appropriate levels), but also accepts string enum-like values that map to the C++ enum values.

One "uhh" thing left is that "outline" does not feel like a "shadow" much.

> At the very least that default_shadowed thing could go away but unsure of how. Using our current shadow width would simple - using this a “1”? Right now in my hacky code it is "6". TBH I don't quite like the current "level" where the only valid options are 0, 3 or 5, that feels more like enum and less like "shadow level". In my mind, ideally it would be changed to something like: - C++ code: instead of "int level", it would take an `enum ShadowType { Simple, Blur3x3, Blur5x5, Outline }` - Python API: continues to accept integer 0, 3, 5 amounts (which map to appropriate levels), but also accepts string enum-like values that map to the C++ enum values. One "uhh" thing left is that "outline" does not feel like a "shadow" much.

I didn't know how to make a PR that builds upon your PR, so I created a new one: #121383. Let me know if 1) it makes sense, and 2) I should redo it in some other way.

I didn't know how to make a PR that builds upon your PR, so I created a new one: #121383. Let me know if 1) it makes sense, and 2) I should redo it in some other way.
Author
Member

Closing in favor of #121383

Closing in favor of #121383
Harley Acheson closed this pull request 2024-05-05 23:18:34 +02:00

Pull request closed

Sign in to join this conversation.
No reviewers
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#121239
No description provided.