Browse Source

Playing with tessellation. Silhouette (using face normals) subdivision creates horrible cracks. Need something else

Panagiotis Christopoulos Charitos 12 years ago
parent
commit
0e8cfaaade
4 changed files with 211 additions and 84 deletions
  1. 132 56
      shaders/MsCommonTessc.glsl
  2. 76 27
      shaders/MsCommonTesse.glsl
  3. 2 0
      src/renderer/Drawer.cpp
  4. 1 1
      testapp/Main.cpp

+ 132 - 56
shaders/MsCommonTessc.glsl

@@ -10,17 +10,7 @@ in mediump vec3 vNormal[];
 in mediump vec4 vTangent[];
 #endif
 
-#if 0
-// Varyings out
-out highp vec3 tcPosition[];
-out highp vec2 tcTexCoords[];
-#if PASS_COLOR
-out mediump vec3 tcNormal[];
-out mediump vec4 tcTangent[];
-#endif
-#endif
-
-struct OutPatch
+struct PNPatch
 {
 	vec3 pos030;
 	vec3 pos021;
@@ -40,7 +30,20 @@ struct OutPatch
 #endif
 };
 
-out patch OutPatch tcPatch;
+struct PhongPatch
+{
+	vec3 terms[3];
+
+	vec3 positions[3];
+	vec2 texCoord[3];
+	vec3 normal[3];
+#if PASS_COLOR
+	vec4 tangent[3];
+#endif
+};
+
+out patch PNPatch pnPatch;
+out patch PhongPatch phongPatch;
 
 // Project point to plane
 vec3 projectToPlane(vec3 point, vec3 planePoint, vec3 planeNormal)
@@ -55,63 +58,136 @@ vec3 projectToPlane(vec3 point, vec3 planePoint, vec3 planeNormal)
 void calcPositions()
 {
 	// The original vertices stay the same
-	tcPatch.pos030 = vPosition[0];
-	tcPatch.pos003 = vPosition[1];
-	tcPatch.pos300 = vPosition[2];
+	pnPatch.pos030 = vPosition[0];
+	pnPatch.pos003 = vPosition[1];
+	pnPatch.pos300 = vPosition[2];
 
 	// edges are names according to the opposing vertex
-	vec3 edgeB300 = tcPatch.pos003 - tcPatch.pos030;
-	vec3 edgeB030 = tcPatch.pos300 - tcPatch.pos003;
-	vec3 edgeB003 = tcPatch.pos030 - tcPatch.pos300;
+	vec3 edgeB300 = pnPatch.pos003 - pnPatch.pos030;
+	vec3 edgeB030 = pnPatch.pos300 - pnPatch.pos003;
+	vec3 edgeB003 = pnPatch.pos030 - pnPatch.pos300;
 
 	// Generate two midpoints on each edge
-	tcPatch.pos021 = tcPatch.pos030 + edgeB300 / 3.0;
-	tcPatch.pos012 = tcPatch.pos030 + edgeB300 * 2.0 / 3.0;
-	tcPatch.pos102 = tcPatch.pos003 + edgeB030 / 3.0;
-	tcPatch.pos201 = tcPatch.pos003 + edgeB030 * 2.0 / 3.0;
-	tcPatch.pos210 = tcPatch.pos300 + edgeB003 / 3.0;
-	tcPatch.pos120 = tcPatch.pos300 + edgeB003 * 2.0 / 3.0;
-
-	tcPatch.pos021 = 
-		projectToPlane(tcPatch.pos021, tcPatch.pos030, tcPatch.normal[0]);
-	tcPatch.pos012 =
-		projectToPlane(tcPatch.pos012, tcPatch.pos003, tcPatch.normal[1]);
-	tcPatch.pos102 = 
-		projectToPlane(tcPatch.pos102, tcPatch.pos003, tcPatch.normal[1]);
-	tcPatch.pos201 = 
-		projectToPlane(tcPatch.pos201, tcPatch.pos300, tcPatch.normal[2]);
-	tcPatch.pos210 = 
-		projectToPlane(tcPatch.pos210, tcPatch.pos300, tcPatch.normal[2]);
-	tcPatch.pos120 = 
-		projectToPlane(tcPatch.pos120, tcPatch.pos030, tcPatch.normal[0]);
+	pnPatch.pos021 = pnPatch.pos030 + edgeB300 / 3.0;
+	pnPatch.pos012 = pnPatch.pos030 + edgeB300 * 2.0 / 3.0;
+	pnPatch.pos102 = pnPatch.pos003 + edgeB030 / 3.0;
+	pnPatch.pos201 = pnPatch.pos003 + edgeB030 * 2.0 / 3.0;
+	pnPatch.pos210 = pnPatch.pos300 + edgeB003 / 3.0;
+	pnPatch.pos120 = pnPatch.pos300 + edgeB003 * 2.0 / 3.0;
+
+	pnPatch.pos021 = 
+		projectToPlane(pnPatch.pos021, pnPatch.pos030, pnPatch.normal[0]);
+	pnPatch.pos012 =
+		projectToPlane(pnPatch.pos012, pnPatch.pos003, pnPatch.normal[1]);
+	pnPatch.pos102 = 
+		projectToPlane(pnPatch.pos102, pnPatch.pos003, pnPatch.normal[1]);
+	pnPatch.pos201 = 
+		projectToPlane(pnPatch.pos201, pnPatch.pos300, pnPatch.normal[2]);
+	pnPatch.pos210 = 
+		projectToPlane(pnPatch.pos210, pnPatch.pos300, pnPatch.normal[2]);
+	pnPatch.pos120 = 
+		projectToPlane(pnPatch.pos120, pnPatch.pos030, pnPatch.normal[0]);
 
 	// Handle the center
-	vec3 center = (tcPatch.pos003 + tcPatch.pos030 + tcPatch.pos300) / 3.0;
-	tcPatch.pos111 = (tcPatch.pos021 + tcPatch.pos012 + tcPatch.pos102 +
-		tcPatch.pos201 + tcPatch.pos210 + tcPatch.pos120) / 6.0;
-	tcPatch.pos111 += (tcPatch.pos111 - center) / 2.0;
+	vec3 center = (pnPatch.pos003 + pnPatch.pos030 + pnPatch.pos300) / 3.0;
+	pnPatch.pos111 = (pnPatch.pos021 + pnPatch.pos012 + pnPatch.pos102 +
+		pnPatch.pos201 + pnPatch.pos210 + pnPatch.pos120) / 6.0;
+	pnPatch.pos111 += (pnPatch.pos111 - center) / 2.0;
 } 
 
