Reputation: 985
Why does the following tessellation control shader makes most triangles disappear?
#version 410
layout(vertices = 3) out;
void main(void) {
gl_TessLevelInner[0]=1;
gl_TessLevelOuter[gl_InvocationID]=gl_InvocationID+1;
gl_TessLevelOuter[gl_InvocationID]=gl_InvocationID+1;
gl_TessLevelOuter[gl_InvocationID]=gl_InvocationID+1;
}
I input triangles. When I index gl_TessLevelOuter with 0,1 and 2, everything works fine. It seems to me that this construct saves me the if statement, which I believe helps in parallel execution of the shader. Of course, I omitted the vertex calculations in the snippet.
Upvotes: 2
Views: 2649
Reputation: 453
The accepted answer is incorrect. You can specify an inner level of 1. If all the outer levels are also 1, then there will be no tessellation (the triangle will be unchanged). If inner is 1 and at least one outer is >1, then inner will be effectively 2 or 3 (depending on spacing), ensuring at least 1 point in the inner area.
The actual problem with the OP code is that it sets 1 outer level 3 times, instead of setting all 3 outer levels. The other 2 are defaulting to 0, causing the patch to be discarded. That is why triangles are disappearing.
ref: https://www.opengl.org/wiki/Tessellation
Upvotes: 6
Reputation: 8325
Triangles disappear because you incurred in "undefined" behaviour, that's it. The Inner tesellation level should be at least 2.
gl_TessLevelInner[0] = 2;
The weird results you obtain are because of how baricentric coordinates are computed when inner level is 1. Given you provide at least 2 as value, you can use any value you want for Outerlevels.
The following is the edge association for a triangle
out0 => edge 1-2
out1 => edge 2-3
out2 => edge 3-1
Out[0] = 4
Out[1] = 1
Out[2] = 2
As you see, the Inner
of 2, cutted the triangle twice along triangle's bisectors, while the 3 different Outer
levels cutted the triangle along the edges (no cuts for 1
, twice for 2
and 4 pieces when value is 4
)
Tips:
Also there are some small advices, data in tessellation control is shared, that's means it is called multiple times, you need to set tessellation control only once:
if(gl_InvocationID==0){
gl_TessLevelInner[0] = 2; //take a triangle
gl_TessLevelOuter[0] = 1; //and subdivde it in 3 triangles
gl_TessLevelOuter[1] = 1;
gl_TessLevelOuter[2] = 1;
}
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
So why it is still possible to set different values for each invocation? that's to add subdivisions based on screen error (at least is a reasonable use).
if(gl_InvocationID==0){
gl_TessLevelInner[0] = 2; //take a triangle
gl_TessLevelOuter[0] = lenghtOnScreen<5? 3: 4;
}
if(gl_InvocationID==1)
gl_TessLevelOuter[1] = lenghtOnScreen<5? 3: 4;
if(gl_InvocationID==2)
gl_TessLevelOuter[2] = lenghtOnScreen<5? 3: 4;
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
In the End:
Another example with Inner=3
and Outer=2
.
Note the 3 cuts along the bisector and 2 cuts along the edges, all other cuts are just for "seamless transition"
Upvotes: 4
Reputation: 578
because you are working with triangles the mininmum you can give to the outer is 3, so, in your case you are setting the index 0 to 1 and 1 to 2 and 2 to 3, but when you adresse them by 0, 1, 2 it works as the final value they will get is gl_InvocationID = 2 + 1 = 3
and thus you save you day, if you do it this way it should work:
void main(void) {
gl_TessLevelOuter[gl_InvocationID] = 3;
gl_TessLevelInner[0] = max(gl_TessLevelInner[0], gl_TessLevelOuter[gl_InvocationID]); // that is a bonus =D
}
Upvotes: -2