From 2f19cd4b87bb202c9aaf277cf3e6868a512ac593 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 4 Oct 2017 18:06:42 +0100 Subject: [PATCH] Improvements to the Signed Distance Field implementation. --- src/osgText/DefaultFont.cpp | 7 +- src/osgText/Glyph.cpp | 4 +- src/osgText/Text.cpp | 34 ++-- src/osgText/shaders/text_sdf_frag.cpp | 216 ++++++++++++++++---------- 4 files changed, 166 insertions(+), 95 deletions(-) diff --git a/src/osgText/DefaultFont.cpp b/src/osgText/DefaultFont.cpp index ad7036b2b..cf3669cef 100644 --- a/src/osgText/DefaultFont.cpp +++ b/src/osgText/DefaultFont.cpp @@ -27,8 +27,13 @@ DefaultFont::DefaultFont() _fontSize = FontResolution(8,12); _minFilterHint = osg::Texture::LINEAR_MIPMAP_LINEAR; - _magFilterHint = osg::Texture::NEAREST; + _magFilterHint = osg::Texture::LINEAR; + char *ptr; + if ((ptr = getenv("OSG_SDF_TEXT")) != 0) + { + _glyphTextureFeatures = osgText::GlyphTexture::ALL_FEATURES; + } constructGlyphs(); } diff --git a/src/osgText/Glyph.cpp b/src/osgText/Glyph.cpp index 4953c2913..e8a11ea87 100644 --- a/src/osgText/Glyph.cpp +++ b/src/osgText/Glyph.cpp @@ -60,7 +60,9 @@ int GlyphTexture::compare(const osg::StateAttribute& rhs) const int GlyphTexture::getEffectMargin(const Glyph* glyph) { if (_glyphTextureFeatures==GREYSCALE) return 0; - else return glyph->getFontResolution().second/4; +// else return glyph->getFontResolution().second/4; + else return osg::maximum(glyph->getFontResolution().second/6, 2u); +// else return osg::maximum(glyph->getFontResolution().second/8,1u); } int GlyphTexture::getTexelMargin(const Glyph* glyph) diff --git a/src/osgText/Text.cpp b/src/osgText/Text.cpp index 3e7e1f49a..23d146372 100644 --- a/src/osgText/Text.cpp +++ b/src/osgText/Text.cpp @@ -47,6 +47,17 @@ Text::Text(): { _supportsVertexBufferObjects = true; + char *ptr; + if ((ptr = getenv("OSG_SDF_TEXT")) != 0) + { + _backdropImplementation = USE_SHADERS; + } + else if ((ptr = getenv("OSG_GREYSCALE_TEXT")) != 0) + { + _backdropImplementation = DELAYED_DEPTH_WRITES; + } + + assignStateSet(); } @@ -80,11 +91,10 @@ osg::StateSet* Text::createStateSet() Font::StateSets& statesets = activeFont->getCachedStateSets(); + std::stringstream ss; osg::StateSet::DefineList defineList; if (_backdropType!=NONE && _backdropImplementation==USE_SHADERS) { - std::stringstream ss; - ss.str(""); ss << "vec4("<<_backdropColor.r()<<", "<<_backdropColor.g()<<", "<<_backdropColor.b()<<", "<<_backdropColor.a()<<")"; @@ -122,15 +132,19 @@ osg::StateSet* Text::createStateSet() } - if (_fontSize.second>16/* && _backdropImplementation==USE_SHADERS*/) + if (activeFont->getGlyphTextureFeatures()!=GlyphTexture::GREYSCALE) { - OSG_NOTICE<<"Requesting SDF support _fontSize.second="<<_fontSize.second<getTextureWidthHint(); + defineList["TEXTURE_DIMENSION"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON); + defineList["SIGNED_DISTNACE_FIELD"] = osg::StateSet::DefinePair("1", osg::StateAttribute::ON); } - else - { - OSG_NOTICE<<"Disabling SDF support _fontSize.second="<<_fontSize.second<get()<get()<get(); } else @@ -180,7 +194,7 @@ osg::StateSet* Text::createStateSet() osg::DisplaySettings::ShaderHint shaderHint = osg::DisplaySettings::instance()->getShaderHint(); if (activeFont->getGlyphTextureFeatures()==GlyphTexture::GREYSCALE && shaderHint==osg::DisplaySettings::SHADER_NONE) { - OSG_INFO<<"Font::Font() Fixed function pipeline"<setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); return stateset.release(); diff --git a/src/osgText/shaders/text_sdf_frag.cpp b/src/osgText/shaders/text_sdf_frag.cpp index fde9f406d..fa2ed3c10 100644 --- a/src/osgText/shaders/text_sdf_frag.cpp +++ b/src/osgText/shaders/text_sdf_frag.cpp @@ -1,21 +1,17 @@ char text_sdf_frag[] = "$OSG_GLSL_VERSION\n" "\n" - "#pragma import_defines( BACKDROP_COLOR, OUTLINE, SIGNED_DISTNACE_FIELD )\n" + "#pragma import_defines( BACKDROP_COLOR, OUTLINE, SIGNED_DISTNACE_FIELD, TEXTURE_DIMENSION, GLYPH_DIMENSION)\n" "\n" - "#if !defined(GL_ES)\n" - " #if __VERSION__>=400\n" - " #define osg_TextureQueryLOD textureQueryLod\n" - " #else\n" - " #extension GL_ARB_texture_query_lod : enable\n" - " #ifdef GL_ARB_texture_query_lod\n" - " #define osg_TextureQueryLOD textureQueryLOD\n" - " #endif\n" + "#ifdef GL_ES\n" + " #extension GL_OES_standard_derivatives : enable\n" + " #ifndef GL_OES_standard_derivatives\n" + " #undef SIGNED_DISTNACE_FIELD\n" " #endif\n" "#endif\n" "\n" "$OSG_PRECISION_FLOAT\n" "\n" - "//#undef USE_SIGNED_DISTNACE_FIELD\n" + "#undef SIGNED_DISTNACE_FIELD\n" "\n" "#if __VERSION__>=130\n" " #define TEXTURE texture\n" @@ -32,13 +28,138 @@ char text_sdf_frag[] = "$OSG_GLSL_VERSION\n" "$OSG_VARYING_IN vec2 texCoord;\n" "$OSG_VARYING_IN vec4 vertexColor;\n" "\n" + "#ifdef SIGNED_DISTNACE_FIELD\n" + "\n" + "float distanceFromEdge(vec2 tc)\n" + "{\n" + " float center_alpha = TEXTURELOD(glyphTexture, tc, 0.0).r;\n" + " if (center_alpha==0.0) return -1.0;\n" + "\n" + " //float distance_scale = (1.0/4.0)*1.41;\n" + " float distance_scale = (1.0/6.0)*1.41;\n" + " //float distance_scale = (1.0/8.0)*1.41;\n" + "\n" + " return (center_alpha-0.5)*distance_scale;\n" + "}\n" + "\n" + "vec4 distanceFieldColorSample(float edge_distance, float blend_width, float blend_half_width)\n" + "{\n" + "#ifdef OUTLINE\n" + " float outline_width = OUTLINE*0.5;\n" + " if (edge_distance>blend_half_width)\n" + " {\n" + " return vertexColor;\n" + " }\n" + " else if (edge_distance>-blend_half_width)\n" + " {\n" + " return mix(vertexColor, BACKDROP_COLOR, smoothstep(0.0, 1.0, (blend_half_width-edge_distance)/(blend_width)));\n" + " }\n" + " else if (edge_distance>(blend_half_width-outline_width))\n" + " {\n" + " return BACKDROP_COLOR;\n" + " }\n" + " else if (edge_distance>-(outline_width+blend_half_width))\n" + " {\n" + " return vec4(BACKDROP_COLOR.rgb, ((blend_half_width+outline_width+edge_distance)/blend_width));\n" + " }\n" + " else\n" + " {\n" + " return vec4(0.0, 0.0, 0.0, 0.0);\n" + " }\n" + "#else\n" + " if (edge_distance>blend_half_width)\n" + " {\n" + " return vertexColor;\n" + " }\n" + " else if (edge_distance>-blend_half_width)\n" + " {\n" + " return vec4(vertexColor.rgb, smoothstep(1.0, 0.0, (blend_half_width-edge_distance)/(blend_width)));\n" + " }\n" + " else\n" + " {\n" + " return vec4(0.0, 0.0, 0.0, 0.0);\n" + " }\n" + "#endif\n" + "}\n" + "\n" + "vec4 distanceFieldColor()\n" + "{\n" + " float sample_distance_scale = 0.75;\n" + " vec2 dx = dFdx(texCoord)*sample_distance_scale;\n" + " vec2 dy = dFdy(texCoord)*sample_distance_scale;\n" + "\n" + " #ifndef TEXTURE_DIMENSION\n" + " float TEXTURE_DIMENSION = 1024.0;\n" + " #endif\n" + "\n" + " #ifndef GLYPH_DIMENSION\n" + " float GLYPH_DIMENSION = 32.0;\n" + " #endif\n" + "\n" + " float distance_across_pixel = length(dx+dy)*(TEXTURE_DIMENSION/GLYPH_DIMENSION);\n" + "\n" + " // compute the appropriate number of samples required to avoid aliasing.\n" + " int maxNumSamplesAcrossSide = 4;\n" + "\n" + " int numSamplesX = int(TEXTURE_DIMENSION * length(dx));\n" + " int numSamplesY = int(TEXTURE_DIMENSION * length(dy));\n" + " if (numSamplesX<2) numSamplesX = 2;\n" + " if (numSamplesY<2) numSamplesY = 2;\n" + " if (numSamplesX>maxNumSamplesAcrossSide) numSamplesX = maxNumSamplesAcrossSide;\n" + " if (numSamplesY>maxNumSamplesAcrossSide) numSamplesY = maxNumSamplesAcrossSide;\n" + "\n" + "\n" + " vec2 delta_tx = dx/float(numSamplesX-1);\n" + " vec2 delta_ty = dy/float(numSamplesY-1);\n" + "\n" + " float numSamples = float(numSamplesX)*float(numSamplesY);\n" + " float scale = 1.0/numSamples;\n" + " vec4 total_color = vec4(0.0,0.0,0.0,0.0);\n" + "\n" + " float blend_width = 1.5*distance_across_pixel/numSamples;\n" + " float blend_half_width = blend_width*0.5;\n" + "\n" + " // check whether fragment is wholly within or outwith glyph body+outline\n" + " float cd = distanceFromEdge(texCoord); // central distance (distance from center to edge)\n" + " if (cd-blend_half_width>distance_across_pixel) return vertexColor; // pixel fully within glyph body\n" + "\n" + " #ifdef OUTLINE\n" + " float outline_width = OUTLINE*0.5;\n" + " if ((-cd-outline_width-blend_half_width)>distance_across_pixel) return vec4(0.0, 0.0, 0.0, 0.0); // pixel fully outside outline+glyph body\n" + " #else\n" + " if (-cd-blend_half_width>distance_across_pixel) return vec4(0.0, 0.0, 0.0, 0.0); // pixel fully outside glyph body\n" + " #endif\n" + "\n" + "\n" + " // use multi-sampling to provide high quality antialised fragments\n" + " vec2 origin = texCoord - dx*0.5 - dy*0.5;\n" + " for(;numSamplesY>0; --numSamplesY)\n" + " {\n" + " vec2 pos = origin;\n" + " int numX = numSamplesX;\n" + " for(;numX>0; --numX)\n" + " {\n" + " vec4 c = distanceFieldColorSample(distanceFromEdge(pos), blend_width, blend_half_width);\n" + " total_color = total_color + c * c.a;\n" + " pos += delta_tx;\n" + " }\n" + " origin += delta_ty;\n" + " }\n" + "\n" + " total_color.rgb /= total_color.a;\n" + " total_color.a *= scale;\n" + "\n" + " return total_color;\n" + "}\n" + "#else\n" + "\n" "vec4 textureColor()\n" "{\n" " #ifdef OUTLINE\n" " // glyph.rgba = (signed_distance, thin_outline, thick_outline, glyph_alpha)\n" " vec4 glyph = TEXTURE(glyphTexture, texCoord);\n" "\n" - " float outline_alpha = (OUTLINE<=0.1) ? glyph.g : glyph.b;\n" + " float outline_alpha = (OUTLINE<=0.05) ? glyph.g : glyph.b;\n" "\n" " float alpha = glyph.a+outline_alpha;\n" " if (alpha>1.0) alpha = 1.0;\n" @@ -52,53 +173,6 @@ char text_sdf_frag[] = "$OSG_GLSL_VERSION\n" " #endif\n" "}\n" "\n" - "#ifdef SIGNED_DISTNACE_FIELD\n" - "vec4 distanceFieldColor()\n" - "{\n" - " float center_alpha = TEXTURELOD(glyphTexture, texCoord, 0.0).r;\n" - " //float center_alpha = TEXTURE(glyphTexture, texCoord).r;\n" - "\n" - " float blend_width = 0.005;\n" - " float distance_scale = 0.25;\n" - " float edge_distance = (center_alpha-0.5)*distance_scale;\n" - "\n" - " #ifdef OUTLINE\n" - " float outline_width = OUTLINE*0.5;\n" - " if (edge_distance>blend_width*0.5)\n" - " {\n" - " return vertexColor;\n" - " }\n" - " else if (edge_distance>-blend_width*0.5)\n" - " {\n" - " return mix(vertexColor, BACKDROP_COLOR, (blend_width*0.5-edge_distance)/(blend_width));\n" - " }\n" - " else if (edge_distance>(blend_width-outline_width))\n" - " {\n" - " return BACKDROP_COLOR;\n" - " }\n" - " else if (edge_distance>-outline_width)\n" - " {\n" - " return vec4(BACKDROP_COLOR.rgb, (outline_width+edge_distance)/blend_width);\n" - " }\n" - " else\n" - " {\n" - " return vec4(0.0, 0.0, 0.0, 0.0);\n" - " }\n" - " #else\n" - " if (edge_distance>0.0)\n" - " {\n" - " return vertexColor;\n" - " }\n" - " else if (edge_distance>-blend_width)\n" - " {\n" - " return vec4(vertexColor.rgb, 1.0+edge_distance/blend_width);\n" - " }\n" - " else\n" - " {\n" - " return vec4(0.0, 0.0, 0.0, 0.0);\n" - " }\n" - " #endif\n" - "}\n" "#endif\n" "\n" "\n" @@ -110,36 +184,12 @@ char text_sdf_frag[] = "$OSG_GLSL_VERSION\n" " return;\n" " }\n" "\n" - "\n" - " float near_fade_away = 2.0;\n" - " float far_fade_away = near_fade_away+5.0;\n" - "\n" - "#ifdef osg_TextureQueryLOD\n" - " float mml = osg_TextureQueryLOD(glyphTexture, texCoord).x;\n" - " if (mml>far_fade_away) discard;\n" - "#else\n" - " float mml = 0.0;\n" - "#endif\n" - "\n" - "\n" "#ifdef SIGNED_DISTNACE_FIELD\n" - "\n" - " float near_transition = 0.0;\n" - " float far_transition = near_transition+1.0;\n" - "\n" - " vec4 color;\n" - " if (mmlfar_transition) color = textureColor();\n" - " else color = mix(distanceFieldColor(), textureColor(), (mml-near_transition)/(far_transition-near_transition));\n" - "\n" + " vec4 color = distanceFieldColor();\n" "#else\n" - "\n" " vec4 color = textureColor();\n" - "\n" "#endif\n" "\n" - " if (mml>near_fade_away) color.a *= (far_fade_away-mml)/(far_fade_away-near_fade_away);\n" - "\n" " if (color.a==0.0) discard;\n" "\n" " osg_FragColor = color;\n"