-#define tessellatePositionNormalTangentTexCoord_DEFINED
-void tessellatePositionNormalTangentTexCoord(
-	in float tessLevelInner, 
-	in float tessLevelOuter)
+vec3 calcFaceNormal(in vec3 v0, in vec3 v1, in vec3 v2)
 {
-	for(int i = 0 ; i < 3 ; i++) 
-	{		
-		tcPatch.texCoord[i] = vTexCoords[i];
-		tcPatch.normal[i] = vNormal[i];
+	return normalize(cross(v1 - v0, v2 - v0));
+}
+
+// This function is part of the point-normal tessellation method
+#define tessellatePNPositionNormalTangentTexCoord_DEFINED
+void tessellatePNPositionNormalTangentTexCoord(
+	in float maxTessLevel,
+	in mat4 mvp,
+	in mat3 normalMat)
+{
+	float tessLevel = 0.0;
+
+	// Calculate the face normal in view space
+	vec3 faceNorm = calcFaceNormal(vPosition[0], vPosition[1], vPosition[2]);
+	faceNorm = (normalMat * faceNorm);
+
+	if(faceNorm.z >= 0.0)
+	{
+		// The face is front facing
+
+		for(int i = 0 ; i < 3 ; i++) 
+		{		
+			pnPatch.texCoord[i] = vTexCoords[i];
+			pnPatch.normal[i] = vNormal[i];
 #if PASS_COLOR
-		tcPatch.tangent[i] = vTangent[i];
+			pnPatch.tangent[i] = vTangent[i];
 #endif
+		}
+
+		calcPositions();
+
+		// Calculate the tessLevel. It's 1.0 when the normal is facing the cam
+		// and maxTessLevel when it's facing away. This gives high tessellation
+		// on silhouettes
+		tessLevel = (1.0 - faceNorm.z) * (maxTessLevel - 1.0) + 1.0;
 	}
 
-	calcPositions();
+	gl_TessLevelOuter[0] = tessLevel;
+	gl_TessLevelOuter[1] = tessLevel;
+	gl_TessLevelOuter[2] = tessLevel;
+	gl_TessLevelInner[0] = tessLevel;
+}
+
+float calcTerm(int ivId, int i, vec3 q)
+{
+	vec3 qMinusP = q - vPosition[i];
+	return q[ivId] - dot(qMinusP, vNormal[i]) * vNormal[i][ivId];
+}
+
+#define tessellatePhongPositionNormalTangentTexCoord_DEFINED
+void tessellatePhongPositionNormalTangentTexCoord(
+	in float maxTessLevel,
+	in mat4 mvp,
+	in mat3 normalMat)
+{
+	float tessLevel = 0.0;
+
+	// Calculate the face normal in view space
+	vec3 faceNorm = calcFaceNormal(vPosition[0], vPosition[1], vPosition[2]);
+	faceNorm = (normalMat * faceNorm);
+
+	if(faceNorm.z >= -0.0)
+	{
+		// The face is front facing
+
+		for(int i = 0 ; i < 3 ; i++) 
+		{
+			phongPatch.positions[i] = vPosition[i];
+			phongPatch.texCoord[i] = vTexCoords[i];
+			phongPatch.normal[i] = vNormal[i];
+#if PASS_COLOR
+			phongPatch.tangent[i] = vTangent[i];
+#endif
+
+			phongPatch.terms[i][0] = 
+				calcTerm(i, 0, vPosition[1]) + calcTerm(i, 1, vPosition[0]);
+			phongPatch.terms[i][1] = 
+				calcTerm(i, 1, vPosition[2]) + calcTerm(i, 2, vPosition[1]);
+			phongPatch.terms[i][2] = 
+				calcTerm(i, 2, vPosition[0]) + calcTerm(i, 0, vPosition[2]);
+		}
+
+		// Calculate the tessLevel. It's 1.0 when the normal is facing the cam
+		// and maxTessLevel when it's facing away. This gives high tessellation
+		// on silhouettes
+		tessLevel = (1.0 - faceNorm.z) * (maxTessLevel - 1.0) + 1.0;
+	}
 
-	// Calculate the tessellation levels
-	gl_TessLevelOuter[0] = tessLevelOuter;
-	gl_TessLevelOuter[1] = tessLevelOuter;
-	gl_TessLevelOuter[2] = tessLevelOuter;
-	gl_TessLevelInner[0] = tessLevelInner;
+	gl_TessLevelOuter[0] = tessLevel;
+	gl_TessLevelOuter[1] = tessLevel;
+	gl_TessLevelOuter[2] = tessLevel;
+	gl_TessLevelInner[0] = tessLevel;
 }
 

+ 76 - 27
shaders/MsCommonTesse.glsl

@@ -1,16 +1,6 @@
 layout(triangles, equal_spacing, ccw) in;
 
-// Varyings in
-#if 0
-in highp vec3 tcPosition[];
-in highp vec2 tcTexCoords[];
-#if PASS_COLOR
-in mediump vec3 tcNormal[];
-in mediump vec4 tcTangent[];
-#endif
-#endif
-
-struct OutPatch
+struct PNPatch
 {
 	vec3 pos030;
 	vec3 pos021;
@@ -30,7 +20,20 @@ struct OutPatch
 #endif
 };
 
-in patch OutPatch tcPatch;
+struct PhongPatch
+{
+	vec3 terms[3];
+
+	vec3 positions[3];
+	vec2 texCoord[3];
+	vec3 normal[3];
+#if PASS_COLOR
+	vec4 tangent[3];
+#endif
+};
+
+in patch PNPatch pnPatch;
+in patch PhongPatch phongPatch;
 
 // Varyings out
 out highp vec2 teTexCoords;
@@ -42,16 +45,16 @@ out mediump vec4 teTangent;
 #define INTERPOLATE(x_) (x_[0] * gl_TessCoord.x + x_[1] * gl_TessCoord.y + x_[2] * gl_TessCoord.z)
 
 // Smooth tessellation
-#define subdivPositionNormalTangentTexCoord_DEFINED
-void subdivPositionNormalTangentTexCoord(in mat4 mvp, in mat3 normalMat)
+#define tessellatePNPositionNormalTangentTexCoord_DEFINED
+void tessellatePNPositionNormalTangentTexCoord(in mat4 mvp, in mat3 normalMat)
 {
 #if PASS_COLOR
-	teNormal = normalize(normalMat * INTERPOLATE(tcPatch.normal));
-	teTangent = INTERPOLATE(tcPatch.tangent);
+	teNormal = normalize(normalMat * INTERPOLATE(pnPatch.normal));
+	teTangent = INTERPOLATE(pnPatch.tangent);
 	teTangent.xyz = normalize(normalMat * teTangent.xyz);
 #endif
 
-	teTexCoords = INTERPOLATE(tcPatch.texCoord);
+	teTexCoords = INTERPOLATE(pnPatch.texCoord);
 
 	float u = gl_TessCoord.x;
 	float v = gl_TessCoord.y;
@@ -65,16 +68,62 @@ void subdivPositionNormalTangentTexCoord(in mat4 mvp, in mat3 normalMat)
 	float wPow2 = pow(w, 2);
 
 	vec3 pos = 
-		tcPatch.pos300 * wPow3
-		+ tcPatch.pos030 * uPow3
-		+ tcPatch.pos003 * vPow3
-		+ tcPatch.pos210 * 3.0 * wPow2 * u 
-		+ tcPatch.pos120 * 3.0 * w * uPow2 
-		+ tcPatch.pos201 * 3.0 * wPow2 * v 
-		+ tcPatch.pos021 * 3.0 * uPow2 * v 
-		+ tcPatch.pos102 * 3.0 * w * vPow2 
-		+ tcPatch.pos012 * 3.0 * u * vPow2 
-		+ tcPatch.pos111 * 6.0 * w * u * v;
+		pnPatch.pos300 * wPow3
+		+ pnPatch.pos030 * uPow3
+		+ pnPatch.pos003 * vPow3
+		+ pnPatch.pos210 * 3.0 * wPow2 * u 
+		+ pnPatch.pos120 * 3.0 * w * uPow2 
+		+ pnPatch.pos201 * 3.0 * wPow2 * v 
+		+ pnPatch.pos021 * 3.0 * uPow2 * v 
+		+ pnPatch.pos102 * 3.0 * w * vPow2 
+		+ pnPatch.pos012 * 3.0 * u * vPow2 
+		+ pnPatch.pos111 * 6.0 * w * u * v;
 
 	gl_Position = mvp * vec4(pos, 1.0);
 }
+
+#define tessellatePhongPositionNormalTangentTexCoord_DEFINED
+void tessellatePhongPositionNormalTangentTexCoord(
+	in mat4 mvp, in mat3 normalMat)
+{
+#if PASS_COLOR
+	teNormal = normalize(normalMat * INTERPOLATE(phongPatch.normal));
+	teTangent = INTERPOLATE(phongPatch.tangent);
+	teTangent.xyz = normalize(normalMat * teTangent.xyz);
+#endif
+
+	teTexCoords = INTERPOLATE(phongPatch.texCoord);
+
+	// interpolated position
+	vec3 barPos = INTERPOLATE(phongPatch.positions);
+
+	// build terms
+	vec3 termIJ = vec3(
+		phongPatch.terms[0][0],
+		phongPatch.terms[1][0],
+		phongPatch.terms[2][0]);
+	vec3 termJK = vec3(
+		phongPatch.terms[0][1],
+		phongPatch.terms[1][1],
+		phongPatch.terms[2][1]);
+	vec3 termIK = vec3(
+		phongPatch.terms[0][2],
+		phongPatch.terms[1][2],
+		phongPatch.terms[2][2]);
+
+	vec3 tc2 = gl_TessCoord * gl_TessCoord;
+
+	// phong tesselated pos
+	vec3 phongPos = 
+		tc2[0] * phongPatch.positions[0]
+		 + tc2[1] * phongPatch.positions[1]
+		 + tc2[2] * phongPatch.positions[2]
+		 + gl_TessCoord[0] * gl_TessCoord[1] * termIJ
+		 + gl_TessCoord[1] * gl_TessCoord[2] * termJK
+		 + gl_TessCoord[2] * gl_TessCoord[0] * termIK;
+
+	float uTessAlpha = 1.0;
+	vec3 finalPos = (1.0 - uTessAlpha) * barPos + uTessAlpha * phongPos;
+	gl_Position = mvp * vec4(finalPos, 1.0);
+}
+

+ 2 - 0
src/renderer/Drawer.cpp

@@ -140,6 +140,7 @@ ANKI_ATTRIBUTE_ALIGNED(struct, 16) SetupRenderableVariableVisitor
 					{
 						Mat4 mv = v * Mat4(trfs[i]);
 						normm[i] = mv.getRotationPart();
+						normm[i].reorthogonalize();
 					}
 				}
 				else
@@ -148,6 +149,7 @@ ANKI_ATTRIBUTE_ALIGNED(struct, 16) SetupRenderableVariableVisitor
 					{
 						Mat4 mv = v * Mat4(trfs[subSpatialIndices[size]]);
 						normm[size] = mv.getRotationPart();
+						normm[size].reorthogonalize();
 					}
 				}
 

+ 1 - 1
testapp/Main.cpp

@@ -478,7 +478,7 @@ void mainLoop()
 
 		// Sleep
 		//
-#if 0
+#if 1
 		timer.stop();
 		if(timer.getElapsedTime() < AppSingleton::get().getTimerTick())
 		{