The OpenGL spec. says:
The variable gl_PrimitiveID is filled with the number of primitives processed
by the drawing command which generated the input vertices. The first primitive generated by a drawing command is numbered zero, and the primitive ID counter is incremented after every individual point, line, or triangle primitive is processed. Restarting a primitive topology using the primitive restart index has no effect on the primitive ID counter.
Unfortunately, I do not quite understand that.
If I make a draw call with GL_PATCHES with number of vertices = 32, do all 32 vertices have gl_PrimitiveID = 0 in the Tesselation Control shader?
Tessellation Control shaders still output a Patch, and a Patch is a single primitive.
Is it correct to assume that when this patch is tessellated as triangles in the Tessellation Evaluation shader, every nth vertex will have its gl_PrimitiveID = n/3?
If not, please explain what their values will be.
OpenGL wiki seems to agree:
gl_PrimitiveID
the index of the current patch within this rendering command.
Looking this up in spec shouldn't be hard, if you need confirmation.
I guess the number of patch within the rendering command would change simply when you process enough vertices and start a new patch.
Related
When not using tessellation shaders, you can pass a primitive type (GL_TRIANGLES, GL_TRIANGLE_STRIP, etc.) to let OpenGL know how the vertex stream is representing geometry faces.
Using tessellation shaders, GL_PATCHES replaces these primitive type enums. This makes sense in my head when processing patches of size 3 or 4, and setting the corresponding layout in the TES to triangles or quads.
But if I have a patch of size 16 (some tutorials do this), how does the TPG know what 3 or 4 vertices form what faces? I've read several times that the order in your vertex buffer does not matter when GL_PATCHES is used, but surely there must be a point where a specific set of 3 vertices is considered a triangle (to pass to e.g. the geometry shader). How is this decided?
The actual tessellation hardware doesn't actually use your patch data. The tessellation unit, the part of the pipeline that actually generates triangles (or lines), operates on an abstract patch. If your TES specifies that the abstract patch is a quad, then the tessellator will perform tessellation on a unit quad.
How many patch vertices you have is completely irrelevant to this process.
The TES is a bit like a vertex shader; it gets called once per vertex. But not per vertex in the GL_PATCHES primitive. It's once per-vertex of the tessellated primitive. So, if you tessellate a quad, and your outer levels are (4, 4, 4, 4) and the inner levels are (4, 4), that will generate 25 vertices. The TES will be called that many times (at least; it can be called multiple times for the same vertex), and it will be told where within the abstract patch that particular vertex is.
The job of the TES is to decide how to use the abstract patch coordinate and the real patch vertex data to generate the actual per-vertex data to be used by the rendering pipeline. For example, if you're creating a Bezier patch, you would have 16 patch vertices. The TES's job would be to take the abstract patch coordinate and use bicubic Bezier interpolation to interpolate the 16 positions on the patch to that particular location in the abstract patch. That becomes the output position. Normals, texture coordinates, and other data can be computed similarly.
The short answer is: The TPG (Tessellation Primitive Generator) doesn't know/care at all about the patch size.
The TPG only cares about the specified input layout of the tessellation evaluation shader (triangle, quad, isoline) and the tessellation levels set by the control shader. It does not have access to the patch itself but generates the tessellation coordinates only based on the type and level used in this tessellation.
The user is than in the tessellation evaluation shader responsible for establishing the relation between the per control point parameters (passed from the tessellation control shader, donated by in/out, somehow similar to varyings) and the gl_TessCoord (coming from the TPG).
Note, that the amount of per control point parameters and the amount of tessellation coordinates is not necessarily the same.
For further reading, the following articles might help:
Primitive Processing in Open GL, especially Figure 8.1
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:
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)?
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?
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.
When not using tessellation shaders, you can pass a primitive type (GL_TRIANGLES, GL_TRIANGLE_STRIP, etc.) to let OpenGL know how the vertex stream is representing geometry faces.
Using tessellation shaders, GL_PATCHES replaces these primitive type enums. This makes sense in my head when processing patches of size 3 or 4, and setting the corresponding layout in the TES to triangles or quads.
But if I have a patch of size 16 (some tutorials do this), how does the TPG know what 3 or 4 vertices form what faces? I've read several times that the order in your vertex buffer does not matter when GL_PATCHES is used, but surely there must be a point where a specific set of 3 vertices is considered a triangle (to pass to e.g. the geometry shader). How is this decided?
The actual tessellation hardware doesn't actually use your patch data. The tessellation unit, the part of the pipeline that actually generates triangles (or lines), operates on an abstract patch. If your TES specifies that the abstract patch is a quad, then the tessellator will perform tessellation on a unit quad.
How many patch vertices you have is completely irrelevant to this process.
The TES is a bit like a vertex shader; it gets called once per vertex. But not per vertex in the GL_PATCHES primitive. It's once per-vertex of the tessellated primitive. So, if you tessellate a quad, and your outer levels are (4, 4, 4, 4) and the inner levels are (4, 4), that will generate 25 vertices. The TES will be called that many times (at least; it can be called multiple times for the same vertex), and it will be told where within the abstract patch that particular vertex is.
The job of the TES is to decide how to use the abstract patch coordinate and the real patch vertex data to generate the actual per-vertex data to be used by the rendering pipeline. For example, if you're creating a Bezier patch, you would have 16 patch vertices. The TES's job would be to take the abstract patch coordinate and use bicubic Bezier interpolation to interpolate the 16 positions on the patch to that particular location in the abstract patch. That becomes the output position. Normals, texture coordinates, and other data can be computed similarly.
The short answer is: The TPG (Tessellation Primitive Generator) doesn't know/care at all about the patch size.
The TPG only cares about the specified input layout of the tessellation evaluation shader (triangle, quad, isoline) and the tessellation levels set by the control shader. It does not have access to the patch itself but generates the tessellation coordinates only based on the type and level used in this tessellation.
The user is than in the tessellation evaluation shader responsible for establishing the relation between the per control point parameters (passed from the tessellation control shader, donated by in/out, somehow similar to varyings) and the gl_TessCoord (coming from the TPG).
Note, that the amount of per control point parameters and the amount of tessellation coordinates is not necessarily the same.
For further reading, the following articles might help:
Primitive Processing in Open GL, especially Figure 8.1
I send a VertexBuffer+IndexBuffer of GL_TRIANGLES via glDrawElements() to the GPU.
In the vertex shader I wanted snap some vertices to the same coordinates to simplify a large mesh on-the-fly.
As result I expeceted a major performance boost because a lot of triangle are collapsing to the same point and would be degenerated.
But I don't get any fps gain.
Due testing I set my vertex shader just to gl_Position(vec4(0)) to degenerate ALL triangles, but still no difference...
Is there any flag to "activate" the degeneration or what am I'm missing?
glQuery of GL_PRIMITIVES_GENERATED also prints always the number of all mesh faces.
What you're missing is how the optimization you're trying to use actually works.
The particular optimization you're talking about is post-caching of T&L. That is, if the same vertex is going to get processed twice, you only process it once and use the results twice.
What you don't understand is how "the same vertex" is actually determined. It isn't determined by anything your vertex shader could compute. Why? Well, the whole point of caching is to avoid running the vertex shader. If the vertex shader was used to determine if the value was already cached... you've saved nothing since you had to recompute it to determine that.
"The same vertex" is actually determined by matching the vertex index and vertex instance. Each vertex in the vertex array has a unique index associated with it. If you use the same index twice (only possible with indexed rendering of course), then the vertex shader would receive the same input data. And therefore, it would produce the same output data. So you can use the cached output data.
Instance ids also play into this, since when doing instanced rendering, the same vertex index does not necessarily mean the same inputs to the VS. But even then, if you get the same vertex index and the same instance id, then you would get the same VS inputs, and therefore the same VS outputs. So within an instance, the same vertex index represents the same value.
Both the instance count and the vertex indices are part of the rendering process. They don't come from anything the vertex shader can compute. The vertex shader could generate the same positions, normals, or anything else, but the actual post-transform cache is based on the vertex index and instance.
So if you want to "snap some vertices to the same coordinates to simplify a large mesh", you have to do that before your rendering command. If you want to do it "on the fly" in a shader, then you're going to need some kind of compute shader or geometry shader/transform feedback process that will compute the new mesh. Then you need to render this new mesh.
You can discard a primitive in a geometry shader. But you still had to do T&L on it. Plus, using a GS at all slows things down, so I highly doubt you'll gain much performance by doing this.
I want to know if there is a way to get the number of effective polygons (or vertices) rendered to a window when Hardware Tessellation is on. Due to adaptive tessellation, the polygon number changes from one frame to the next.
I'm using OpenGL 4.2 and render the mesh calling glDrawElements. I'm using full program shaders (Vertex, Tessellation Control, Tessellation Evaluation, Geometry and Fragment).
I have the initial number of polygons in an array, but after the tessellation stage is executed, this number is no longer valid.
I tried to use glGetQuery(GL_PRIMITIVES_GENERATED) but it always returns 0.
glGenQueries(1, query).
glBeginQuery(GL_PRIMITIVES_GENERATED, query).
//Draw stuff
glEndQuery(GL_PRIMITIVES_GENERATED).
glGetQueryObjectuiv(query, GL_QUERY_RESULT_AVAILABLE, &value).
The number of primitives generated is the same per vertex for a given LOD. If you want to calculate the # triangles generated for each tessellation, you can do the calculations yourself, there's a set of equations over at:
GLSL Tessellation shader number of triangles/faces?