Mobile
 

iPhone 3D Programming : Crisper Text with Distance Fields (part 3) - Implementing Outline, Glow, and Shadow Effects

 
12/13/2011 6:14:41 PM

5. Implementing Outline, Glow, and Shadow Effects

Using shaders with distance fields can also achieve a variety of special effects, as shown in Figure 4. In the interest of brevity, I won’t go into too much detail here; much like the smoothing example from the previous section, all these effects rely on using smoothstep and various offsets from the distance=0 boundary. They also make use of a GLSL function called mix; here’s its declaration:

float mix(float x, float y, float a)

You probably already guessed that this function performs linear interpolation between its first two arguments:

mix(x, y, a) = x * (1 - a) + y * a

See Example 4 for an “übershader” that can produce any of the aforementioned distance field effects, depending on how the application sets up the uniforms. If you’re trying to run this shader on the simulator, you’ll need to remove the top line and replace the fwidth function with a constant.


Example 4. Distance field übershader

#extension GL_OES_standard_derivatives : enable

varying mediump vec2 TextureCoord;

uniform sampler2D DistanceField;
uniform mediump vec3 OutlineColor;
uniform mediump vec3 GlyphColor;
uniform mediump vec3 GlowColor;

uniform bool Outline;
uniform bool Glow;
uniform bool Shadow;

const mediump vec2 ShadowOffset = vec2(0.005, 0.01);
const mediump vec3 ShadowColor = vec3(0.0, 0.0, 0.125);
const mediump float SmoothCenter = 0.5;
const mediump float OutlineCenter = 0.4;
const mediump float GlowBoundary = 1.0;

void main(void)
{
mediump vec4 color = texture2D(DistanceField, TextureCoord);
mediump float distance = color.a;
mediump float smoothWidth = fwidth(distance);
mediump float alpha;
mediump vec3 rgb;

if (Outline) {
mediump float mu = smoothstep(OutlineCenter - smoothWidth,
OutlineCenter + smoothWidth,
distance);
alpha = smoothstep(SmoothCenter - smoothWidth,
SmoothCenter + smoothWidth, distance)
rgb = mix(GlyphColor, OutlineColor, mu);
}

if (Glow) {
mediump float mu = smoothstep(SmoothCenter - smoothWidth,
SmoothCenter + smoothWidth,
distance);
rgb = mix(GlyphColor, GlowColor, mu);
alpha = smoothstep(SmoothCenter, GlowBoundary, sqrt(distance));
}

if (Shadow) {
mediump float distance2 = texture2D(DistanceField,
TextureCoord + ShadowOffset).a;
mediump float s = smoothstep(SmoothCenter - smoothWidth,
SmoothCenter + smoothWidth,
distance2);
mediump float v = smoothstep(SmoothCenter - smoothWidth,
SmoothCenter + smoothWidth,
distance);

// If s is 0, then we're inside the shadow;
// if it's 1, then we're outside the shadow.
//
// If v is 0, then we're inside the vector;
// if it's 1, then we're outside the vector.

// Totally inside the vector (i.e., inside the glyph):
if (v == 0.0) {
rgb = GlyphColor;
alpha = 0.0;
}

// On a nonshadowed vector edge:
else if (s == 1.0 && v != 1.0) {
rgb = GlyphColor;
alpha = v;
}

// Totally inside the shadow:
else if (s == 0.0 && v == 1.0) {
rgb = ShadowColor;
alpha = 0.0;
}

// On a shadowed vector edge:
else if (s == 0.0) {
rgb = mix(GlyphColor, ShadowColor, v);
alpha = 0.0;
}

// On the shadow's outside edge:
else {
rgb = mix(GlyphColor, ShadowColor, v);
alpha = s;
}
}

gl_FragColor = vec4(rgb, alpha);
}



The shadow effect in Example 4 deserves further explanation. It applies anti-aliasing to the transition not only between the vector and the background but also between the shadow and the background and between the vector and the shadow. The shader pulls this off by deciding which of the following five regions the pixel falls into (see Figure 7):

  1. Completely within the vector

  2. On a vector edge that’s not shadowed

  3. Completely within the shadow

  4. On a vector edge that’s shadowed

  5. On the shadow’s outside edge

