Faux-3D Performant Emissive Text

What We Needed Emissive Text For

Note: Skip this section if you’re only here to read about the emissive text

One of the biggest challenges we’ve faced during beta development is quite simple: explaining to players what they have to do.

The concept of collecting a minimum number of StratoSpheres and handing them in at the “exit” is easily taught with inelegant solutions like text popups or tutorial mazes designed solely to teach that mechanic. But with our recent level design overhaul we’ve dropped the entire concept of “tutorial” mazes and are aiming to create one whole experience during which you learn mechanics at a natural pace. And of course we favor elegant solutions over annoying text popups.

This is one of our recent attempts to highlight how many StratoSpheres are needed to hand in:

Piggybacking off of the four pillars that are already part of the exit to display how many are left to hand in will (hopefully) highlight how the mechanic works.

How We Created Faux-3D Emissive Text

Creating performant “true” 3D text with an emission effect is a difficult challenge that I couldn’t overcome. From what I found, it’s difficult to get multiple materials to play nice when attached to a 3D textmesh. I really wanted to use 3D text to take advantage of the mesh batching that would come with it, so I tried some inefficient workarounds like a child object mesh renderer with an emission effect. No dice, didn’t look good.

What I ended up doing was create a regular world Canvas with 2D text and applying a Standard Specular emission effect.

Aside: If anyone knows of a more efficient shader or technique for emissive effects (especially for mobile devices) PLEASE ping me in the comments section (or at deniz@variancecs.com) as I could not find much on that topic..

2D world-canvas text of course creates the problem shown here:

As the player moves around in 3D space, they won’t always see the 2D text. We could have the text auto-rotate to always face the player using a dot product, but that’s an expensive operation to perform every single frame. Luckily in our game, the player can only ever be in one of four rotations on the Y axis: 0, 90, 180, 270. So instead of rotating every frame, we can rotate the text to face the player only when the player’s rotation has changed. So it boils down to this:

void RotateGoalText(int nextRot)
{
foreach (ui_text r in ui_goal_text)
{
ui_text.SetRotation(nextRot);
}
}

public void SetRotation(int setRot)
{
t.rotation = Quaternion.Euler(t.rotation.x, setRot, t.rotation.z);
}

How To Apply This Solution To A Different Game

If I were to apply this same solution to a game where the player can be at any Y rotation 0 to 360, or any rotation in general, it’s worth checking if the text is even being rendered before calculating a rotation vector.

For a 2D world Canvas this isn’t a straightforward task, so if you can work with a 3D text mesh that’s much better since you can simply use renderer.isVisible.

Once you know the text is being rendered, then you can calculate the dot product to the player and rotate the text accordingly. Personally, instead of doing this every frame, I would use a Coroutine to wait for X number of frames to pass until I recalculate, since it’s unlikely that the player will notice that the text isn’t rotating to perfectly face them every frame but rather every 5 or 10 frames.

Leave a Reply

Your email address will not be published. Required fields are marked *