$OSG_GLSL_VERSION #pragma import_defines( BACKDROP_COLOR, SHADOW, OUTLINE, SIGNED_DISTANCE_FIELD, TEXTURE_DIMENSION, GLYPH_DIMENSION) #ifdef GL_ES #extension GL_OES_standard_derivatives : enable #ifndef GL_OES_standard_derivatives #undef SIGNED_DISTANCE_FIELD #endif #endif #if !defined(GL_ES) #if __VERSION__>=400 #define osg_TextureQueryLOD textureQueryLod #else #extension GL_ARB_texture_query_lod : enable #ifdef GL_ARB_texture_query_lod #define osg_TextureQueryLOD textureQueryLOD #endif #endif #endif $OSG_PRECISION_FLOAT #if __VERSION__>=130 #define TEXTURE texture #define TEXTURELOD textureLod out vec4 osg_FragColor; #else #define TEXTURE texture2D #define TEXTURELOD texture2DLod #define osg_FragColor gl_FragColor #endif #if !defined(GL_ES) && __VERSION__>=130 #define ALPHA r #define SDF g #else #define ALPHA a #define SDF r #endif uniform sampler2D glyphTexture; $OSG_VARYING_IN vec2 texCoord; $OSG_VARYING_IN vec4 vertexColor; #ifndef TEXTURE_DIMENSION const float TEXTURE_DIMENSION = 1024.0; #endif #ifndef GLYPH_DIMENSION const float GLYPH_DIMENSION = 32.0; #endif #ifdef SIGNED_DISTANCE_FIELD float distanceFromEdge(vec2 tc) { float center_alpha = TEXTURELOD(glyphTexture, tc, 0.0).SDF; if (center_alpha==0.0) return -1.0; //float distance_scale = (1.0/4.0)*1.41; float distance_scale = (1.0/6.0)*1.41; //float distance_scale = (1.0/8.0)*1.41; return (center_alpha-0.5)*distance_scale; } vec4 distanceFieldColorSample(float edge_distance, float blend_width, float blend_half_width) { #ifdef OUTLINE float outline_width = OUTLINE*0.5; if (edge_distance>blend_half_width) { return vertexColor; } else if (edge_distance>-blend_half_width) { return mix(vertexColor, vec4(BACKDROP_COLOR.rgb, BACKDROP_COLOR.a*vertexColor.a), smoothstep(0.0, 1.0, (blend_half_width-edge_distance)/(blend_width))); } else if (edge_distance>(blend_half_width-outline_width)) { return vec4(BACKDROP_COLOR.rgb, BACKDROP_COLOR.a*vertexColor.a); } else if (edge_distance>-(outline_width+blend_half_width)) { return vec4(BACKDROP_COLOR.rgb, vertexColor.a * ((blend_half_width+outline_width+edge_distance)/blend_width)); } else { return vec4(0.0, 0.0, 0.0, 0.0); } #else if (edge_distance>blend_half_width) { return vertexColor; } else if (edge_distance>-blend_half_width) { return vec4(vertexColor.rgb, vertexColor.a * smoothstep(1.0, 0.0, (blend_half_width-edge_distance)/(blend_width))); } else { return vec4(0.0, 0.0, 0.0, 0.0); } #endif } vec4 textColor(vec2 src_texCoord) { float sample_distance_scale = 0.75; vec2 dx = dFdx(src_texCoord)*sample_distance_scale; vec2 dy = dFdy(src_texCoord)*sample_distance_scale; float distance_across_pixel = length(dx+dy)*(TEXTURE_DIMENSION/GLYPH_DIMENSION); // compute the appropriate number of samples required to avoid aliasing. int maxNumSamplesAcrossSide = 4; int numSamplesX = int(TEXTURE_DIMENSION * length(dx)); int numSamplesY = int(TEXTURE_DIMENSION * length(dy)); if (numSamplesX<2) numSamplesX = 2; if (numSamplesY<2) numSamplesY = 2; if (numSamplesX>maxNumSamplesAcrossSide) numSamplesX = maxNumSamplesAcrossSide; if (numSamplesY>maxNumSamplesAcrossSide) numSamplesY = maxNumSamplesAcrossSide; vec2 delta_tx = dx/float(numSamplesX-1); vec2 delta_ty = dy/float(numSamplesY-1); float numSamples = float(numSamplesX)*float(numSamplesY); float scale = 1.0/numSamples; vec4 total_color = vec4(0.0,0.0,0.0,0.0); float blend_width = 1.5*distance_across_pixel/numSamples; float blend_half_width = blend_width*0.5; // check whether fragment is wholly within or outwith glyph body+outline float cd = distanceFromEdge(src_texCoord); // central distance (distance from center to edge) if (cd-blend_half_width>distance_across_pixel) return vertexColor; // pixel fully within glyph body #ifdef OUTLINE float outline_width = OUTLINE*0.5; 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 #else if (-cd-blend_half_width>distance_across_pixel) return vec4(0.0, 0.0, 0.0, 0.0); // pixel fully outside glyph body #endif // use multi-sampling to provide high quality antialised fragments vec2 origin = src_texCoord - dx*0.5 - dy*0.5; for(;numSamplesY>0; --numSamplesY) { vec2 pos = origin; int numX = numSamplesX; for(;numX>0; --numX) { vec4 c = distanceFieldColorSample(distanceFromEdge(pos), blend_width, blend_half_width); total_color = total_color + c * c.a; pos += delta_tx; } origin += delta_ty; } total_color.rgb /= total_color.a; total_color.a *= scale; return total_color; } #else vec4 textColor(vec2 src_texCoord) { #ifdef OUTLINE float alpha = TEXTURE(glyphTexture, src_texCoord).ALPHA; float delta_tc = 1.6*OUTLINE*GLYPH_DIMENSION/TEXTURE_DIMENSION; float outline_alpha = alpha; vec2 origin = src_texCoord-vec2(delta_tc*0.5, delta_tc*0.5); float numSamples = 3.0; delta_tc = delta_tc/(numSamples-1.0); float background_alpha = 1.0; for(float i=0.0; i1.0) outline_alpha = 1.0; if (outline_alpha==0.0) return vec4(0.0, 0.0, 0.0, 0.0); // outside glyph and outline vec4 color = mix(BACKDROP_COLOR, vertexColor, smoothstep(0.0, 1.0, alpha)); color.a = vertexColor.a * smoothstep(0.0, 1.0, outline_alpha); return color; #else float alpha = TEXTURE(glyphTexture, src_texCoord).ALPHA; if (alpha==0.0) vec4(0.0, 0.0, 0.0, 0.0); return vec4(vertexColor.rgb, vertexColor.a * alpha); #endif } #endif void main(void) { if (texCoord.x<0.0 && texCoord.y<0.0) { osg_FragColor = vertexColor; return; } #ifdef SHADOW float scale = -1.0*GLYPH_DIMENSION/TEXTURE_DIMENSION; vec2 delta_tc = SHADOW*scale; vec4 shadow_color = textColor(texCoord+delta_tc); shadow_color.rgb = BACKDROP_COLOR.rgb; vec4 glyph_color = textColor(texCoord); #if 0 vec4 color = mix(shadow_color, glyph_color, glyph_color.a); #else // lower the alpha_power value the greater the staturation, no need to be so aggressive with SDF than GREYSCALE #if SIGNED_DISTANCE_FIELD float alpha_power = 0.6; #else float alpha_power = 0.5; #endif // over saturate the alpha values to make sure the font and it's shadow are clear shadow_color.a = pow(shadow_color.a, alpha_power); glyph_color.a = pow(glyph_color.a, alpha_power); vec4 color = mix(shadow_color, glyph_color, glyph_color.a); #endif #else vec4 color = textColor(texCoord); #endif if (color.a==0.0) discard; osg_FragColor = color; }