I have a triangular mesh that is read from an ".obj" file and is to be tessellated with respect to the camera position.
I try to avoid T-junctions by tessellating common edges with the same rounded factor. To do this, I use only the vertices of the edge to calculate a tessellation factor. This way, the common edge for both triangles will have the same tessellation factor.
Code:
I am currently using the following code to calculate the tessellation levels.
vec3 center0 = (viewSpacePosTC[1].xyz + viewSpacePosTC[2].xyz) * 0.5;
vec3 center1 = (viewSpacePosTC[0].xyz + viewSpacePosTC[2].xyz) * 0.5;
vec3 center2 = (viewSpacePosTC[0].xyz + viewSpacePosTC[1].xyz) * 0.5;
float length0 = length(viewSpacePosTC[1].xyz - viewSpacePosTC[2].xyz);
float length1 = length(viewSpacePosTC[0].xyz - viewSpacePosTC[2].xyz);
float length2 = length(viewSpacePosTC[0].xyz - viewSpacePosTC[1].xyz);
float tanFactor0 = length0 / length(center0) / u_maxTan * u_maxCountDivisions;
float tanFactor1 = length1 / length(center1) / u_maxTan * u_maxCountDivisions;
float tanFactor2 = length2 / length(center2) / u_maxTan * u_maxCountDivisions;
edgeLod[0] = round(clamp(tanFactor0, 1, u_maxCountDivisions));
edgeLod[1] = round(clamp(tanFactor1, 1, u_maxCountDivisions));
edgeLod[2] = round(clamp(tanFactor2, 1, u_maxCountDivisions));
gl_TessLevelOuter[0] = edgeLod[0];
gl_TessLevelOuter[1] = edgeLod[1];
gl_TessLevelOuter[2] = edgeLod[2];
gl_TessLevelInner[0] = round((edgeLod[0] + edgeLod[1] + edgeLod[2]) * 0.33);
The idea behind the code:
length0
length1
and length2
are the lengths of the three edges inside the input triangle. center0
center1
and center2
are the centers of the edges in the view space.
u_maxTan
is a uniform constant passed from the CPU to the shader and contains the value max(tanX, tanY)
, where tanX
and tanY
are the frustum tangents in the x and y directions. u_maxCountDivisions
is a uniform constant (32).
The tessellation factor of an edge is rotation independent, since the edge length (rotation independent) and the position of the edge center (length(center0)
rotation independent) are the only information used to calculate the tessellation factor. Think of it as rotating the edge orthogonally to the frustum and then using the distance to the camera to calculate the tessellation factor (see Figure 2). Beyond the tessellation, a noise function should later shift the generated vertices. The orthogonal approach is to avoid strong flickering when the camera moves.
Lets take a look at the output (see figure 1):
As we can see, adjacent triangles sharing an edge use the same tessellation factor for the same edge. Thus, no T-junctions occur. However, the inner and outer tessellation planes do not match.
Figure 1: Left: Input triangle mesh. Right: Tessellated output.
Figure 2: Example of a single edge. Blue: The edge in view space. Red: Edge rotated orthogonally to the camera. The red edge is used to calculate the tessellation level of the edge.
Question:
How can I avoid the strange tessellation highlighted in Figure 1? I know this is because the inner and outer tessellation levels of this triangle are too different (difference of about 10). Calculating a tessellation level for the entire triangle, where each edge gets the same tessellation level, will result in T-junctions. So this is not an option.
Is it possible to instruct the tessellator to connect the vertices that are close to the edges to the nearest 2 vertices? Then these degenerate sub-triangles will not occur.
The triangles of the input mesh do not have the same edge length for each edge. Some triangles are small, others are large. So you could say: The tessellation level depends only on the distance, is not the way I want to solve this problem.
Edit:
I was thinking of writing my own tessellation in the following way:
- create SSBO of all possible tessellations (inner and outer together with connections).
- disable rasterization
- render the geometry and write the created vertices (from TES) into a buffer (Vertex Buffer object). At the same time, write the triangle connection into an (IBO) using the SSBO from list item 1.
- activate rasterization
- Render new VBO and IBO
But before I program this, I'd like to hear from you what you think about it?