3

I am currently drawing a grid using a series of triangle strips. I am using this to render a height field, and generating the vertex data completely in the vertex shader without any input buffers just using the vertex and instance indexes. This is all working fine and is very efficient.

However, I now find myself also needing to implement border lines on this grid. The obvious solution here would be something like marching squares. Basically, what I want to achieve is something like this:

Diagram of what I want

The black dots represent the vertices in the grid that are part of some set, and I want to shade the area inside the red line differently than that outside it.

Naïvely, this seems like it would be easy: Add a value to the vertices that is 1 for vertices in the set and 0 for those outside it, and render differently depending on if the interpolated value is above or below 0.5, for instance.

However, because this is rendered as a triangle strip, this does not quite work. In pracitce, since this is rendered as a triangle strip, this ends up looking like this:

enter image description here

So, half the edges work and half end up with ugly square staircases.

I've now been trying to wrack my brain for days whether there is some trick that could be used to generate the vertex values differently or making a more complicated test than >0.5 to get closer to the intended shape without giving up on the nice and simple triangle strips and having to actually generate geometry ahead of time, but I can not think of one.

Has anyone ever dealt with a similar problem? Is there some clever solution I am missing?

I am doing this in Metal, but I don't expect this to depend much on the specific API used.

Dag Ågren
  • 1,064
  • 7
  • 18
  • 1
    "*what I want to achieve is something like this*" What is an algorithm that would generate such a thing from a field of dots? Specifically, the long line at the end doesn't make any sense. There are no dots in the middle of it to sustain such a long line. – Nicol Bolas Oct 18 '21 at 01:43
  • 1
    Marching squares, as I mentioned in the post, will do that. – Dag Ågren Oct 18 '21 at 08:03
  • 1
    Then... use that algorithm. Are you saying that you're using that algorithm and not getting the right result? – Nicol Bolas Oct 18 '21 at 13:20
  • 2
    The question is whether there is a way to emulate the results of marching squares while retaining the current rendering method based on triangle strips, which is very useful for other reasons. – Dag Ågren Oct 18 '21 at 14:05
  • I don't understand what triangle strips have to do with drawing lines. That's what you said you're trying to do: "implement border lines". – Nicol Bolas Oct 18 '21 at 14:46
  • 3
    @NicolBolas: I don't think OP is trying to draw lines. The OP "wants to shade the area inside the ... line differently than that outside it". So, presumably, those lines are just illustrations of the boundary between the inside and the outside of the shaded regions. – Yakov Galka Oct 18 '21 at 14:53
  • 1
    Yes, that is exactly it. I blame the limitation of the tool I used to draw the diagram. – Dag Ågren Oct 18 '21 at 18:35

1 Answers1

2

It sounds like you're trying to calculate the colors in the fragment shader independently of the mesh underneath. If so, you should decouple the color calculation from the mesh.

Assuming your occupancy is stored in a texture, use textureGather to get the four nearby occupancy values; determine the equation of the boundary; then use the fractional part of the texture coordinates to determine its position relative to the boundary. (The devil here is in the details -- in particularly the ambiguous checker-board pattern case.)

Once you implement the above approach, it's very likely you won't even need the triangle strip mesh anymore -- simply fill your entire drawing area with a single large quad and let the fragment shader to do the rest.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • Well, since I am reading that same texture anyway in the vertex shader, I guess I was hoping to give the memory bandwidth a break by not reading it again in the fragment shader, but you are right that that would work fine. I still need the triangle strip for other reasons, but maybe I do need to consider just doing this. (Also, I won't have many checkerboard cases with my data, and it doesn't matter massively what I do for them, so at least that is not a headache I need to have.) – Dag Ågren Oct 18 '21 at 18:40
  • However that does give me an idea: I can get this data in the vertex shader, and store it as a flat value and then use it in the fragment shader. That saves the memory accesses from the fragment shader but lets me do the same thing you suggest! I think will try it that way! – Dag Ågren Oct 18 '21 at 20:48
  • @DagÅgren I might be mistaken on this one, but this won't necessarily save on memory bandwidth. The values from the vertex shader do not magically appear in the fragment shader; to my understanding the way it's implemented on the GPU is that the vertex shader writes its outputs to a temporary memory buffer that the fragment shader invocations read from. – Yakov Galka Oct 19 '21 at 03:19
  • It's possible. Also if your are drawing a lot of tiny triangles and triangles that get clipped it might be faster to read in the fragment shader, but at least this way it's easy enough to try both and compare. – Dag Ågren Oct 19 '21 at 08:56