A general outline:
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.
Render your scene normally, pass the depth map to your shield shader.
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.

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:

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!