Figure 7. Shadow regions

 
Others
 
- iPhone 3D Programming : Crisper Text with Distance Fields (part 2) - Smoothing and Derivatives
- iPhone 3D Programming : Crisper Text with Distance Fields (part 1) - Generating Distance Fields with Python
- Mapping Well-Known Patterns onto Symbian OS : Singleton
- Mapping Well-Known Patterns onto Symbian OS : Model–View–Controller
- The Anatomy of a Mobile Site : STYLING WITH CSS - CSS Considerations for Mobile & Optimizing CSS
- The Anatomy of a Mobile Site : INVOKING OTHER DEVICE CAPABILITIES & THE STATE OF JAVASCRIPT
- iPad Development : The Dual-Action Color Popover (part 3) - Serving Two Masters
- iPad Development : The Dual-Action Color Popover (part 2) - Hooking Up the Grid
- iPad Development : The Dual-Action Color Popover (part 1) - Creating a Simple Color Grid
- XNA Game Studio 3.0 : Creating Fake 3-D - Creating Shadows Using Transparent Colors
- Android Application Development : ViewGroups (part 2) - ListView, ListActivity, ScrollView & TabHost
- Android Application Development : ViewGroups (part 1) - Gallery and GridView
- Java ME on Symbian OS : MIDP 2.0 Game API Core Concepts
- Java ME on Symbian OS : Building a Simple MIDP Game
- jQuery 1.3 : Compound effects & Creating custom animations
- jQuery 1.3 : Effects and speed
- Mobile Web Apps : Quick Wins (part 2) - Form Field Attributes
- Mobile Web Apps : Quick Wins (part 1) - Nifty Links
- iPhone Developer : Using Creative Popping Options
- iPhone Developer : Navigating Between View Controllers
 
 
Most View
 
- SQL Server 2012 : Fault Tolerance - High Availability Features in SQL Server (part 3) - Configuring Database Mirroring
- Deploying Exchange Server 2010 : Running and Modifying Exchange Server 2010 Setup
- Understanding Core Exchange Server 2013 Design Plans (part 1) - Planning for Exchange Server 2013
- Sharepoint 2013 : Building an Application with Access Services (part 6) - Adding a Macro, Reporting and External Data
- Microsoft Dynamics Sure Step 2010 : Quality Management and Optimization (part 2) - The Sure Step Optimization Offerings Roadmap
- BizTalk 2009 : Getting Started with Pipeline Development (part 1) - Pipeline Stages & Understanding Pipeline Execution
- Iphone Application : Implementing Location Services - Understanding Core Location
- Lync Server 2013 Clients : Mac Client - Navigation and Layout (part 2)
- Active Directory 2008 : Monitoring and Troubleshooting Active Directory Replication
- Using Windows Azure WCF Services in SharePoint and Office : Create the WCF Service
 
 
Top 10
 
- Microsoft Access 2010 : Introduction to Relational Database Design (part 2) - Normalization and Normal Forms
- Microsoft Access 2010 : Introduction to Relational Database Design (part 1) - Rules of Relational Database Design
- Windows Phone 8 : Scheduled Notifications (part 3) - Reminder Registration, Reminder Sample
- Windows Phone 8 : Scheduled Notifications (part 2) - Alarm Registration, Alarm Sample
- Windows Phone 8 : Scheduled Notifications (part 1)
- Windows 8 : Customizing the Start Screen (part 5) - Adding Shutdown and Restart Tiles to the Start Screen, Customizing the Start Screen Background
- Windows 8 : Customizing the Start Screen (part 4) - Pinning a Website to the Start Screen,Displaying the Administrative Tools on the Start Screen
- Windows 8 : Customizing the Start Screen (part 3) - Turning Off a Live Tile, Pinning a Program to the Start Screen
- Windows 8 : Customizing the Start Screen (part 2) - Creating an App Group
- Windows 8 : Customizing the Start Screen (part 1) - Resizing a Tile, Moving a Tile