1
\$\begingroup\$

Imagine a scene with a minecraft style world held in a bounded container and is being viewed from a isometric 3rd person camera that has a fixed orientation. I want to create a shader that expresses as much information the player might want to know, e.g. x-ray vision of tunnels and areas behind walls that the player might be in close proximity to but would normally be occluded by the terrain. Objects (such as the player) can be inside the object and should be blended nicely with the x-rayed layers.

Here is a rough illustration to convey the idea:

Crude example of how I'd like it to look like if there was inside geometry being occluded This is how it would look if the shader did the following:

  • Render back to front
  • The first (furthest depth) fragment has an alpha of 1, and after that each overlapping fragment is alpha blended using an alpha of 0.5 (or maybe of decreasing alpha, so e.g. 2nd fragment is 0.5, 3rd is 0.33, 4th is 0.25 so we favor preserving further fragments information).

So AFAICT, this shader would alpha blend like a normal transparent shader, except that it doesn't blend/interact with anything but itself. How to do that?

I have little experience with shaders but am comfortable if I know where to read. So I'd really appreciate it if someone could point me in the direction I can look to create such a shader. The project is using Unity at the moment but I don't think that changes the approach to this problem.

Update: After clarifying some thoughts I realize that the approach described above wouldn't be the most suitable solution in my case. This is because I forgot to emphasize that the most important thing is to visualize geometry within a proximity around the player, and that current approach would potentially obscure too much of the players view if there is a lot of layers drawn in front, and it would also look a bit too "busy" in general; the player should probably prefer to just know the information most relevant to him and nothing that is relatively far away. So instead I think the blending should be most x-ray view for geometry within close proximity to the player, and fade out to the foreground as it gets more distant.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I can think of a way to do this in two passes with a floating point render target initialized to black:

Pass 1: use additive blending into the render target with depth testing/writing off; write your colour to the RGB channel and 1 to the alpha channel.

Pass 2: read the previous contents of the render target, and divide the RGB values by the alpha value, outputting the result as an opaque colour (no blending).

For pixels written to only once, this is basically a no-op and just gives the original colour you wrote. For pixels written to multiple times, this gives the average colour, with each write given an equal weighting. That matches your 1, 0.5, 0.33, 0.25 weight series.

This second pass can be the one that writes into your original scene, with depth testing/writing enabled to clip out any occluded parts of this object.

\$\endgroup\$
5
  • \$\begingroup\$ Unfortunately I'm still a bit stumped. One thing I forgot to mention is that there could also be other object geometry inside the x-rayed object. Based off your idea I was thinking to do as you describe except to also do depth checks in the first pass and treating any pixels that pass as the first layer by adding them to a render texture (no writes though so it would only test against other geometries), and then the x-ray geometry would layer on-top as normal if they pass the depth test. Finally we do a 2nd pass which just divides colors by alpha. \$\endgroup\$
    – Buretto
    Sep 23 at 16:49
  • \$\begingroup\$ Some problems are that it isn't nice to work with for further rendering down the pipline if there is any, like since depth isn't written and blending with transparent objects inside the object wouldn't blend correct. \$\endgroup\$
    – Buretto
    Sep 23 at 16:53
  • \$\begingroup\$ I've updated the question to better describe the situation. I apologize for not being very clear at the beginning I was a bit lost and needed to clarify my thoughts. Currently I have a rough idea that I hope might work. First write to a render texture all the geometry within proximity to the player blended so it has highest alpha around the player. Then blend this with the result of drawing the whole thing completely opaque. \$\endgroup\$
    – Buretto
    Sep 23 at 18:49
  • \$\begingroup\$ It won't blend with other transparent objects that are inside it, but AFAICT that isn't really a feasible goal without re-designing everything around it so I am okay without it. Perhaps can reduce overdraw by doing depth tests during the whole process so we ignore anything occluded by other objects and the final depth result is written based on the furthest back depth in the blend (I guess we'd get this by writing the minimum depth of close proximity geometry to the render texture). \$\endgroup\$
    – Buretto
    Sep 23 at 19:08
  • \$\begingroup\$ But might not do that last thing since the whole thing might have to be drawn last if I really want to make the player's view always visible (so other meshes don't obscure view). \$\endgroup\$
    – Buretto
    Sep 23 at 19:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .