CVS: data/Shaders landmass-g.vert, 1.1, 1.2 landmass.geom, 1.3, 1.4

Tim Moore <[email protected]> Thu, 22 Apr 2010 09:56:37 -0500
Newsgroups gmane.games.flightgear.cvc
Message-ID <[email protected]>
Update of /var/cvs/FlightGear-0.9/data/Shaders
In directory baron.flightgear.org:/tmp/cvs-serv2733/Shaders

Modified Files:
	landmass-g.vert landmass.geom 
Log Message:
Rewrote landmass geometry shader

I did several optimizations, including reducing to a bare minimum
shader computations and producing the geometry as one tristrip with
degenerate triangles. The result was an increase from 14 fps to 51 fps
(NVidia 8600M, ufo, ksfo).


Author: Tim Moore <[email protected]>


Index: landmass-g.vert
===================================================================
RCS file: /var/cvs/FlightGear-0.9/data/Shaders/landmass-g.vert,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- landmass-g.vert	29 Mar 2010 06:13:43 -0000	1.1
+++ landmass-g.vert	22 Apr 2010 14:56:35 -0000	1.2
@@ -1,19 +1,55 @@
+#version 120
+
+// "landmass" effect with forest construction using a geometry
+// shader. The landmass effect includes a bumpmap effect as well as
+// variation by altitude.
+//
+// The fragment shader needs position and normals in model and eye
+// coordinates. This vertex shader calculates the positions and
+// normals of the forest polygons so the geometry shader can do as
+// little as possible.
+
+// Input for the geometry shader. "raw" means terrain model
+// coordinates; that's a tile-local coordinate system, with z as local
+// up. "ec" means eye coordinates.
+
+// model position of original terrain poly; the bottom of the forest.
 varying vec4 rawposIn;
+// model forest top
+varying vec4 rawTopIn;
+// model normal
 varying vec3 NormalIn;
+varying vec4 ecPosIn;
+varying vec4 ecTopIn;
+varying vec3 ecNormalIn;
+// eye spacce tangent and binormal
 varying vec3 VTangentIn;
 varying vec3 VBinormalIn;
+// screen-space position of top
+varying vec4 positionTopIn;
+// constant color component
+varying vec4 constantColorIn;
 
 attribute vec3 tangent;
 attribute vec3 binormal;
 
+uniform float canopy_height;
+
 void main(void)
 {
-	rawposIn = gl_Vertex;
+        rawposIn = gl_Vertex;
+	ecPosIn = gl_ModelViewMatrix * gl_Vertex;
 	NormalIn = normalize(gl_Normal);
+        rawTopIn = rawposIn + vec4(0.0, 0.0, canopy_height, 0.0);
+        ecTopIn = gl_ModelViewMatrix * rawTopIn;
+        ecNormalIn = gl_NormalMatrix * NormalIn;
 	VTangentIn = gl_NormalMatrix * tangent;
 	VBinormalIn = gl_NormalMatrix * binormal;
 
 	gl_FrontColor = gl_Color;
 	gl_Position = ftransform();
+        positionTopIn = gl_ModelViewProjectionMatrix * rawTopIn;
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+        constantColorIn = gl_FrontMaterial.emission
+		+ gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient);  
 }

Index: landmass.geom
===================================================================
RCS file: /var/cvs/FlightGear-0.9/data/Shaders/landmass.geom,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- landmass.geom	11 Apr 2010 08:36:39 -0000	1.3
+++ landmass.geom	22 Apr 2010 14:56:35 -0000	1.4
@@ -1,82 +1,116 @@
 #version 120
 #extension GL_EXT_geometry_shader4 : enable
 
+// Geometry shader that creates a prism from a terrain triangle,
+// resulting in a forest effect.
+//
+// A geometry shader should do as little computation as possible.
+
+// See landmass-g.vert for a description of the inputs.
 varying in vec4 rawposIn[];
 varying in vec3 NormalIn[];
+varying in vec4 rawTopIn[];
+varying in vec4 ecPosIn[];
+varying in vec4 ecTopIn[];
+varying in vec3 ecNormalIn[];
 varying in vec3 VTangentIn[];
 varying in vec3 VBinormalIn[];
+varying in vec4 positionTopIn[];
+varying in vec4 constantColorIn[];
+
+uniform float canopy_height;
 
+// model position
 varying out vec4 rawpos;
+// eye position
 varying out vec4 ecPosition;
+// eye space surface matrix
 varying out vec3 VNormal;
 varying out vec3 VTangent;
 varying out vec3 VBinormal;
+// model normal
 varying out vec3 Normal;
 varying out vec4 constantColor;
 varying out float bump;
 
-uniform float canopy_height;
-
-void createVertex(int i, int j, float offset, float s)
+// Emit one vertex of the forest geometry.
+// parameters:
+// i - index into original terrain triangle
+void doVertex(in int i, in vec4 pos, in vec4 ecpos, in vec4 screenpos,
+              in vec3 rawNormal, in vec3 normal, in float s)
 {
-	rawpos = rawposIn[i] + offset * vec4(NormalIn[i], 0.0);
-	ecPosition = gl_ModelViewMatrix * rawpos;
-	if ( s == 0.0 )
-	{
-		vec4 v;
-		if (j < i)
-		{
-			v = rawposIn[j] - rawposIn[i];
-			Normal = normalize(cross( NormalIn[i], v.xyz ));
-		}
-		else
-		{
-			v = rawposIn[i] - rawposIn[j];
-			Normal = normalize(cross( NormalIn[j], v.xyz ));
-		}
-	}
-	else
-	{
-		Normal = NormalIn[i];
-	}
-	VNormal = normalize(gl_NormalMatrix * Normal);
-	VTangent  = VTangentIn[i];
+        rawpos = pos;
+        ecPosition = ecpos;
+        Normal = rawNormal;
+        VNormal = normal;
+        VTangent  = VTangentIn[i];
 	VBinormal = VBinormalIn[i];
 	bump = s;
 
 	gl_FrontColor = gl_FrontColorIn[i];
-	constantColor = gl_FrontMaterial.emission
-		+ gl_FrontColorIn[i] * (gl_LightModel.ambient + gl_LightSource[0].ambient);  
-	gl_Position = gl_ProjectionMatrix * ecPosition;
+	constantColor = constantColorIn[i];
+	gl_Position = screenpos;
 	gl_TexCoord[0] = gl_TexCoordIn[i][0];
 	EmitVertex();
 }
 
+vec3 rawSideNormal[3];
+vec3 sideNormal[3];
+
+// Emit a vertex for a forest side triangle
+void doSideVertex(in int vertIdx, in int sideIdx, vec4 pos, in vec4 ecpos,
+                  in vec4 screenpos)
+{
+        doVertex(vertIdx, pos, ecpos, screenpos, rawSideNormal[sideIdx],
+                 sideNormal[sideIdx], 0.0);
+}
+
 void main(void)
 {
-	if (canopy_height > 0.01) {
-		createVertex(0, 1, canopy_height, 0.0);
-		createVertex(0, 1, 0.0, 0.0);
-		createVertex(1, 0, canopy_height, 0.0);
-		createVertex(1, 0, 0.0, 0.0);
-		EndPrimitive();
-		createVertex(1, 2, canopy_height, 0.0);
-		createVertex(1, 2, 0.0, 0.0);
-		createVertex(2, 1, canopy_height, 0.0);
-		createVertex(2, 1, 0.0, 0.0);
-		EndPrimitive();
-		createVertex(2, 0, canopy_height, 0.0);
-		createVertex(2, 0, 0.0, 0.0);
-		createVertex(0, 2, canopy_height, 0.0);
-		createVertex(0, 2, 0.0, 0.0);
-		EndPrimitive();
-		createVertex(0, 1, 0.0, 0.0);
-		createVertex(1, 2, 0.0, 0.0);
-		createVertex(2, 0, 0.0, 0.0);
-		EndPrimitive();
-	}
-	createVertex(0, 1, canopy_height, 1.0);
-	createVertex(1, 2, canopy_height, 1.0);
-	createVertex(2, 0, canopy_height, 1.0);
-	EndPrimitive();
+        rawSideNormal[0] = normalize(cross((rawposIn[1] - rawposIn[0]).xyz,
+                                           NormalIn[0]));
+        rawSideNormal[1] = normalize(cross((rawposIn[2] - rawposIn[1]).xyz,
+                                           NormalIn[1]));
+        rawSideNormal[2] = normalize(cross((rawposIn[0] - rawposIn[2]).xyz, 
+                                           NormalIn[2]));
+        for (int i = 0; i < 3; ++i)
+                sideNormal[i] = gl_NormalMatrix * rawSideNormal[i];
+        if (canopy_height > 0.01) {
+                // Sides
+                doSideVertex(0, 0, rawTopIn[0], ecTopIn[0], positionTopIn[0]);
+                doSideVertex(0, 0, rawposIn[0], ecPosIn[0], gl_PositionIn[0]);
+                doSideVertex(1, 0, rawTopIn[1], ecTopIn[1], positionTopIn[1]);
+                doSideVertex(1, 0, rawposIn[1], ecPosIn[1], gl_PositionIn[1]);
+
+                doSideVertex(2, 1, rawTopIn[2], ecTopIn[2], positionTopIn[2]);
+                doSideVertex(2, 1, rawposIn[2], ecPosIn[2], gl_PositionIn[2]);
+        
+                doSideVertex(0, 2, rawTopIn[0], ecTopIn[0], positionTopIn[0]);
+                doSideVertex(0, 2, rawposIn[0], ecPosIn[0], gl_PositionIn[0]);
+                // Degenerate triangles; avoids EndPrimitive()
+                doSideVertex(0, 2, rawposIn[0], ecPosIn[0], gl_PositionIn[0]);
+                doVertex(0, rawTopIn[0], ecTopIn[0], positionTopIn[0], NormalIn[0],
+                         ecNormalIn[0], 1.0);
+        // Top
+        }
+        doVertex(0, rawTopIn[0], ecTopIn[0], positionTopIn[0], NormalIn[0],
+                 ecNormalIn[0], 1.0);
+        doVertex(1, rawTopIn[1], ecTopIn[1], positionTopIn[1], NormalIn[1],
+                 ecNormalIn[1], 1.0);
+        doVertex(2, rawTopIn[2], ecTopIn[2], positionTopIn[2], NormalIn[2],
+                 ecNormalIn[2], 1.0);
+        // Don't render "bottom" triangle for now; it's hidden.
+#if 0
+        // degenerate
+        doVertex(2, rawTopIn[2], ecTopIn[2], positionTopIn[2], NormalIn[2],
+                 ecNormalIn[2], 1.0);
+        // bottom
+        doVertex(0, rawposIn[0], ecPosIn[0], gl_PositionIn[0], NormalIn[0],
+                 ecNormalIn[0], 1.0);
+        doVertex(1, rawposIn[1], ecPosIn[1], gl_PositionIn[1], NormalIn[1],
+                 ecNormalIn[1], 1.0);
+        doVertex(2, rawposIn[2], ecPosIn[2], gl_PositionIn[2], NormalIn[2],
+                 ecNormalIn[2], 1.0);
+#endif
+        EndPrimitive();
 }


------------------------------------------------------------------------------