Opened 7 years ago

Last modified 2 years ago

#1315 assigned enhancement

Support volume mesh line widths > 1

Reported by: Elaine Meng Owned by: Tom Goddard
Priority: normal Milestone:
Component: Volume Data Version:
Keywords: Cc: Tristan Croll
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description (last modified by Tom Goddard)

The following bug report has been submitted:
Platform:        Darwin-17.7.0-x86_64-i386-64bit
ChimeraX Version: 0.8 (2018-09-15)
Description
volume command "lineThickness" option does not thicken mesh lines

same option in Chimera works on same computer

OpenGL version: 4.1 INTEL-10.36.19
OpenGL renderer: Intel Iris Pro OpenGL Engine
OpenGL vendor: Intel Inc.

Attachments (6)

c114_cx1_lw2.png (1.4 MB ) - added by Tom Goddard 5 years ago.
ChimeraX left 1 pixel thickness, Chimera 1.14 right 2 pixel thickness, 1a0m
c114_cx1.png (1.3 MB ) - added by Tom Goddard 5 years ago.
ChimeraX and Chimera with 1 pixel thickness look very similar.
grating.png (158.6 KB ) - added by Tom Goddard 5 years ago.
ChimeraX simple grating
grating_const_thick.png (160.2 KB ) - added by Tom Goddard 5 years ago.
ChimeraX simple grating with normal vector constant width correction
grating_perp.png (139.0 KB ) - added by Tom Goddard 5 years ago.
ChimeraX simple grating omitting places where surface parallel to grating
thick_smooth.png (1.5 MB ) - added by Tom Goddard 5 years ago.
Comparing macOS retina 1 pixel lines to thicker lines obtained by enabling smoothing without blending.

Change History (17)

comment:1 by pett, 7 years ago

Component: UnassignedVolume Data
Milestone: 1.0
Owner: set to Tom Goddard
Platform: all
Project: ChimeraX
Status: newassigned
Summary: ChimeraX bug report submissionvolume command "lineThickness" option does not thicken mesh lines

comment:2 by Tom Goddard, 7 years ago

The volume command lineWidth option does nothing. Unfortunately the modern OpenGL graphics standard (core profile) used by ChimeraX only supports linewidth 1 while older OpenGL standard (legacy profile) supports linewidths > 1 (usually up to 10 pixels). It is quite complex to support linewidths > 1 in modern OpenGL — it requires drawing triangles instead of lines and special GPU shader code. In the future we are may switch ChimeraX graphics from OpenGL to Vulkan which is the next generation of OpenGL and Vulkan allows linewidth > 1.

For now I will remove the lineWidth option from the volume command.

comment:3 by Tom Goddard, 7 years ago

I have removed the lineThickness (incorrectly called lineWidth in previous comment) and outlineBoxLinewidth options from the volume command.

comment:4 by Tom Goddard, 7 years ago

Milestone: 1.0
Summary: volume command "lineThickness" option does not thicken mesh linesSupport volume mesh line widths > 1
Type: defectenhancement

In the future if we switch from OpenGL graphics to Vulkan it may be easy to get linewidth > 1. Or it may not. Although Vulkan has an API to request line widths > 1 it is unclear whether drivers will support that.

comment:5 by Tom Goddard, 5 years ago

I looked at a few methods to allow line thickness > 1 pixel. I am particularly interested in the case of retina or high-dpi displays (e.g. 4K displays) where single pixel width lines are narrow and faint. None of the methods I considered seem feasible. But here is a summary.

First I'll attach two images that compare the appearance of line thickness 1 versus 2 pixel using Chimera to show the two pixel width (with legacy OpenGL context). I also attach an image comparing Chimera and ChimeraX with 1 pixel lines to show that they look very similar (I could not get exactly the same view in Chimera and ChimeraX).

Here are the 3 methods for line thickness > 1 that I looked at. First I tried a method that would only work for volumes that shows the volume surface and slices it through a grating along the 3 axes. In other words keep pixels with mod(x,spacing) <= thickness or mod(y,spacing) <= thickness or mod(z,spacing) <= thickness. It is very simple, just a couple extra lines in the fragment shader. But it is pretty ugly. The ribbons of surface are sometimes very wide where the surface is nearly parallel the grating plane. I'll attach an image of that. I then tried to make the ribbon width more uniform by using the surface normal vector. That improved appearance a bit but didn't work as well as expected because the surface normal I need is the triangle normal but current code only has the interpolated vertex normal. I then tried not showing the ribbons where the surface makes less than a 45 degree angle with the normal. That is not horrible, but the ribbon lines just end in places and it looks a bit tattered. With all these tests I used mesh lighting off because mesh lighting on looked worse. My conclusion was that while the grating method is simple, it is just uglier in appearance. I was excited to try it because it would allow closer mesh spacing than the volume grid spacing which could be nice. It also makes the mesh lines an (approximately) fixed width in Angstroms not pixels. It was interesting but a failure.

I looked at two other method that I did not try. The standard technique is to use a geometry shader that turns each line segment into two triangles facing the camera. It can work and look good. The joins of two segments can look bad for thick lines since a simple approach will make each segment have square ends. But for the common 2 pixel wide line that probably will look fine. The basic geometry shader is simple enough, maybe 20 lines of code. But the geometry shader sits between the vertex and fragment shaders so it would have to know about all the different variables that pass between vertex and fragment shaders (lighting normals, textures, clip planes...) and those variables differ based on what graphics features are being used. So its a real nightmare to pass all that stuff through. This looks like just too much complexity for two little gain.

A third method I considered but did not try is simply to render the mesh multiple times offset by a half pixel in maybe 6 directions to thicken up the lines. It would probably work but would be 6 times slower and that only gets thickness 2. To go to thickness 4 would take about 24 times slower. Probably fine for saving an image, but I am more interested getting thicker lines for interactive x-ray and cryo-EM model building where the meshes can be huge. So really slow methods don't look too attractive.

Another slow method might simply be to make the mesh lines box beams each with 8 triangles for use with no lighting so the edges are not too distracting. 8 times slower and joining the segments nicely might be painful. Computing the mesh triangles would slow changing contour level. Lots of sacrifices in performance for too little gain.

The bottom line is that OpenGL abandoned lines thicker than one pixel, and given the advent of high-dpi displays that really makes line drawing less useful with only 1 pixel lines. Getting good speed and appearance is very complex and still looks out of reach.

by Tom Goddard, 5 years ago

Attachment: c114_cx1_lw2.png added

ChimeraX left 1 pixel thickness, Chimera 1.14 right 2 pixel thickness, 1a0m

by Tom Goddard, 5 years ago

Attachment: c114_cx1.png added

ChimeraX and Chimera with 1 pixel thickness look very similar.

by Tom Goddard, 5 years ago

Attachment: grating.png added

ChimeraX simple grating

by Tom Goddard, 5 years ago

Attachment: grating_const_thick.png added

ChimeraX simple grating with normal vector constant width correction

by Tom Goddard, 5 years ago

Attachment: grating_perp.png added

ChimeraX simple grating omitting places where surface parallel to grating

comment:6 by Tom Goddard, 5 years ago

Here is a web page showing the images and duplicating the discussion above. Thought it might benefit other developers who hit this problem.

https://www.rbvi.ucsf.edu/chimerax/data/linewidth-aug2020/linewidth.html

comment:7 by Tom Goddard, 5 years ago

Cc: tic20@… added

Wide lines deprecated in core profile, not supported by Windows Nvidia

OpenGL core profile deprecated linewidths except 1 pixel, but did not eliminate them, and I read online a post from 2014 that said Linux and Windows with Nvidia or AMD drivers still supported wide lines in core profile. I tested on two Windows machines and both reported allowing only 1 pixel lines (GL_LINE_WIDTH_RANGE and GL_SMOOTH_LINE_WIDTH_RANGE = (1, 1)) and trying to call glLineWidth(3.0) gave an invalid value error. This was on a 2018 Windows laptop with Nvidia GTX 1070 and 2018 driver, and on a 2017 desktop with GTX 1080 Ti and recent driver. My only Linux system has Intel graphics and old posts said Intel and all Mac computers do not support lines wider than 1 pixel.

Enabling smooth lines with no blending thickens lines

When testing smooth lines with glEnable(GL_SMOOTH_LINE) which is currently not used in ChimeraX I found that if I don't use blending glDisable(GL_BLEND) then the lines appear much brighter and thicker on a retina display, maybe equivalent to 1.5 - 2 pixels wide and still have reasonable quality (with no smoothing). The blending is required to get the smoothing and by not using blending the fringe pixels on the line become full brightness making the line appear thicker. This may be a useful trick to allow a thicker line capability. It would prevent using smooth lines. But the appearance of smooth lines was not good on macOS, showing banding that was as bad as the unsmoothed lines. Screen captures show the smoothing is working but the gamma looks way off, so two pixels next to each other but off the center of the line are much dimmer than half the brightness of a single pixel centered on the line. This might be especially bad on macOS.

Vulkan wide line support, widespread but not on macOS

A quick look at gpuinfo.org shows that Vulkan drivers for Nvidia, AMD and Intel are supporting the wideLines capability and allow a line width range up to thousands of pixels wide. If ChimeraX used Vulkan that would provide wide lines on Windows and Linux. On macOS Apple does not support Vulkan and the open source MoltenVK project currently does not handle wide lines, although that project has a ticket saying Metal 3.0 introduced in 2019 was supposed to offer a wideLines capability.

comment:8 by Tom Goddard, 5 years ago

I attached an image showing how smooth lines with no blending makes the lines thicker.

by Tom Goddard, 5 years ago

Attachment: thick_smooth.png added

Comparing macOS retina 1 pixel lines to thicker lines obtained by enabling smoothing without blending.

comment:9 by Tom Goddard, 3 years ago

glLineWidth(w) with value w > 1 generates an INVALID_VALUE in fowardcompatible core contexts. I'm not sure if ChimeraX requests a forwardcompatible context.

"See OpenGL 4.6 API Core Profile Specificatio - E.2.1 Deprecated But Still Supported Features (https://registry.khronos.org/OpenGL/specs/gl/glspec46.core.pdf#page=700&zoom=100,168,758)
The following features are deprecated, but still present in the core profile. They may be removed from a future version of OpenGL, and are removed in a forwardcompatible context implementing the core profile.
Wide lines - LineWidth values greater than 1.0 will generate an INVALID_VALUE error"

Testing on Intel Mac (macOS 13.2.1) with Radeon Pro 580 graphics get linewidth ranges 1-1 for aliased and smooth. Same for M1 Mac (macOS 13.2.1).

print ('Allowed aliased line width range', GL.glGetFloatv(GL.GL_ALIASED_LINE_WIDTH_RANGE),

'smooth line width range', GL.glGetFloatv(GL.GL_SMOOTH_LINE_WIDTH_RANGE))

On Windows 10, Quadro P6000 graphics, driver NVIDIA 528.24, get aliased range 1-10, smooth 1-1, but disabling smooth and using glLineWidth(2) gives invalid value error (expected if forwardcompatible context is used).

GL.glDisable(GL.GL_LINE_SMOOTH)
GL.glLineWidth(2)

Also on Ubuntu 20.04 LTS with RTX 3090 graphics, driver nvidia 515.86.01 gives range 1-10 aliased, 1-1 smooth, and invalid value error on glLineWidth(2).

Checking Qt 6 documentation, QSurfaceFormat used to specify OpenGL context parameters by default gives a forward compatible context. But using

fmt.setOption(QSurfaceFormat.DeprecatedFunctions)

gives a non-forward compatible context allowing glLineWidth(w) with w > 1. Testing this on Mac (Intel and ARM) still only allowed width 1. On Windows and Linux systems with Nvidia graphics reported above glLineWidth(2) worked and rendered 2 pixel thick lines and reported line width ranges were 1-10 aliased, and 0.5-10 smooth.

So Nvidia systems on Windows and Linux could provide thick lines in ChimeraX. Unfortunately Mac systems with retina displays are where the thick lines are probably most needed and does not appear to support thick lines with a core OpenGL context.

It may be worth supporting thick lines on Windows and Ubuntu. Would be nice to test Intel and AMD graphics to see if they provide thick lines on Windows and Linux. On systems which only allow line width 1 ChimeraX could simply warn that only linewidth 1 is supported by your computer graphics.

comment:10 by pett, 3 years ago

Cc: Tristan Croll added; tic20@… removed

comment:11 by Tom Goddard, 2 years ago

Description: modified (diff)

Surprisingly on a MacBookPro with M1 graphics Chimera which uses a legacy OpenGL context shows wide mesh lines (tried width 5) on a volume mesh. But from the previous comment it seems that with a core context and allowing deprecated functions does not allow wide lines. So although the driver is able to do it, Apple does not enable it with a core OpenGL context.

Note: See TracTickets for help on using tickets.