Browse Source

Shaders: ported MeshVisualizer to not require geometry shader.

Wireframe width and smoothness isn't ported yet, because I don't fully
understand the behavior of standard derivatives in fragment shader.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
b9a72bd3d1
  1. 60
      src/Shaders/MeshVisualizer.cpp
  2. 36
      src/Shaders/MeshVisualizer.frag
  3. 57
      src/Shaders/MeshVisualizer.h
  4. 33
      src/Shaders/MeshVisualizer.vert

60
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<Extensions::GL::ARB::explicit_attrib_location>() ||
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<Extensions::GL::ARB::explicit_uniform_location>())
#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");
}
}
}
}}

36
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

57
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 */

33
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
}

Loading…
Cancel
Save