I'm trying to implement a simple tessellation program based on this tutorial.
These are my shaders:
Vertex:
#version 410 core
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
in vec4 vPosition;
in vec3 vNormal;
// Input for the tesselation control shader
smooth out vec3 vEyePos_TCS;
smooth out vec3 vNorm_TCS;
void main()
{
vNorm_TCS = normalize(normalMatrix * vNormal);
vEyePos_TCS = vec3(mvMatrix * vPosition);
}
Tessellation Control:
#version 410 core
// Define the number of CPs in the output patch
layout (vertices = 3) out;
uniform vec3 eyePos;
in vec3 vEyePos_TCS[];
in vec3 vNorm_TCS[];
// Output for the tesselation evaluation shader
out vec3 vEyePos_TES[];
out vec3 vNorm_TES[];
float GetTessLevel(float dist0, float dist1)
{
float avgDist = (dist0 + dist1) / 2.0;
if (avgDist <= 10.0)
return 5.0;
else if (avgDist <= 15.0)
return 3.0;
else
return 1.0;
}
void main()
{
// Set the control points of the output patch
vEyePos_TES[gl_InvocationID] = vEyePos_TCS[gl_InvocationID];
vNorm_TES[gl_InvocationID] = vNorm_TCS[gl_InvocationID];
// Calculate the distance from the camera to the three control points
float dist0 = distance(eyePos, vEyePos_TES[0]);
float dist1 = distance(eyePos, vEyePos_TES[1]);
float dist2 = distance(eyePos, vEyePos_TES[2]);
// Calculate the tesselation levels
gl_TessLevelOuter[0] = GetTessLevel(dist1, dist2);
gl_TessLevelOuter[1] = GetTessLevel(dist2, dist0);
gl_TessLevelOuter[2] = GetTessLevel(dist0, dist1);
gl_TessLevelInner[0] = gl_TessLevelOuter[2];
}
Tessellation Evaluator:
#version 410 core
layout(triangles, equal_spacing, ccw) in;
uniform mat4 pMatrix;
in vec3 vEyePos_TES[];
in vec3 vNorm_TES[];
// Input for the geometry shader
out vec3 vEyePos_GS;
out vec3 vNorm_GS;
vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2)
{
return vec3(gl_TessCoord.x) * v0 + vec3(gl_TessCoord.y) * v1 + vec3(gl_TessCoord.z) * v2;
}
void main()
{
// Interpolate the attributes of the output vertex using the barycentric coordinates
vNorm_GS = interpolate3D(vNorm_TES[0], vNorm_TES[1], vNorm_TES[2]);
vEyePos_GS = interpolate3D(vEyePos_TES[0], vEyePos_TES[1], vEyePos_TES[2]);
gl_Position = pMatrix * vec4(vEyePos_GS, 1.0);
}
Geometry:
#version 410
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec3 vEyePos_GS[];
in vec3 vNorm_GS[];
out vec3 vEyePos_FS;
out vec3 vNorm_FS;
out vec3 gTriDistance;
void main()
{
vNorm_FS = vNorm_GS[0];
vEyePos_FS = vEyePos_GS[0];
gTriDistance = vec3(1, 0, 0);
gl_Position = gl_in[0].gl_Position;
EmitVertex();
vNorm_FS = vNorm_GS[1];
vEyePos_FS = vEyePos_GS[1];
gTriDistance = vec3(0, 1, 0);
gl_Position = gl_in[1].gl_Position;
EmitVertex();
vNorm_FS = vNorm_GS[2];
vEyePos_FS = vEyePos_GS[2];
gTriDistance = vec3(0, 0, 1);
gl_Position = gl_in[2].gl_Position;
EmitVertex();
EndPrimitive();
}
Fragment:
#version 410 core
uniform vec3 vLightPosition;
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
in vec3 vEyePos_FS;
in vec3 vNorm_FS;
in vec3 gTriDistance;
out vec4 fragColor;
float amplify(float d, float scale, float offset)
{
d = scale * d + offset;
d = clamp(d, 0, 1);
d = 1 - exp2(-2 * d * d);
return d;
}
void main()
{
vec3 L = normalize(vLightPosition - vEyePos_FS);
vec3 E = normalize(-vEyePos_FS);
vec3 R = normalize(-reflect(L, vNorm_FS));
//calculate Ambient Term:
vec4 Iamb = ambientColor;
//calculate Diffuse Term:
vec4 Idiff = diffuseColor * max(dot(vNorm_FS, L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);
// calculate Specular Term:
vec4 Ispec = specularColor * pow(max(dot(R, E), 0.0), 0.3 * 128.0);
Ispec = clamp(Ispec, 0.0, 1.0);
fragColor = Iamb + Idiff + Ispec;
float d1 = min( min( gTriDistance.x, gTriDistance.y ), gTriDistance.z );
fragColor = fragColor * amplify( d1, 60, -0.5 ) ;
};
The problem that I'm facing seems to be similar to this one, in which when the tess level gets higher, the surface starts to flicker. However, I couldn't solve it so far.
To draw, I simple do:
glBindVertexArray(_vao);
LoadUniformVariables();
glPatchParameteri(GL_PATCH_VERTICES, 3);
glDrawArrays(GL_PATCHES, 0, _modelCoordinates.size());
glBindVertexArray(0);
Those are my results:
Well, the problem seemed to be with my drawing call and how my data was sctructured. The following works properly: