{"action":"created","issue":{"url":"https://api.github.com/repos/Stellarium/stellarium/issues/131","repository_url":"https://api.github.com/repos/Stellarium/stellarium","labels_url":"https://api.github.com/repos/Stellarium/stellarium/issues/131/labels{/name}","comments_url":"https://api.github.com/repos/Stellarium/stellarium/issues/131/comments","events_url":"https://api.github.com/repos/Stellarium/stellarium/issues/131/events","html_url":"https://github.com/Stellarium/stellarium/issues/131","id":312119064,"number":131,"title":"Color banding artifacts make atmosphere ugly in low light","user":{"login":"10110111","id":6376882,"avatar_url":"https://avatars3.githubusercontent.com/u/6376882?v=4","gravatar_id":"","url":"https://api.github.com/users/10110111","html_url":"https://github.com/10110111","followers_url":"https://api.github.com/users/10110111/followers","following_url":"https://api.github.com/users/10110111/following{/other_user}","gists_url":"https://api.github.com/users/10110111/gists{/gist_id}","starred_url":"https://api.github.com/users/10110111/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/10110111/subscriptions","organizations_url":"https://api.github.com/users/10110111/orgs","repos_url":"https://api.github.com/users/10110111/repos","events_url":"https://api.github.com/users/10110111/events{/privacy}","received_events_url":"https://api.github.com/users/10110111/received_events","type":"User","site_admin":false},"labels":[{"id":92071566,"url":"https://api.github.com/repos/Stellarium/stellarium/labels/enhancement","name":"enhancement","color":"1d76db","default":true}],"state":"open","locked":false,"assignee":{"login":"guillaumechereau","id":107679,"avatar_url":"https://avatars3.githubusercontent.com/u/107679?v=4","gravatar_id":"","url":"https://api.github.com/users/guillaumechereau","html_url":"https://github.com/guillaumechereau","followers_url":"https://api.github.com/users/guillaumechereau/followers","following_url":"https://api.github.com/users/guillaumechereau/following{/other_user}","gists_url":"https://api.github.com/users/guillaumechereau/gists{/gist_id}","starred_url":"https://api.github.com/users/guillaumechereau/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guillaumechereau/subscriptions","organizations_url":"https://api.github.com/users/guillaumechereau/orgs","repos_url":"https://api.github.com/users/guillaumechereau/repos","events_url":"https://api.github.com/users/guillaumechereau/events{/privacy}","received_events_url":"https://api.github.com/users/guillaumechereau/received_events","type":"User","site_admin":false},"assignees":[{"login":"guillaumechereau","id":107679,"avatar_url":"https://avatars3.githubusercontent.com/u/107679?v=4","gravatar_id":"","url":"https://api.github.com/users/guillaumechereau","html_url":"https://github.com/guillaumechereau","followers_url":"https://api.github.com/users/guillaumechereau/followers","following_url":"https://api.github.com/users/guillaumechereau/following{/other_user}","gists_url":"https://api.github.com/users/guillaumechereau/gists{/gist_id}","starred_url":"https://api.github.com/users/guillaumechereau/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guillaumechereau/subscriptions","organizations_url":"https://api.github.com/users/guillaumechereau/orgs","repos_url":"https://api.github.com/users/guillaumechereau/repos","events_url":"https://api.github.com/users/guillaumechereau/events{/privacy}","received_events_url":"https://api.github.com/users/guillaumechereau/received_events","type":"User","site_admin":false},{"login":"gzotti","id":18099873,"avatar_url":"https://avatars1.githubusercontent.com/u/18099873?v=4","gravatar_id":"","url":"https://api.github.com/users/gzotti","html_url":"https://github.com/gzotti","followers_url":"https://api.github.com/users/gzotti/followers","following_url":"https://api.github.com/users/gzotti/following{/other_user}","gists_url":"https://api.github.com/users/gzotti/gists{/gist_id}","starred_url":"https://api.github.com/users/gzotti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gzotti/subscriptions","organizations_url":"https://api.github.com/users/gzotti/orgs","repos_url":"https://api.github.com/users/gzotti/repos","events_url":"https://api.github.com/users/gzotti/events{/privacy}","received_events_url":"https://api.github.com/users/gzotti/received_events","type":"User","site_admin":false}],"milestone":null,"comments":31,"created_at":"2018-04-06T21:08:31Z","updated_at":"2018-04-10T10:48:06Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"See the following screenshot in 1:1 scale to understand the problem:\r\n![screenshot of the problem](https://user-images.githubusercontent.com/6376882/38443916-e322450a-39dc-11e8-9d9e-56c8e2952975.png)\r\n\r\nThis banding can be smoothed by application of dithering. I've done a quick-and-dirty implementation of it just to see which places would need it, and below is a proof-of-concept patch I've come up with. I'm sure it can be improved, including a switch to toggle it on/off as well as enable/disable 6 BPP monitor support (which is currently an `#ifdef`). Also it might be better to simply do _all_ the rendering to a higher-precision FBO texture (e.g. with `GL_RGBA32F` format) and then simply dither this render target when blitting to screen. But at least this patch makes the image much nicer (see the screenshot after the diff).\r\n```diff\r\ndiff --git a/src/core/StelPainter.cpp b/src/core/StelPainter.cpp\r\nindex 529407e826..f3d66e5cc3 100644\r\n--- a/src/core/StelPainter.cpp\r\n+++ b/src/core/StelPainter.cpp\r\n@@ -2027,12 +2027,36 @@ void StelPainter::initGLShaders()\r\n \r\n \tQOpenGLShader fshader2(QOpenGLShader::Fragment);\r\n \tconst char *fsrc2 =\r\n+\"#version 120\\n\"\r\n+\"vec3 dither(vec3 c)\\n\"\r\n+\"{\\n\"\r\n+\"    const float bayerPattern[] = float[](\\n\"\r\n+\"        0,  32,  8, 40,  2, 34, 10, 42,  /* 8x8 Bayer ordered dithering  */\\n\"\r\n+\"        48, 16, 56, 24, 50, 18, 58, 26,  /* pattern.  Each input pixel   */\\n\"\r\n+\"        12, 44,  4, 36, 14, 46,  6, 38,  /* is scaled to the 0..63 range */\\n\"\r\n+\"        60, 28, 52, 20, 62, 30, 54, 22,  /* before looking in this table */\\n\"\r\n+\"        3,  35, 11, 43,  1, 33,  9, 41,  /* to determine the action.     */\\n\"\r\n+\"        51, 19, 59, 27, 49, 17, 57, 25,\\n\"\r\n+\"        15, 47,  7, 39, 13, 45,  5, 37,\\n\"\r\n+\"        63, 31, 55, 23, 61, 29, 53, 21);\\n\"\r\n+\"    float bayer=bayerPattern[int(mod(int(gl_FragCoord.x),8)+8*mod(int(gl_FragCoord.y),8))]/64;\\n\"\r\n+#ifdef MONITOR_6_BPP\r\n+        \"    const float rgbByteMax=63.;\\n\"\r\n+#else\r\n+        \"    const float rgbByteMax=255.;\\n\"\r\n+#endif\r\n+\"    vec3 rgb=c*rgbByteMax;\\n\"\r\n+\"    vec3 head=floor(rgb);\\n\"\r\n+\"    vec3 tail=fract(rgb);\\n\"\r\n+\"    return (head+step(bayer,tail))/rgbByteMax;\\n\"\r\n+\"}\\n\"\r\n+\"vec4 dither(vec4 c) { return vec4(dither(c.xyz),c.w); }\\n\"\r\n \t\t\"varying mediump vec2 texc;\\n\"\r\n \t\t\"uniform sampler2D tex;\\n\"\r\n \t\t\"uniform mediump vec4 texColor;\\n\"\r\n \t\t\"void main(void)\\n\"\r\n \t\t\"{\\n\"\r\n-\t\t\"    gl_FragColor = texture2D(tex, texc)*texColor;\\n\"\r\n+\t\t\"    gl_FragColor = dither(texture2D(tex, texc)*texColor);\\n\"\r\n \t\t\"}\\n\";\r\n \tfshader2.compileSourceCode(fsrc2);\r\n \tif (!fshader2.log().isEmpty()) { qWarning() << \"StelPainter: Warnings while compiling fshader2: \" << fshader2.log(); }\r\n@@ -2067,12 +2091,36 @@ void StelPainter::initGLShaders()\r\n \r\n \tQOpenGLShader fshader4(QOpenGLShader::Fragment);\r\n \tconst char *fsrc4 =\r\n+\"#version 120\\n\"\r\n+\"vec3 dither(vec3 c)\\n\"\r\n+\"{\\n\"\r\n+\"    const float bayerPattern[] = float[](\\n\"\r\n+\"        0,  32,  8, 40,  2, 34, 10, 42,  /* 8x8 Bayer ordered dithering  */\\n\"\r\n+\"        48, 16, 56, 24, 50, 18, 58, 26,  /* pattern.  Each input pixel   */\\n\"\r\n+\"        12, 44,  4, 36, 14, 46,  6, 38,  /* is scaled to the 0..63 range */\\n\"\r\n+\"        60, 28, 52, 20, 62, 30, 54, 22,  /* before looking in this table */\\n\"\r\n+\"        3,  35, 11, 43,  1, 33,  9, 41,  /* to determine the action.     */\\n\"\r\n+\"        51, 19, 59, 27, 49, 17, 57, 25,\\n\"\r\n+\"        15, 47,  7, 39, 13, 45,  5, 37,\\n\"\r\n+\"        63, 31, 55, 23, 61, 29, 53, 21);\\n\"\r\n+\"    float bayer=bayerPattern[int(mod(int(gl_FragCoord.x),8)+8*mod(int(gl_FragCoord.y),8))]/64;\\n\"\r\n+#ifdef MONITOR_6_BPP\r\n+        \"    const float rgbByteMax=63.;\\n\"\r\n+#else\r\n+        \"    const float rgbByteMax=255.;\\n\"\r\n+#endif\r\n+\"    vec3 rgb=c*rgbByteMax;\\n\"\r\n+\"    vec3 head=floor(rgb);\\n\"\r\n+\"    vec3 tail=fract(rgb);\\n\"\r\n+\"    return (head+step(bayer,tail))/rgbByteMax;\\n\"\r\n+\"}\\n\"\r\n+\"vec4 dither(vec4 c) { return vec4(dither(c.xyz),c.w); }\\n\"\r\n \t\t\"varying mediump vec2 texc;\\n\"\r\n \t\t\"varying mediump vec4 outColor;\\n\"\r\n \t\t\"uniform sampler2D tex;\\n\"\r\n \t\t\"void main(void)\\n\"\r\n \t\t\"{\\n\"\r\n-\t\t\"    gl_FragColor = texture2D(tex, texc)*outColor;\\n\"\r\n+\t\t\"    gl_FragColor = dither(texture2D(tex, texc)*outColor);\\n\"\r\n \t\t\"}\\n\";\r\n \tfshader4.compileSourceCode(fsrc4);\r\n \tif (!fshader4.log().isEmpty()) { qWarning() << \"StelPainter: Warnings while compiling fshader4: \" << fshader4.log(); }\r\ndiff --git a/src/core/modules/Atmosphere.cpp b/src/core/modules/Atmosphere.cpp\r\nindex 12953ed9ed..20798f554f 100644\r\n--- a/src/core/modules/Atmosphere.cpp\r\n+++ b/src/core/modules/Atmosphere.cpp\r\n@@ -58,10 +58,34 @@ Atmosphere::Atmosphere(void)\r\n \t}\r\n \tQOpenGLShader fShader(QOpenGLShader::Fragment);\r\n \tif (!fShader.compileSourceCode(\r\n+\"#version 120\\n\"\r\n+\"vec3 dither(vec3 c)\\n\"\r\n+\"{\\n\"\r\n+\"    const float bayerPattern[] = float[](\\n\"\r\n+\"        0,  32,  8, 40,  2, 34, 10, 42,  /* 8x8 Bayer ordered dithering  */\\n\"\r\n+\"        48, 16, 56, 24, 50, 18, 58, 26,  /* pattern.  Each input pixel   */\\n\"\r\n+\"        12, 44,  4, 36, 14, 46,  6, 38,  /* is scaled to the 0..63 range */\\n\"\r\n+\"        60, 28, 52, 20, 62, 30, 54, 22,  /* before looking in this table */\\n\"\r\n+\"        3,  35, 11, 43,  1, 33,  9, 41,  /* to determine the action.     */\\n\"\r\n+\"        51, 19, 59, 27, 49, 17, 57, 25,\\n\"\r\n+\"        15, 47,  7, 39, 13, 45,  5, 37,\\n\"\r\n+\"        63, 31, 55, 23, 61, 29, 53, 21);\\n\"\r\n+\"    float bayer=bayerPattern[int(mod(int(gl_FragCoord.x),8)+8*mod(int(gl_FragCoord.y),8))]/64;\\n\"\r\n+#ifdef MONITOR_6_BPP\r\n+        \"    const float rgbByteMax=63.;\\n\"\r\n+#else\r\n+        \"    const float rgbByteMax=255.;\\n\"\r\n+#endif\r\n+\"    vec3 rgb=c*rgbByteMax;\\n\"\r\n+\"    vec3 head=floor(rgb);\\n\"\r\n+\"    vec3 tail=fract(rgb);\\n\"\r\n+\"    return (head+step(bayer,tail))/rgbByteMax;\\n\"\r\n+\"}\\n\"\r\n+\"vec4 dither(vec4 c) { return vec4(dither(c.xyz),c.w); }\\n\"\r\n \t\t\t\t\t\"varying mediump vec3 resultSkyColor;\\n\"\r\n \t\t\t\t\t\"void main()\\n\"\r\n \t\t\t\t\t\"{\\n\"\r\n-\t\t\t\t\t \"   gl_FragColor = vec4(resultSkyColor, 1.);\\n\"\r\n+\t\t\t\t\t \"   gl_FragColor = vec4(dither(resultSkyColor), 1.);\\n\"\r\n \t\t\t\t\t \"}\"))\r\n \t{\r\n \t\tqFatal(\"Error while compiling atmosphere fragment shader: %s\", fShader.log().toLatin1().constData());\r\n```\r\nScreenshot of the same scene with the above patch:\r\n![screenshot with patch](https://user-images.githubusercontent.com/6376882/38444240-15ab1bc2-39de-11e8-8d03-a5c82deb9b38.png)\r\n"},"comment":{"url":"https://api.github.com/repos/Stellarium/stellarium/issues/comments/380056501","html_url":"https://github.com/Stellarium/stellarium/issues/131#issuecomment-380056501","issue_url":"https://api.github.com/repos/Stellarium/stellarium/issues/131","id":380056501,"user":{"login":"10110111","id":6376882,"avatar_url":"https://avatars3.githubusercontent.com/u/6376882?v=4","gravatar_id":"","url":"https://api.github.com/users/10110111","html_url":"https://github.com/10110111","followers_url":"https://api.github.com/users/10110111/followers","following_url":"https://api.github.com/users/10110111/following{/other_user}","gists_url":"https://api.github.com/users/10110111/gists{/gist_id}","starred_url":"https://api.github.com/users/10110111/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/10110111/subscriptions","organizations_url":"https://api.github.com/users/10110111/orgs","repos_url":"https://api.github.com/users/10110111/repos","events_url":"https://api.github.com/users/10110111/events{/privacy}","received_events_url":"https://api.github.com/users/10110111/received_events","type":"User","site_admin":false},"created_at":"2018-04-10T10:48:06Z","updated_at":"2018-04-10T10:48:06Z","author_association":"CONTRIBUTOR","body":"> What about the maxRGB, should this be 2^n-1 or 2^n? It seems the value for Color101010 is off by one?\r\n\r\nAh, right. It's the maximum value, so indeed `Color101010` should have `1023` instead of `1024`.\r\n\r\n> I can show working result in OpenGL and bad in GL ES2/ANGLE on Windows and bad in GL ES2 on Raspberry Pi3.\r\n\r\nPlease do, with the same color depth mode, and please mention which color depth it actually is."}}
{"actor":{"display_login":"10110111"}}