A Fuzzy Shadow Behind Text

How might I go about creating a soft-shadow/outline effect around a piece of dynamic text?

To be specific, I have a TextNode that I’m using to identify the current object (if any) that the player is looking at. Since the backdrop against which this text is shown may vary considerably, I want a means of separating said text from the background. The specific effect that I have in mind is a fuzzy black “outline” or “shadow” behind the text, perhaps slightly offset–in short, conceptually: Copy the text to a layer below the main text, then expand the glyph (perhaps along normals if the glyphs are polygonal or via pixel-dilation if they’re a raster image). Finally, blur the layer.

I’m currently using TextNode’s “setShadow” method, but as that only allows an offset the shadow produced doesn’t surround the text, and thus doesn’t quite separate it from the background. I’d rather not have a solid rectangular backdrop behind the text, and so would prefer to not just place a card behind it.

One thing that has occurred to me in writing this post is that I could produce a non-specific “shadow” texture which could be applied to the TextNode’s card and which might do the job–that might serve if there isn’t a sufficiently easy way of creating something like the shadow effect that I described above. If I do end up using this approach, is there a way of breaking the card behind a TextNode into three parts, with only the middle section being stretched, so that the ends remain undistorted?

The first idea I had is to draw the text to a buffer, downscale, blur, invert colors, upscale then put the original text on top and finaly put it back on the screen.

Putting the text on a card with partially transparent backgroud and a fading edge would be simpler.

Depending on the font you might try making a fake shadow using a bold version of the font (if there is one)

The TextNode also has a method called setGlyphScale, maybe you can use it to make the shadow bigger? I never used that so I don’t know how it works.

Duplicate the text, and give the bottom version of the text a different color and an LOD bias so that it samples a higher mipmap level. This is generally a very cheap and very effective way to get a texture showing up more blurry.

1.9 allows you to sample the same texture in different ways by using a SamplerState. So you’d have to replace the SamplerState using which the texture is assigned to the bottom TextNode with one on which you called set_lod_bias or set_min_lod.

Ah, that seems like just the thing–thank you! :slight_smile:

However, I’m not seeing the relevant methods in either the documentation or my copy of the repository, in any of NodePath, PandaNode, or TextNode. (I will admit that I’m very tired right now, and fear that I could easily be missing something quite obvious… ^^; )

Heh, yes, your first option doesn’t look worth it, given the possibility of the second and the result achieved. ^^;

I do think that some sort of simple card-based setup is likely a good fallback position, however.

Actually, I just discovered Panda can already generate fuzzy shadows. Try this code:

from panda3d.core import *

# Change the font to have an outline
font = TextProperties.get_default_font()
font.set_bg((0, 0, 0, 0))
font.set_outline((0, 0, 0, 0.7), 2, 0.5)

# Create TextNode
tn = TextNode('text')
tn.set_text('Lorem pandum dolor sit amet')

# Display it
from direct.showbase.ShowBase import ShowBase
base = ShowBase()
np = base.aspect2d.attach_new_node(tn)
np.set_scale(0.1)
base.run()

Note the set_outline call. First parameter is the color of the outline, second parameter is the width in pixels, and third is a float between 0 and 1 that indicates how fuzzy it should be.

Wow! That is so cool, I vote it Panda Feature of the Week :smiley:

Ah, wonderful! It looks as though I have some parameter-tweaking to do, but this looks like just the thing! Thank you! :slight_smile: