MRtrix3 / mrtrix3

MRtrix3 provides a set of tools to perform various advanced diffusion MRI analyses, including constrained spherical deconvolution (CSD), probabilistic tractography, track-density imaging, and apparent fibre density
http://www.mrtrix.org
Mozilla Public License 2.0
294 stars 181 forks source link

Feature request: proper font rendering on HiDPI displays #1144

Open neurolabusc opened 7 years ago

neurolabusc commented 7 years ago

At the moment the text in mrview looks blurry. It would be great if it could be upgraded to support signed distance fonts. There is a nice javascript tool to generate these textures (and a sample program to render them). The screenshot below compares the fonts from mrview (top) and surfice (below, which uses this method). msdf

jdtournier commented 7 years ago

I think the issue here isn't so much with the font rendering - we rely on Qt's functionality for that, I doubt it's sub-standard. I think this is due to your display being a HiDPI (retina) display, which means the fonts need to be rendered at twice the nominal DPI value. You'll note the issue is only in the main OpenGL panel - it's fine for the adjacent UI element (at least I assume you're OK with how the 'Tractography' is rendered...?). It should be trivial to deal with, but Qt5's handling of HiDPI display does not make this easy (no functionality for this at all in Qt4, by the way), so it's been left as-is.

I tried to do something about this in past (see this branch), but never found the motivation to finish it - you'll note that branch is almost 5,000 commits behind... I'm not a macOS user, so it's difficult to test. Any input on that front would be appreciated... :wink:

neurolabusc commented 7 years ago

Feel free to close if you do not want to pursue. The current font is readable and users can always use an image editor to sharpen text for publication.

However, I do think QT's functionality predates the 2007 introduction of signed distance field fonts as well as the advent of high-DPI monitors. The beauty of SDF is that with a single texture you can map a font of any size and any rotation very rapidly with a simple GLSL shader. I suggest you look at this page which provides you with a simple webGL demo that demonstrates the scaling and rotation. This can help not only MacOS users, but also users of high-DPI screens on other operating systems, where the font can be stretched proportionally to DPI to avoid microscopic text (for example, with Surfice if you change the Window size, the font size scales nicely, and when you toggle Retina on and off it looks as good as it can given the pixels provided). By the way, the demo I link here is based on the basic single-channel SDF which will have blurry edges, whereas the previous post provides an equally easy to implement solution for the sharper multi-channel SDF technique. Because they only require a single texture per font, and a single shader, it is pretty easy to implement. It has very low computational load: the single texture lives in GPU memory and you only have to update the vertices when the text changes.

jdtournier commented 7 years ago

I do think QT's functionality predates the 2007 introduction of signed distance field fonts as well as the advent of high-DPI monitors.

It undoubtedly does - I have a feeling it's likely to be based on Freetype or similar technology. However, these dedicated font rendering engines are designed to produce high quality output, including hinting, etc. at the target resolution. I can definitely see the appeal of signed distance rendering for scalable fonts, but we don't currently need this - the font size is set at startup and held fixed thereafter (tunable via a config file option, which I note is currently not documented - I'll fix that in a tic). Since we render explicitly at the target resolution (at least on non-HiDPI displays), there should be no issues with scaling, and the approach should produce high quality font rendering.

But if it is indeed simple to support signed distance rendering with no additional dependencies, then it might be worth bearing in mind for future implementation. One slight issue is that you'd be stuck with the font we supplied. As things stand, the font used is the default system one. Not a huge deal, but hey...

jdtournier commented 7 years ago

Because they only require a single texture per font, and a single shader, it is pretty easy to implement. It has very low computational load: the single texture lives in GPU memory and you only have to update the vertices when the text changes.

I should add that this is also how mrview handles font rendering: we use Qt to generate the pixmap for all the characters, and load that to texture for later use.

neurolabusc commented 7 years ago

OK, I will close this issue. By the way, you can supply several pre-rendered fonts and let the user choose - for example the Surfice preferences allows you to select Ubuntu, Oxygen, Oswald, etc.

jdtournier commented 7 years ago

Actually, I don't think this should be closed - there's currently no issue open regarding the poor rendering on Retina displays. Let's keep this open, but I'll change the title to reflect the underlying problem...

neurolabusc commented 7 years ago

Perhaps a simpler solution would be to retain the current rendering, but detect the backingScaleFactor for MacOS (or perhaps here or here). The trick is to generate the texture at higher resolution but not alter the size they are drawn.

ifdef MRTRIX_MACOSX

    font_.setPointSize (MR::File::Config::get_int ("FontSize", round(10* scaling)));

else

    font_.setPointSize (MR::File::Config::get_int ("FontSize", 10));

endif

jdtournier commented 7 years ago

Something like that. Qt5 provides the devicePixelRatio() function to figure this out, so that bit's easy. But it depends on the display it's being rendered to, so we need to cater for the case where the application starts on a regular display (e.g. an external monitor) and is then dragged over onto a retina display (e.g. your laptop's screen). This is what the changes I'd pushed on that branch are about: the information about which screen is being rendered to needs to be passed to the font rendering code, so it can then use the appropriate texture. It's a bit annoying, but if we bring that branch up to date, I reckon there's not a lot more to do. It's just that I don't have access to a retina display...

bjeurissen commented 7 years ago

Sorry, was looking at this on my phone and accidently closed... I can test HiDPI on my iMac if you want.

jdtournier commented 7 years ago

That would be helpful. I was just looking at the changes that are still needed. I think I've got it worked out in my head, but it'll require a bit of work... I guess if you want to start by merging master into the retina_display branch and fixing all the conflicts, that would be a start :wink:

thijsdhollander commented 7 years ago

merging master into the retina_display branch

:rofl: Wait, let me get a bag of popcorn first. Maybe I'm getting things wrong, but this sounds like a very painful exercise, given how far back that branch goes...

thijsdhollander commented 7 years ago

the font size is set at startup and held fixed thereafter (tunable via a config file option, which I note is currently not documented - I'll fix that in a tic)

For reference: this is now documented since #1146, relevant commit being 7224a6fb0b2d023ab783ac0587e30681fdbb4e58.