Improvements to the Signed Distance Field implementation.

This commit is contained in:
Robert Osfield 2017-10-04 18:06:42 +01:00
parent d2fa7c4317
commit 2f19cd4b87
4 changed files with 166 additions and 95 deletions

View File

@ -27,8 +27,13 @@ DefaultFont::DefaultFont()
_fontSize = FontResolution(8,12); _fontSize = FontResolution(8,12);
_minFilterHint = osg::Texture::LINEAR_MIPMAP_LINEAR; _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(); constructGlyphs();
} }

View File

@ -60,7 +60,9 @@ int GlyphTexture::compare(const osg::StateAttribute& rhs) const
int GlyphTexture::getEffectMargin(const Glyph* glyph) int GlyphTexture::getEffectMargin(const Glyph* glyph)
{ {
if (_glyphTextureFeatures==GREYSCALE) return 0; 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) int GlyphTexture::getTexelMargin(const Glyph* glyph)

View File

@ -47,6 +47,17 @@ Text::Text():
{ {
_supportsVertexBufferObjects = true; _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(); assignStateSet();
} }
@ -80,11 +91,10 @@ osg::StateSet* Text::createStateSet()
Font::StateSets& statesets = activeFont->getCachedStateSets(); Font::StateSets& statesets = activeFont->getCachedStateSets();
std::stringstream ss;
osg::StateSet::DefineList defineList; osg::StateSet::DefineList defineList;
if (_backdropType!=NONE && _backdropImplementation==USE_SHADERS) if (_backdropType!=NONE && _backdropImplementation==USE_SHADERS)
{ {
std::stringstream ss;
ss.str(""); ss.str("");
ss << "vec4("<<_backdropColor.r()<<", "<<_backdropColor.g()<<", "<<_backdropColor.b()<<", "<<_backdropColor.a()<<")"; 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<<std::endl; ss.str("");
ss << _fontSize.second;
defineList["GLYPH_DIMENSION"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON);
ss.str("");
ss << activeFont->getTextureWidthHint();
defineList["TEXTURE_DIMENSION"] = osg::StateSet::DefinePair(ss.str(), osg::StateAttribute::ON);
defineList["SIGNED_DISTNACE_FIELD"] = osg::StateSet::DefinePair("1", osg::StateAttribute::ON); defineList["SIGNED_DISTNACE_FIELD"] = osg::StateSet::DefinePair("1", osg::StateAttribute::ON);
} }
else
{
OSG_NOTICE<<"Disabling SDF support _fontSize.second="<<_fontSize.second<<std::endl;
}
#if 0 #if 0
OSG_NOTICE<<"Text::createStateSet() _backdropType="<<_backdropType<<", _backdropImplementation="<<_backdropImplementation<<std::endl; OSG_NOTICE<<"Text::createStateSet() _backdropType="<<_backdropType<<", _backdropImplementation="<<_backdropImplementation<<std::endl;
@ -151,7 +165,7 @@ osg::StateSet* Text::createStateSet()
{ {
if ((*itr)->getDefineList()==defineList) if ((*itr)->getDefineList()==defineList)
{ {
OSG_NOTICE<<"Text::createStateSet() : Matched DefineList, return StateSet "<<itr->get()<<std::endl; // OSG_NOTICE<<"Text::createStateSet() : Matched DefineList, return StateSet "<<itr->get()<<std::endl;
return itr->get(); return itr->get();
} }
else else
@ -180,7 +194,7 @@ osg::StateSet* Text::createStateSet()
osg::DisplaySettings::ShaderHint shaderHint = osg::DisplaySettings::instance()->getShaderHint(); osg::DisplaySettings::ShaderHint shaderHint = osg::DisplaySettings::instance()->getShaderHint();
if (activeFont->getGlyphTextureFeatures()==GlyphTexture::GREYSCALE && shaderHint==osg::DisplaySettings::SHADER_NONE) if (activeFont->getGlyphTextureFeatures()==GlyphTexture::GREYSCALE && shaderHint==osg::DisplaySettings::SHADER_NONE)
{ {
OSG_INFO<<"Font::Font() Fixed function pipeline"<<std::endl; OSG_NOTICE<<"Font::Font() Fixed function pipeline"<<std::endl;
stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON); stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
return stateset.release(); return stateset.release();

View File

@ -1,21 +1,17 @@
char text_sdf_frag[] = "$OSG_GLSL_VERSION\n" char text_sdf_frag[] = "$OSG_GLSL_VERSION\n"
"\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" "\n"
"#if !defined(GL_ES)\n" "#ifdef GL_ES\n"
" #if __VERSION__>=400\n" " #extension GL_OES_standard_derivatives : enable\n"
" #define osg_TextureQueryLOD textureQueryLod\n" " #ifndef GL_OES_standard_derivatives\n"
" #else\n" " #undef SIGNED_DISTNACE_FIELD\n"
" #extension GL_ARB_texture_query_lod : enable\n"
" #ifdef GL_ARB_texture_query_lod\n"
" #define osg_TextureQueryLOD textureQueryLOD\n"
" #endif\n"
" #endif\n" " #endif\n"
"#endif\n" "#endif\n"
"\n" "\n"
"$OSG_PRECISION_FLOAT\n" "$OSG_PRECISION_FLOAT\n"
"\n" "\n"
"//#undef USE_SIGNED_DISTNACE_FIELD\n" "#undef SIGNED_DISTNACE_FIELD\n"
"\n" "\n"
"#if __VERSION__>=130\n" "#if __VERSION__>=130\n"
" #define TEXTURE texture\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 vec2 texCoord;\n"
"$OSG_VARYING_IN vec4 vertexColor;\n" "$OSG_VARYING_IN vec4 vertexColor;\n"
"\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" "vec4 textureColor()\n"
"{\n" "{\n"
" #ifdef OUTLINE\n" " #ifdef OUTLINE\n"
" // glyph.rgba = (signed_distance, thin_outline, thick_outline, glyph_alpha)\n" " // glyph.rgba = (signed_distance, thin_outline, thick_outline, glyph_alpha)\n"
" vec4 glyph = TEXTURE(glyphTexture, texCoord);\n" " vec4 glyph = TEXTURE(glyphTexture, texCoord);\n"
"\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" "\n"
" float alpha = glyph.a+outline_alpha;\n" " float alpha = glyph.a+outline_alpha;\n"
" if (alpha>1.0) alpha = 1.0;\n" " if (alpha>1.0) alpha = 1.0;\n"
@ -52,53 +173,6 @@ char text_sdf_frag[] = "$OSG_GLSL_VERSION\n"
" #endif\n" " #endif\n"
"}\n" "}\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" "#endif\n"
"\n" "\n"
"\n" "\n"
@ -110,36 +184,12 @@ char text_sdf_frag[] = "$OSG_GLSL_VERSION\n"
" return;\n" " return;\n"
" }\n" " }\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" "#ifdef SIGNED_DISTNACE_FIELD\n"
"\n" " vec4 color = distanceFieldColor();\n"
" float near_transition = 0.0;\n"
" float far_transition = near_transition+1.0;\n"
"\n"
" vec4 color;\n"
" if (mml<near_transition) color = distanceFieldColor();\n"
" else if (mml>far_transition) color = textureColor();\n"
" else color = mix(distanceFieldColor(), textureColor(), (mml-near_transition)/(far_transition-near_transition));\n"
"\n"
"#else\n" "#else\n"
"\n"
" vec4 color = textureColor();\n" " vec4 color = textureColor();\n"
"\n"
"#endif\n" "#endif\n"
"\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" " if (color.a==0.0) discard;\n"
"\n" "\n"
" osg_FragColor = color;\n" " osg_FragColor = color;\n"