15
\$\begingroup\$

In this Overwatch gameplay video, the character's shield lights up white in areas that are near other objects' geometry.

Reinhart's shield clipping some level geometry

Note the white edges on the blue shield, near the floor, walls and pillar.

I believe the shield has its own model and the effect is done with a shader, but I'm lost trying to figure how to translate the concept of "nearness" to shader programming.

\$\endgroup\$
28
+50
\$\begingroup\$

A general outline:

  1. Create a depth map of your scene without the shield. You can get this effectively for free, since transparent objects are often rendered in a later pass anyway. Otherwise, you can create the depth map by rendering the scene sans shield onto an RTT with a depth shader.

  2. Render your scene normally, pass the depth map to your shield shader.

  3. In the shader, compute the difference in scene depth from the shield fragment's depth, and use that difference to modify the fragment colour.

Demo

I wrote a simple WebGL demo of that.

screenshot of the demo

Line by line

Let's go over the fragment shader code in detail:

float solidsDepth = texture2D(depthMap, gl_FragCoord.xy / dims).r;

Sample the depth map at every fragment. Remember to divide by your viewport dimensions to convert your fragment from screen space [0, width/height] to normalized [0.0, 1.0] coordinates. At this point, if you simply set the fragment color to the sampled depth map pixel, it would look like this:

screenshot of depth map

The depth map is grayscale, so you can get the value from any channel (I used r here).

float solidsDiff = 1.0 - smoothstep(
    zNear,
    zFar,
    gl_FragCoord.z / gl_FragCoord.w
  ) - solidsDepth;

You can then use that depth sample to find the difference between the scene depth and the depth of the shield fragment. Remember to normalize your depth also, to take it from [zNear, zFar] (the near and far planes of your camera) to [0.0, 1.0]. smoothstep does this nicely. The 1.0 - is to invert the value such that solidsDiff is 1.0 when the difference is the maximum (zFar - zNear) and 0.0 at the minimum (0.0).

Note that I've assumed solidsDepth was already normalized in the depth shader that created the depth map.

float alpha = 0.3 + max(0.0, 1.0 - log(100.0 * (solidsDiff - 0.005) + 1.0));

You can then modify the alpha channel of your shield depending on the depth difference. Here we start at a minimum alpha of 0.3, then create a nice sharp increase in alpha as we near 0.0 difference.

The - 0.005 offset just adds a white margin to make the "intersection" thicker. Try modifying it!

gl_FragColor = vec4(vec3(1.0), alpha);

And finally, apply that alpha to your fragment color.


Enhancements

You could make a curved shield, add plasma for an "energy shield" look (demo) or explore effects with just the intersections showing (demo).

The sky Your graphics card is the limit!

\$\endgroup\$
  • \$\begingroup\$ Oh. My. Goodnews. Ty for the awesome tutorial. \$\endgroup\$ – Blue Bug Nov 22 '15 at 11:42
5
\$\begingroup\$

It's just using the depth map. It renders the world then renders the shield and takes a difference between the shield's rendered z value and the depth buffer z value to tint the pixel more white.

\$\endgroup\$
3
\$\begingroup\$

I don't know which Engine, if any, you are using. Or which language you are working with. Still, most of what you can find online is not hard to port from one environment to the other to achieve what you are looking for.

And there certainly is material online that can be of help to you. See this discussion related to Unity: http://www.superspacetrooper.com/2012/06/tutorial-force-field-weapon-impact-energy-dispersion/ and this question UE4-related: https://answers.unrealengine.com/questions/74858/dynamic-forcefield-shader.html . For a complete shader example, implementing that shield effect, from a quite recent debate in Reddit, you can see: https://www.reddit.com/r/Unity3D/comments/3edi0n/does_any_one_knows_how_to_make_this_shield_effect/ And for a tutorial that is not exactly on that but is related enough to of interest: http://www.nightbox-studios.com/2015/09/05/assets-shield-effect-scripts-for-texture3d-perlin-noise-shader/

Also, here are the links for 3 related questions previously made in this very site, that are likely to be of great help to grasp the concepts behind what you want to achieve:

Spaceship Shield Flare

How to implement a starwar energy shield in game

XNA shield effect with a Primative sphere problem

Lastly, there are quite a few nice implementations of shield shaders both in Unity and in Unreal Engine in their respective virtual store, if you happen to be using any of those engines. They are generally paid assets of course, but are almost always open source after buying - and are frequently cheap. Even if you don't happen to use these engines, those assets can be of help to play around and learn.

Hope it helps.

\$\endgroup\$
  • \$\begingroup\$ Although those links are helpful, this answer is basically just links and doesn't actually address the question directly. It would be better to extract the relevant content of the links into an actual explanation. \$\endgroup\$ – Anko Nov 20 '15 at 13:08
  • \$\begingroup\$ While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review \$\endgroup\$ – Vaillancourt Nov 20 '15 at 13:13
  • \$\begingroup\$ @Anko Sure, my bad. I usually include an explanation and a collection of links, but this time you are right, the real explanation was missing. I will probably delete the answer, then. \$\endgroup\$ – MAnd Nov 20 '15 at 19:34
  • \$\begingroup\$ @AlexandreVaillancourt I don't like the idea of just copy-paste from another link instead of redirecting the OP to the original source. Then, what I think is best is to give links in the comments to the question. The problem with such is when you know plenty of material that can be of help but it's too big for comments. But still, since a good explanation answer was already posted here, I will just erase this one \$\endgroup\$ – MAnd Nov 20 '15 at 19:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.