16
\$\begingroup\$

I would like to know how to make this effect of merged circle selection. Here are images to illustrate:

enter image description here enter image description here

Basically I'm looking for this effect:

enter image description here

How the merge effect of the circles can be achieved ? I didn't found any explanation concerning this effect. I know that to project those texture I can develop a decal system but I don't know how to create the merging effect.

If possible, I'm looking for purely shaders solution.

\$\endgroup\$
  • \$\begingroup\$ Could you explain what do you mean by "merge effect"? \$\endgroup\$ – wondra Aug 11 '14 at 12:16
  • \$\begingroup\$ Of course, if you look at the top right characters of the screenshot, the decals are not crossing each other but the two on the left cross their blue circle and are merged. I added a new screenshot to show the effect. \$\endgroup\$ – MaT Aug 11 '14 at 12:33
  • \$\begingroup\$ Do you insist on shader solution? If not, you just solved it in your last picture. \$\endgroup\$ – wondra Aug 11 '14 at 13:54
  • \$\begingroup\$ The last screenshot only shows the effect I am targeting. The final result should look like the previous screenshots. \$\endgroup\$ – MaT Aug 11 '14 at 14:02
  • 1
    \$\begingroup\$ Yep, I agree, I think that they build dynamically a mesh circle with the texture and then cut the mesh to merge them. It's also a good solution but I think it's more limited in term of effect you can do. \$\endgroup\$ – MaT Aug 21 '14 at 6:13
8
\$\begingroup\$

There are a few tricks you can do:

Z-buffer

After you have rendered all other objects, for each unit render a transparent circle of smaller size with max Z value. Then render selection circles decals on the ground. Since they are below in Z-order, they will be discarded when under units.

Being fully transparent means that the circle gets written only to Z-buffer (max Z value). Now when you render decals, they are tested against Z buffer values, and if they are passing the test they get rendered (which happens only outside of the circles)

Stencil

Same as with previous approach, but this time use a stencil buffer. Render smaller circles for units with some stencil value, then render selection decals. Setup stencil to discard any elements with your stencil value.

\$\endgroup\$
  • \$\begingroup\$ The Z-Buffer technique is interesting but I don't get how the first transparent circle can clip the ground decals. \$\endgroup\$ – MaT Aug 22 '14 at 7:47
0
\$\begingroup\$

You could for example check in the decal rendering pixel shader if there is an intersection with any other decals and kill the pixel if so. It's quite efficient to do for this kind of circular decals.

\$\endgroup\$
  • 1
    \$\begingroup\$ I assume you have skipped the part from your answer - to pass all the circles locations and radiuses to shader. \$\endgroup\$ – Kromster says support Monica Aug 21 '14 at 4:41
  • \$\begingroup\$ @Krom If OP expresses any interest in the solution, I'm happy to give more details. \$\endgroup\$ – JarkkoL Aug 21 '14 at 12:42
0
\$\begingroup\$

Do you mean those blue circles on the ground?

There may be a smarter way to do this but consider my solution as an example how this can be done. Render your circles to a separate empty texture of the size of the screen. At this point you can blend them together, however you want. Depending on your needs you can write the full color or just the information that a circle is present at given pixel. However, you will definetely need a depth information for each pixel that you write if you want a Z-test effect.

When you render the terrain after the previous step, you can sample the previously created texture, using screen coordinates in pixel shader, as UVs. Now you know, that the circle should or shouldn't be projected at given pixel of the terrain. However, this way it will work as if the Z-test was disabled, so a terrain can't hide any circle. If you want a terrain to hide circles that are behind it, perform a depth test before blending a circle with terrain texture. You can use a small bias to enable rendering of circles that are just a little bit under the terrain but you would still like them to render.


Edit: Now in order to get the effect of merged circles what you need to do is: When rendering to the separate texture, you need to check if there is already a circle rendered where you are trying to render a new one. (Check if the texture has a value there) if so, erase this pixel. This should give the effect of "outline" when two or more circles overlap. For this to work correctly, however you will need to do this test only for the inside of the circle, not the border. So when rendering circles, write some specific value to the output texture, which indicates that it is a circle inside. Then you just need not to render anything on the circle inside and you should be good.

