From c880e6293a98d6d0d850c16f03bb5809c65b5b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 18 Mar 2020 23:10:36 +0100 Subject: [PATCH] Shaders: enable noperspective in MeshVisualizer properly. This makes existing tests slightly broken, which is good (if it wouldn't, the thresholds would be too huge). Since the addition of ES3.2 geometry shaders (which broke this) happened long before there were rendering tests for shaders, this breakage wasn't caught until now. Of course proper tests would include the perspective case from the previous commit since the very beginning, but that's hard to do when you're testing long after the code was written. The test files are now RLE-encoded, which makes them significantly smaller (tho I assume Git would further compress both anyway). Not updating existing files to RLE yet to avoid repo history bloat, doing that the next time they get changed. --- doc/changelog.dox | 3 +++ src/Magnum/Shaders/MeshVisualizer.frag | 2 +- src/Magnum/Shaders/MeshVisualizer.geom | 2 +- .../Shaders/Test/MeshVisualizerGLTest.cpp | 10 ++++++++-- .../wireframe-wide3D.tga | Bin 19218 -> 5888 bytes .../MeshVisualizerTestFiles/wireframe3D.tga | Bin 19218 -> 6755 bytes 6 files changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 82ba7bd89..aa1448267 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -432,6 +432,9 @@ See also: check - For a @ref Shaders::Phong with zero lights, alpha mask default value was incorrectly @cpp 0.0f @ce instead of @cpp 0.5f @ce on OpenGL ES +- @ref Shaders::MeshVisualizer3D accidentally didn't enable + @glsl noperspective @ce interpolation on desktop, resulting in minor + wireframe rendering artifacts @subsection changelog-latest-deprecated Deprecated APIs diff --git a/src/Magnum/Shaders/MeshVisualizer.frag b/src/Magnum/Shaders/MeshVisualizer.frag index 12d792737..7f454ae88 100644 --- a/src/Magnum/Shaders/MeshVisualizer.frag +++ b/src/Magnum/Shaders/MeshVisualizer.frag @@ -82,7 +82,7 @@ uniform lowp float smoothness ; #ifndef NO_GEOMETRY_SHADER -#ifdef GL_NV_shader_noperspective_interpolation +#if !defined(GL_ES) || defined(GL_NV_shader_noperspective_interpolation) noperspective #endif in lowp vec3 dist; diff --git a/src/Magnum/Shaders/MeshVisualizer.geom b/src/Magnum/Shaders/MeshVisualizer.geom index 4ca350882..32989140b 100644 --- a/src/Magnum/Shaders/MeshVisualizer.geom +++ b/src/Magnum/Shaders/MeshVisualizer.geom @@ -44,7 +44,7 @@ layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; /* Interpolate in screen space (if possible) */ -#ifdef GL_NV_shader_noperspective_interpolation +#if !defined(GL_ES) || defined(GL_NV_shader_noperspective_interpolation) noperspective #endif out lowp vec3 dist; diff --git a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp index fe7add89b..c33306f9f 100644 --- a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp +++ b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp @@ -792,8 +792,14 @@ void MeshVisualizerGLTest::renderWireframe3D() { CORRADE_EXPECT_FAIL_IF(data.flags & MeshVisualizer3D::Flag::NoGeometryShader, "Line width is currently not configurable w/o geometry shader."); #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) - /* SwiftShader has differently rasterized edges on four pixels */ - const Float maxThreshold = 170.0f, meanThreshold = 0.327f; + /* SwiftShader has differently rasterized edges on four pixels. On a + GS, if GL_NV_shader_noperspective_interpolation is not supported, + the artifacts are bigger. */ + Float maxThreshold = 170.0f, meanThreshold = 0.327f; + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if(!(data.flags & MeshVisualizer3D::Flag::NoGeometryShader) && !GL::Context::current().isExtensionSupported()) + meanThreshold = 2.166f; + #endif #else /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ const Float maxThreshold = 170.0f, meanThreshold = 1.699f; diff --git a/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide3D.tga b/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide3D.tga index 1314e14a289afc7c719cd4511221eaac548fbf8b..5aff6ce018308a7a636511f475c092a860132aa3 100644 GIT binary patch literal 5888 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 literal 19218 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 diff --git a/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe3D.tga b/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe3D.tga index 9d972407210bd6d2177b77a62911f45ee5044b04..efa7e3383ba6d5ab8b9a2834c1525cd965002ad0 100644 GIT binary patch literal 6755 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