From 0ccd9aa26ef5838218ac644c7594dff3dca49f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Jul 2015 22:32:00 +0200 Subject: [PATCH] Shaders: ported MeshVisualizer to use geometry shaders also on ES3+AEP. Please note that in ES3 there is a behavioral change -- geometry shader is no longer explicitly disabled, but it is enabled by default and you have to disable it if you don't have the required extension or don't want to use it. --- src/Magnum/Shaders/MeshVisualizer.cpp | 17 +++++++++++------ src/Magnum/Shaders/MeshVisualizer.frag | 11 +++++++++-- src/Magnum/Shaders/MeshVisualizer.geom | 18 ++++++++++++++---- src/Magnum/Shaders/MeshVisualizer.h | 15 ++++++++++----- .../Shaders/Test/MeshVisualizerGLTest.cpp | 18 ++++++++++++++---- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/Magnum/Shaders/MeshVisualizer.cpp b/src/Magnum/Shaders/MeshVisualizer.cpp index 71a50fd86..08d2e6e43 100644 --- a/src/Magnum/Shaders/MeshVisualizer.cpp +++ b/src/Magnum/Shaders/MeshVisualizer.cpp @@ -37,12 +37,16 @@ namespace Magnum { namespace Shaders { MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationProjectionMatrixUniform(0), viewportSizeUniform(1), colorUniform(2), wireframeColorUniform(3), wireframeWidthUniform(4), smoothnessUniform(5) { - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) { + #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL320); MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); + #else + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::geometry_shader); + #endif } - #elif defined(MAGNUM_TARGET_GLES2) + #else if(flags & Flag::Wireframe) MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::OES::standard_derivatives); #endif @@ -58,7 +62,8 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP const Version version = Context::current()->supportedVersion({Version::GL320, Version::GL310, Version::GL300, Version::GL210}); CORRADE_INTERNAL_ASSERT(flags & Flag::NoGeometryShader || version >= Version::GL320); #else - const Version version = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); + const Version version = Context::current()->supportedVersion({Version::GLES310, Version::GLES300, Version::GLES200}); + CORRADE_INTERNAL_ASSERT(flags & Flag::NoGeometryShader || version >= Version::GLES310); #endif Shader vert = Implementation::createCompatibilityShader(rs, version, Shader::Type::Vertex); @@ -78,7 +83,7 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP .addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "") .addSource(rs.get("MeshVisualizer.frag")); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 std::optional geom; if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) { geom = Implementation::createCompatibilityShader(rs, version, Shader::Type::Geometry); @@ -86,14 +91,14 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP } #endif - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 if(geom) CORRADE_INTERNAL_ASSERT_OUTPUT(Shader::compile({vert, *geom, frag})); else #endif CORRADE_INTERNAL_ASSERT_OUTPUT(Shader::compile({vert, frag})); attachShaders({vert, frag}); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 if(geom) attachShader(*geom); #endif diff --git a/src/Magnum/Shaders/MeshVisualizer.frag b/src/Magnum/Shaders/MeshVisualizer.frag index ce613fb14..8c48eb079 100644 --- a/src/Magnum/Shaders/MeshVisualizer.frag +++ b/src/Magnum/Shaders/MeshVisualizer.frag @@ -40,6 +40,10 @@ #extension GL_OES_standard_derivatives : enable #endif +#if defined(GL_ES) && !defined(NO_GEOMETRY_SHADER) && defined(GL_NV_shader_noperspective_interpolation) +#extension GL_NV_shader_noperspective_interpolation: require +#endif + #ifndef GL_ES layout(location = 2) uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); #else @@ -58,7 +62,10 @@ uniform lowp float smoothness; #endif #ifndef NO_GEOMETRY_SHADER -noperspective in lowp vec3 dist; +#ifdef GL_NV_shader_noperspective_interpolation +noperspective +#endif +in lowp vec3 dist; #else in lowp vec3 barycentric; #endif @@ -72,7 +79,7 @@ void main() { #ifdef WIREFRAME_RENDERING #ifndef NO_GEOMETRY_SHADER /* Distance to nearest side */ - const float nearest = min(min(dist.x, dist.y), dist.z); + lowp const float nearest = min(min(dist.x, dist.y), dist.z); /* Smooth step between face color and wireframe color based on distance */ fragmentColor = mix(wireframeColor, color, smoothstep(wireframeWidth-smoothness, wireframeWidth+smoothness, nearest)); diff --git a/src/Magnum/Shaders/MeshVisualizer.geom b/src/Magnum/Shaders/MeshVisualizer.geom index e2825989e..109e21fe2 100644 --- a/src/Magnum/Shaders/MeshVisualizer.geom +++ b/src/Magnum/Shaders/MeshVisualizer.geom @@ -27,6 +27,13 @@ #define const #endif +#ifdef GL_ES +#extension GL_EXT_geometry_shader: require +#ifdef GL_NV_shader_noperspective_interpolation +#extension GL_NV_shader_noperspective_interpolation: require +#endif +#endif + #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 1) uniform vec2 viewportSize; #else @@ -37,8 +44,11 @@ layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; -/* Interpolate in screen space */ -noperspective out vec3 dist; +/* Interpolate in screen space (if possible) */ +#ifdef GL_NV_shader_noperspective_interpolation +noperspective +#endif +out lowp vec3 dist; void main() { /* Screen position of each vertex */ @@ -47,11 +57,11 @@ void main() { p[i] = viewportSize*gl_in[i].gl_Position.xy/gl_in[i].gl_Position.w; /* Vector of each triangle side */ - const vec2 v[3] = { + const vec2 v[3] = vec2[3]( p[2]-p[1], p[2]-p[0], p[1]-p[0] - }; + ); /* Compute area using perp-dot product */ const float area = abs(dot(vec2(-v[1].y, v[1].x), v[2])); diff --git a/src/Magnum/Shaders/MeshVisualizer.h b/src/Magnum/Shaders/MeshVisualizer.h index 3d5a61083..44b235edb 100644 --- a/src/Magnum/Shaders/MeshVisualizer.h +++ b/src/Magnum/Shaders/MeshVisualizer.h @@ -56,15 +56,20 @@ If you have geometry shaders available, you don't need to do anything else. @requires_gl32 Extension @extension{ARB,geometry_shader4} for wireframe rendering using geometry shaders. +@requires_es_extension Extension @es_extension{EXT,geometry_shader} for + wireframe rendering using geometry shaders. If you don't have geometry shaders, you need to set @ref Flag::NoGeometryShader -(it's enabled by default in OpenGL ES) and use only **non-indexed** triangle +(it's enabled by default in OpenGL ES 2.0) and use only **non-indexed** triangle meshes (see @ref MeshTools::duplicate() for possible solution). Additionaly, if you have OpenGL < 3.1 or OpenGL ES 2.0, you need to provide also @ref VertexIndex attribute. -@requires_es_extension Extension @extension{OES,standard_derivatives} for - wireframe rendering. +@requires_gles30 Extension @es_extension{OES,standard_derivatives} for + wireframe rendering without geometry shaders. + +If using geometry shaders on OpenGL ES, @es_extension{NV,shader_noperspective_interpolation} +is optionally used for improving line appearance. ## Example usage @@ -174,10 +179,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public AbstractShaderProgram { */ enum class Flag: UnsignedByte { /** - * Visualize wireframe. On OpenGL ES this also enables + * Visualize wireframe. On OpenGL ES 2.0 this also enables * @ref Flag::NoGeometryShader. */ - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 Wireframe = 1 << 0, #else Wireframe = (1 << 0) | (1 << 1), diff --git a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp index 0f3141f5b..47a029199 100644 --- a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp +++ b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp @@ -34,13 +34,17 @@ struct MeshVisualizerGLTest: Magnum::Test::AbstractOpenGLTester { explicit MeshVisualizerGLTest(); void compile(); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void compileWireframeGeometryShader(); + #endif void compileWireframeNoGeometryShader(); }; MeshVisualizerGLTest::MeshVisualizerGLTest() { addTests({&MeshVisualizerGLTest::compile, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) &MeshVisualizerGLTest::compileWireframeGeometryShader, + #endif &MeshVisualizerGLTest::compileWireframeNoGeometryShader}); } @@ -49,17 +53,23 @@ void MeshVisualizerGLTest::compile() { CORRADE_VERIFY(shader.validate().first); } +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void MeshVisualizerGLTest::compileWireframeGeometryShader() { - #ifdef MAGNUM_TARGET_GLES - CORRADE_SKIP("Geometry shader is not available in OpenGL ES"); - #else + #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::geometry_shader4::string() + std::string(" is not supported")); + #else + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::geometry_shader::string() + std::string(" is not supported")); + #endif + + if(Context::current()->isExtensionSupported()) + Debug() << "Using" << Extensions::GL::NV::shader_noperspective_interpolation::string(); Shaders::MeshVisualizer shader(Shaders::MeshVisualizer::Flag::Wireframe); CORRADE_VERIFY(shader.validate().first); - #endif } +#endif void MeshVisualizerGLTest::compileWireframeNoGeometryShader() { Shaders::MeshVisualizer shader(Shaders::MeshVisualizer::Flag::Wireframe|Shaders::MeshVisualizer::Flag::NoGeometryShader);