Edit2: For your simple red/green example: Before you render any pixel, check if this pixel is not already green. If it is, don't render. This will do the trick. In fact, while writing to the texture you can even use red/green for outside/inside of the circle, and then while rendering the terrain read those values and convert them to a desired color.

If my answer is too abstract by any chance, let me know.

\$\endgroup\$
  • \$\begingroup\$ I get the general idea but as you say, it's a bit to abstract for me concerning the merged circles :) \$\endgroup\$ – MaT Aug 11 '14 at 14:33
0
\$\begingroup\$

There are a few options. As a general method, stencil buffers often come in very handy where certain drawing needs to be masked out, like the outline where the circles overlap in your example.

In this case, I think this can be done just as easily without a stencil buffer. You can use the depth buffer to eliminate the outline where the circles overlap. The idea is that you draw the interior of the circles into just the depth buffer (since we don't want to see the interior), and then draw the outline. This way, the part of the outline that overlaps with another circle will be eliminated by the depth test.

The only caveat is that you have to be careful about depth fighting. You can use a small offset to make sure that the outlines are in fact behind the interior, and get eliminated by the depth test. An alternative would be to use glPolygonOffset().

Let's say you have two circles that are parallel to the xy-plane, with centers at (x1, y1, z) and (x2, y2, z). And you have these draw functions:

// Draw interior part of circle, shown in green in the schematic in the question.
drawInterior(x, y, z);

// Draw outline of circle, shown in red in the schematic in the question.
drawOutline(x, y, z);

The sequence of drawing then looks like this, with delta being a small offset:

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
drawInterior(x1, y1, z + delta);
drawInterior(x2, y2, z + delta);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
drawOutline(x1, y1, z);
drawOutline(x2, y2, z);
\$\endgroup\$
0
\$\begingroup\$

Off the top of my head, if these decals are drawn as discs, I would test each circle for intersection against each other circle, and put the intersection points into an array. Then draw arcs that are not inside an intersection. This is not a shader solution, though.

\$\endgroup\$
  • \$\begingroup\$ Yeah I thought about that too :) but as you said it's not a shader solution and it is not a very generic solution. But thanks ! \$\endgroup\$ – MaT Aug 14 '14 at 14:08
  • \$\begingroup\$ That's pretty vague description \$\endgroup\$ – Kromster says support Monica Aug 21 '14 at 4:36
0
\$\begingroup\$

You want stenciling here. Your first pass renders the circles to the stencil buffer. The second pass renders the visible outline, anywhere the stencil buffer has not changed. The second pass must use geometry which is larger than the first pass, in this case, a simple linear scalar is sufficient.

While the solution I have for drawing outlines over here is more than you need (as that shader turns every mesh edge into a full quad), it does follow this approach: drawing the original model to the stencil buffer, then rendering a larger version where the stencil buffer is still 0.

\$\endgroup\$
  • \$\begingroup\$ Thanks! So instead of first drawing the visible parts I should start with rendering the transparent circles into the stencil. But how do I render round transparent circles? I can't limit parts of the image to be rendered into the stencil. When I render to the stencil, everything goes there, am I right? \$\endgroup\$ – Doodlemeat Jan 13 '16 at 19:25
  • \$\begingroup\$ Yes, that's why the second pass (the visible portion) is scaled larger: so its bounds are larger than the stencil buffer. You just have to apply a vertex scalar in the second pass (look around for outline shaders, most of them use the simpler scalar I am referring to). You can also not change the stencil buffer if the color is transparent. You'll probably need a second texture mask in this case or you can do some distance math to determine the circle instead. I'd need a couple hours and access to Unity to provide any code. \$\endgroup\$ – Draco18s Jan 13 '16 at 19:31
  • \$\begingroup\$ Hmm, what about having a black/white image just to write to the stencil buffer in the first pass so that black becomes 0 and white becomes 1 in the stencil. Is that even possible? \$\endgroup\$ – Doodlemeat Jan 13 '16 at 19:48
  • \$\begingroup\$ That's what I meant by a second texture mask. I'm pretty sure it would work, I just can't actually verify without having Unity in front of me, which I won't have for over 24 hours. \$\endgroup\$ – Draco18s Jan 13 '16 at 19:49

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.