diff --git a/src/Shaders/MeshVisualizer.cpp b/src/Shaders/MeshVisualizer.cpp index 8164074c3..f2e3f5a84 100644 --- a/src/Shaders/MeshVisualizer.cpp +++ b/src/Shaders/MeshVisualizer.cpp @@ -33,35 +33,81 @@ namespace Magnum { namespace Shaders { MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationProjectionMatrixUniform(0), viewportSizeUniform(1), colorUniform(2), wireframeColorUniform(3), wireframeWidthUniform(4), smoothnessUniform(5) { - if(flags & Flag::Wireframe) MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_attrib_location); - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_uniform_location); + #ifndef MAGNUM_TARGET_GLES + if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); + #endif Utility::Resource rs("MagnumShaders"); - Shader vert(Version::GL330, Shader::Type::Vertex); + #ifndef MAGNUM_TARGET_GLES + const Version v = Context::current()->supportedVersion({Version::GL320, Version::GL310, Version::GL210}); + #else + const Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); + #endif + + Shader vert(v, Shader::Type::Vertex); vert.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + .addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "") .addSource(rs.get("compatibility.glsl")) .addSource(rs.get("MeshVisualizer.vert")); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); + vert.compile(); attachShader(vert); - if(flags & Flag::Wireframe) { - Shader geom(Version::GL330, Shader::Type::Geometry); + #ifndef MAGNUM_TARGET_GLES + if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) { + Shader geom(v, Shader::Type::Geometry); geom.addSource(rs.get("compatibility.glsl")) .addSource(rs.get("MeshVisualizer.geom")); CORRADE_INTERNAL_ASSERT_OUTPUT(geom.compile()); + geom.compile(); attachShader(geom); } + #endif - Shader frag(Version::GL330, Shader::Type::Fragment); + Shader frag(v, Shader::Type::Fragment); frag.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") + .addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "") .addSource(rs.get("compatibility.glsl")) .addSource(rs.get("MeshVisualizer.frag")); CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + frag.compile(); attachShader(frag); + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported() || + Context::current()->version() == Version::GL210) + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) + #endif + { + bindAttributeLocation(Position::Location, "position"); + #ifndef MAGNUM_TARGET_GLES + if(v < Version::GL310) + #else + if(v < Version::GLES300) + #endif + bindAttributeLocation(VertexIndex::Location, "vertexIndex"); + } + + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); link(); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + #endif + { + transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); + colorUniform = uniformLocation("color"); + if(flags & Flag::Wireframe) { + wireframeColorUniform = uniformLocation("wireframeColor"); + wireframeWidthUniform = uniformLocation("wireframeWidth"); + smoothnessUniform = uniformLocation("smoothness"); + if(!(flags & Flag::NoGeometryShader)) + viewportSizeUniform = uniformLocation("viewportSize"); + } + } } }} diff --git a/src/Shaders/MeshVisualizer.frag b/src/Shaders/MeshVisualizer.frag index 467d82ce2..ad3c9103a 100644 --- a/src/Shaders/MeshVisualizer.frag +++ b/src/Shaders/MeshVisualizer.frag @@ -22,24 +22,60 @@ DEALINGS IN THE SOFTWARE. */ +#ifndef NEW_GLSL +#define in varying +#define fragmentColor gl_FragColor +#endif + +#ifndef EXPLICIT_UNIFORM_LOCATION +#define layout(arg) +#endif + +#ifndef GL_ES layout(location = 2) uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); +#else +uniform lowp vec4 color; +#endif #ifdef WIREFRAME_RENDERING +#ifndef GL_ES layout(location = 3) uniform vec4 wireframeColor = vec4(0.0, 0.0, 0.0, 1.0); layout(location = 4) uniform float wireframeWidth = 1.0; layout(location = 5) uniform float smoothness = 2.0; +#else +uniform lowp vec4 wireframeColor; +uniform lowp float wireframeWidth; +uniform lowp float smoothness; +#endif + +#ifndef NO_GEOMETRY_SHADER noperspective in vec3 dist; +#else +in vec3 barycentric; +#endif #endif out vec4 fragmentColor; +#if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER) && defined(GL_ES) +#extension GL_OES_standard_derivatives : enable +#endif + void main() { #ifdef WIREFRAME_RENDERING + #ifndef NO_GEOMETRY_SHADER /* Distance to nearest side */ 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)); + #else + const vec3 d = fwidth(barycentric); + const vec3 factor = smoothstep(vec3(0.0), d*1.5, barycentric); + const float nearest = min(min(factor.x, factor.y), factor.z); + fragmentColor = mix(wireframeColor, color, nearest); + #endif + #else fragmentColor = color; #endif diff --git a/src/Shaders/MeshVisualizer.h b/src/Shaders/MeshVisualizer.h index b009e67f4..1eb9896a2 100644 --- a/src/Shaders/MeshVisualizer.h +++ b/src/Shaders/MeshVisualizer.h @@ -39,23 +39,68 @@ namespace Magnum { namespace Shaders { /** @brief %Mesh visualization shader -Uses geometry shader to visualize wireframe. You need to call at least -setTransformationProjectionMatrix() (and setViewportSize(), if -@ref Flag "Flag::Wireframe" is enabled) to be able to render. -@requires_gl32 %Extension @extension{ARB,geometry_shader4} if - @ref Magnum::Shaders::MeshVisualizer::Flag "Flag::Wireframe" is enabled. +Uses geometry shader to visualize wireframe. You need to provide @ref Position +attribute in your triangle mesh and call at least @ref setTransformationProjectionMatrix() +to be able to render. + +@section ShadersMeshVisualizer-wireframe Wireframe visualization + +Wireframe visualization is done by enabling @ref Flag "Flag::Wireframe". It is +done either using geometry shaders or with help of additional vertex information. + +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. + +If you don't have geometry shaders, you need to set @ref Flag "Flag::NoGeometryShader" +(it's enabled by default in OpenGL ES) and use only **non-indexed** triangle +meshes (see 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. + +@todo Understand and add support wireframe width/smoothness without GS */ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public AbstractShaderProgram { public: typedef Attribute<0, Vector3> Position; /**< @brief Vertex position */ + /** + * @brief Vertex index + * + * Used only in OpenGL < 3.1 and OpenGL ES 2.0 if @ref Flag "Flag::Wireframe" + * is enabled. This attribute specifies index of given vertex in + * triangle, i.e. `0` for first, `1` for second, `2` for third. In + * OpenGL 3.1, OpenGL ES 3.0 and newer this value is provided by the + * shader itself, so the attribute is not needed. + */ + typedef Attribute<1, Float> VertexIndex; + /** * @brief %Flag * * @see Flags, MeshVisualizer() */ enum class Flag: UnsignedByte { - Wireframe = 1 << 0 /**< Visualize wireframe */ + /** + * Visualize wireframe. On OpenGL ES this also enables + * @ref Flag "Flag::NoGeometryShader". + */ + #ifndef MAGNUM_TARGET_GLES + Wireframe = 1 << 0, + #else + Wireframe = (1 << 0) | (1 << 1), + #endif + + /** + * Don't use geometry shader for wireframe visualization. If + * enabled, you might need to provide also VertexIndex attribute in + * the mesh. In OpenGL ES enabled alongside @ref Flag "Flag::Wireframe". + */ + NoGeometryShader = 1 << 1 }; /** @brief %Flags */ diff --git a/src/Shaders/MeshVisualizer.vert b/src/Shaders/MeshVisualizer.vert index 784193ece..90f579d77 100644 --- a/src/Shaders/MeshVisualizer.vert +++ b/src/Shaders/MeshVisualizer.vert @@ -22,10 +22,41 @@ DEALINGS IN THE SOFTWARE. */ +#ifndef NEW_GLSL +#define in attribute +#define out varying +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 0) uniform mat4 transformationProjectionMatrix; +#else +uniform highp mat4 transformationProjectionMatrix; +#endif + +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 0) highp in vec4 position; +#else +in highp vec4 position; +#endif -layout(location = 0) in vec4 position; +#if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER) +#if (!defined(GL_ES) && __VERSION__ < 140) || (defined(GL_ES) && __VERSION__ < 300) +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 1) highp in float vertexIndex; +#else +in lowp float vertexIndex; +#endif +#define gl_VertexID int(vertexIndex) +#endif + +out vec3 barycentric; +#endif void main() { gl_Position = transformationProjectionMatrix*position; + + #if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER) + barycentric = vec3(0.0); + barycentric[gl_VertexID % 3] = 1.0; + #endif }