0

I have a well-established OpenGL project (in c# using SharpGL, if that helps), and within it is a class that can handle drawing points, lines (well, line stripes), and triangles (for filled polygons). Currently, my single shader program consists of a vertex shader and a fragment shader, which works for any of the three primitive types.

However, in reality, any lines in the resulting graphic (from line stripes or lines between triangle vertices) need to follow a curvature within a well-understood geometry (I know how to calculate points between the vertices that will follow the curve).

Given that, I now want to introduce tessellation shaders (control and evaluation) to add the additional points needed to display the curvatures.

That leads to my main questions:

  1. Is there a way to have one shader program where the tessellation shaders can be told at runtime how many vertices are in the input patches about to be rendered (i.e., there will be 2 vertices per patch when rendering lines but 3 when rendering triangles)?
  2. Further, can the tessellation shaders dynamically decide how many vertices will be output (e.g., if the 2 vertices of a line segment are too far apart, I may want to increase the number of vertices in the output to better depict the curvature).

I've had a hard time researching these questions as most tutorials focus on other, more fundamental aspects of tessellation shaders.

I know that there is an OpenGL call, glPatchParameter, that lets me set patch vertex size as well as default outer and inner patch sizes, but does that forego the need for having layout(vertices = patch_size​) out; in the shader code? Is there a way for me to access, for example, the patch vertex size set using glPatchParameter from within the shader code (other than passing in my own, additional uniform variable)? Are there any good examples out there of code that does something similar to what I'm looking for?

genpfault
  • 51,148
  • 11
  • 85
  • 139
FTLPhysicsGuy
  • 1,035
  • 1
  • 11
  • 23
  • 1. No. 2. *"can the tessellation shaders dynamically decide how many vertices will be output "* - for this is the [Tessellation Control Shader](https://www.khronos.org/opengl/wiki/Tessellation_Control_Shader) and the tesselation levels (see [Tessellation primitive generation](https://www.khronos.org/opengl/wiki/Tessellation#Tessellation_primitive_generation)) – Rabbid76 Dec 03 '21 at 19:09
  • "*there will be 2 vertices per patch when rendering lines but 3 when rendering triangles*" Wouldn't your algorithm have to be different for the different numbers of input vertices? I don't know how it could use the same algorithm for rendering a single line vs. rendering a triangle. – Nicol Bolas Dec 03 '21 at 19:12
  • @Rabbid76 Copy that. So the TCS doesn't have to have a pre-determined number of vertices it outputs for a given patch? Do I even need a `layout(vertices = patch_size​) out;` command in my TCS if the number of output vertices can be changed dynamically? Thanks. – FTLPhysicsGuy Dec 03 '21 at 19:24
  • @NicolBolas Yes, I would have to use if-then statements to handle the two different patch sizes (which is why I asked about accessing the patch size in the shader code), but I would still be able to keep one shader program instead of using a different program for each of the primitive types. Hope that helps clarify my questions. – FTLPhysicsGuy Dec 03 '21 at 19:26
  • 1
    @FTLPhysicsGuy The tessellation levels have nothing to do with the patch size. – Rabbid76 Dec 03 '21 at 19:27

1 Answers1

2

The TCS and TES do not define the input patch size. They can query the patch size effectively by using the .length() function on any arrayed input parameter.

However, the size of the output patch from the TCS is a compile-time fixed part of the TCS itself. So even if you could make a TCS that could handle 2 or 3 input vertices, it wouldn't be able to selectively choose between 2 or 3 output vertices based on the number of input vertices.

So you're going to need to use different programs. If you're able to use SPIR-V shaders, you can use specialization constants to set the number of output vertices in the patch. You would still get different programs, but they would all come from the same shader source.

You can also do some find/replace stuff with the text of your shader before compiling it to get the same effect.

Note: do not mistake the number of vertices output by the TCS with the amount of tessellation done to the abstract patch. They are in no way related.

Further, can the tessellation shaders dynamically decide how many vertices will be output (e.g., if the 2 vertices of a line segment are too far apart, I may want to increase the number of vertices in the output to better depict the curvature).

This is about tessellation levels. And basically 80% of the job of the TCS is to decide how much tessellation to do.

Lines are somewhat tricky in as far as tessellation works. An isoline output "patch" is really a sequence of lines. The number of lines is defined by gl_TessLevelOuter[0], and the subdivisions within each line are defined by gl_TessLevelOuter[1]. But since the amount of tessellation is capped (implementation-defined, but is at least 64), if you need more than this number of subdivisions for a single conceptual line, you'll have to build it out of multiple lines.

This would be done by making the end-point of one line binary-identical to the start-point of the next line in the tessellated isoline patch. Fortunately, you're guaranteed that gl_TessCoord.x will be 0 and 1 exactly for the start and end of lines.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • You noted: _do not mistake the number of vertices output by the TCS with the amount of tessellation done to the abstract patch_. So is the output number of vertices generally the same as the input patch size regardless of the tessellation level? e.g. you input a triangle and you output a triangle (along with additional point information derived from the tessellation levels)? – FTLPhysicsGuy Dec 03 '21 at 19:37
  • I'd looked into the use of the isoline output patch concept, and so I get what you're saying there. However, when you note the cap on the amount of tessellation, you note that if I need more I'll have to "_build it out of multiple lines_." Do you mean I'd do this external to the shader (e.g., add the points to my VBO) or do you mean I would somehow "trick" the tessellation shader? I ask this because of your final paragraph where you note the end/start points in terms of the gl_TessCoord values. Thanks! – FTLPhysicsGuy Dec 03 '21 at 19:48
  • I won't delete my previous comment, but I think I understand now. If I need more subdivisions than the cap, I could, for example, set `gl_TessLevelOuter[0] = 2` and interpret the first line as creating subdivisions for the first half of my line segment while using the second line to create subdivisions for the second half. I could interpret the coords for the first subdivision as 0 - 1 => 0 - 0.5 and I'd interpret the coords of the second subdivision as 0 - 1 => 0.5 - 1 (or something like that). Right? – FTLPhysicsGuy Dec 03 '21 at 23:10