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 <timoore@redhat.com>
This commit is contained in:
parent
04376ca95c
commit
6e58bce8e5
3 changed files with 125 additions and 55 deletions
|
@ -87,7 +87,7 @@
|
||||||
<vertex-shader>Shaders/landmass-g.vert</vertex-shader>
|
<vertex-shader>Shaders/landmass-g.vert</vertex-shader>
|
||||||
<geometry-shader>Shaders/landmass.geom</geometry-shader>
|
<geometry-shader>Shaders/landmass.geom</geometry-shader>
|
||||||
<fragment-shader>Shaders/landmass.frag</fragment-shader>
|
<fragment-shader>Shaders/landmass.frag</fragment-shader>
|
||||||
<geometry-vertices-out type="int">20</geometry-vertices-out>
|
<geometry-vertices-out type="int">18</geometry-vertices-out>
|
||||||
<geometry-input-type>triangles</geometry-input-type>
|
<geometry-input-type>triangles</geometry-input-type>
|
||||||
<geometry-output-type>triangle-strip</geometry-output-type>
|
<geometry-output-type>triangle-strip</geometry-output-type>
|
||||||
<attribute>
|
<attribute>
|
||||||
|
|
|
@ -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;
|
varying vec4 rawposIn;
|
||||||
|
// model forest top
|
||||||
|
varying vec4 rawTopIn;
|
||||||
|
// model normal
|
||||||
varying vec3 NormalIn;
|
varying vec3 NormalIn;
|
||||||
|
varying vec4 ecPosIn;
|
||||||
|
varying vec4 ecTopIn;
|
||||||
|
varying vec3 ecNormalIn;
|
||||||
|
// eye spacce tangent and binormal
|
||||||
varying vec3 VTangentIn;
|
varying vec3 VTangentIn;
|
||||||
varying vec3 VBinormalIn;
|
varying vec3 VBinormalIn;
|
||||||
|
// screen-space position of top
|
||||||
|
varying vec4 positionTopIn;
|
||||||
|
// constant color component
|
||||||
|
varying vec4 constantColorIn;
|
||||||
|
|
||||||
attribute vec3 tangent;
|
attribute vec3 tangent;
|
||||||
attribute vec3 binormal;
|
attribute vec3 binormal;
|
||||||
|
|
||||||
|
uniform float canopy_height;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
rawposIn = gl_Vertex;
|
rawposIn = gl_Vertex;
|
||||||
|
ecPosIn = gl_ModelViewMatrix * gl_Vertex;
|
||||||
NormalIn = normalize(gl_Normal);
|
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;
|
VTangentIn = gl_NormalMatrix * tangent;
|
||||||
VBinormalIn = gl_NormalMatrix * binormal;
|
VBinormalIn = gl_NormalMatrix * binormal;
|
||||||
|
|
||||||
gl_FrontColor = gl_Color;
|
gl_FrontColor = gl_Color;
|
||||||
gl_Position = ftransform();
|
gl_Position = ftransform();
|
||||||
|
positionTopIn = gl_ModelViewProjectionMatrix * rawTopIn;
|
||||||
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
|
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
|
||||||
|
constantColorIn = gl_FrontMaterial.emission
|
||||||
|
+ gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,82 +1,116 @@
|
||||||
#version 120
|
#version 120
|
||||||
#extension GL_EXT_geometry_shader4 : enable
|
#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 vec4 rawposIn[];
|
||||||
varying in vec3 NormalIn[];
|
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 VTangentIn[];
|
||||||
varying in vec3 VBinormalIn[];
|
varying in vec3 VBinormalIn[];
|
||||||
|
varying in vec4 positionTopIn[];
|
||||||
|
varying in vec4 constantColorIn[];
|
||||||
|
|
||||||
|
uniform float canopy_height;
|
||||||
|
|
||||||
|
// model position
|
||||||
varying out vec4 rawpos;
|
varying out vec4 rawpos;
|
||||||
|
// eye position
|
||||||
varying out vec4 ecPosition;
|
varying out vec4 ecPosition;
|
||||||
|
// eye space surface matrix
|
||||||
varying out vec3 VNormal;
|
varying out vec3 VNormal;
|
||||||
varying out vec3 VTangent;
|
varying out vec3 VTangent;
|
||||||
varying out vec3 VBinormal;
|
varying out vec3 VBinormal;
|
||||||
|
// model normal
|
||||||
varying out vec3 Normal;
|
varying out vec3 Normal;
|
||||||
varying out vec4 constantColor;
|
varying out vec4 constantColor;
|
||||||
varying out float bump;
|
varying out float bump;
|
||||||
|
|
||||||
uniform float canopy_height;
|
// Emit one vertex of the forest geometry.
|
||||||
|
// parameters:
|
||||||
void createVertex(int i, int j, float offset, float s)
|
// 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);
|
rawpos = pos;
|
||||||
ecPosition = gl_ModelViewMatrix * rawpos;
|
ecPosition = ecpos;
|
||||||
if ( s == 0.0 )
|
Normal = rawNormal;
|
||||||
{
|
VNormal = normal;
|
||||||
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];
|
VTangent = VTangentIn[i];
|
||||||
VBinormal = VBinormalIn[i];
|
VBinormal = VBinormalIn[i];
|
||||||
bump = s;
|
bump = s;
|
||||||
|
|
||||||
gl_FrontColor = gl_FrontColorIn[i];
|
gl_FrontColor = gl_FrontColorIn[i];
|
||||||
constantColor = gl_FrontMaterial.emission
|
constantColor = constantColorIn[i];
|
||||||
+ gl_FrontColorIn[i] * (gl_LightModel.ambient + gl_LightSource[0].ambient);
|
gl_Position = screenpos;
|
||||||
gl_Position = gl_ProjectionMatrix * ecPosition;
|
|
||||||
gl_TexCoord[0] = gl_TexCoordIn[i][0];
|
gl_TexCoord[0] = gl_TexCoordIn[i][0];
|
||||||
EmitVertex();
|
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)
|
void main(void)
|
||||||
{
|
{
|
||||||
|
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) {
|
if (canopy_height > 0.01) {
|
||||||
createVertex(0, 1, canopy_height, 0.0);
|
// Sides
|
||||||
createVertex(0, 1, 0.0, 0.0);
|
doSideVertex(0, 0, rawTopIn[0], ecTopIn[0], positionTopIn[0]);
|
||||||
createVertex(1, 0, canopy_height, 0.0);
|
doSideVertex(0, 0, rawposIn[0], ecPosIn[0], gl_PositionIn[0]);
|
||||||
createVertex(1, 0, 0.0, 0.0);
|
doSideVertex(1, 0, rawTopIn[1], ecTopIn[1], positionTopIn[1]);
|
||||||
EndPrimitive();
|
doSideVertex(1, 0, rawposIn[1], ecPosIn[1], gl_PositionIn[1]);
|
||||||
createVertex(1, 2, canopy_height, 0.0);
|
|
||||||
createVertex(1, 2, 0.0, 0.0);
|
doSideVertex(2, 1, rawTopIn[2], ecTopIn[2], positionTopIn[2]);
|
||||||
createVertex(2, 1, canopy_height, 0.0);
|
doSideVertex(2, 1, rawposIn[2], ecPosIn[2], gl_PositionIn[2]);
|
||||||
createVertex(2, 1, 0.0, 0.0);
|
|
||||||
EndPrimitive();
|
doSideVertex(0, 2, rawTopIn[0], ecTopIn[0], positionTopIn[0]);
|
||||||
createVertex(2, 0, canopy_height, 0.0);
|
doSideVertex(0, 2, rawposIn[0], ecPosIn[0], gl_PositionIn[0]);
|
||||||
createVertex(2, 0, 0.0, 0.0);
|
// Degenerate triangles; avoids EndPrimitive()
|
||||||
createVertex(0, 2, canopy_height, 0.0);
|
doSideVertex(0, 2, rawposIn[0], ecPosIn[0], gl_PositionIn[0]);
|
||||||
createVertex(0, 2, 0.0, 0.0);
|
doVertex(0, rawTopIn[0], ecTopIn[0], positionTopIn[0], NormalIn[0],
|
||||||
EndPrimitive();
|
ecNormalIn[0], 1.0);
|
||||||
createVertex(0, 1, 0.0, 0.0);
|
// Top
|
||||||
createVertex(1, 2, 0.0, 0.0);
|
}
|
||||||
createVertex(2, 0, 0.0, 0.0);
|
doVertex(0, rawTopIn[0], ecTopIn[0], positionTopIn[0], NormalIn[0],
|
||||||
EndPrimitive();
|
ecNormalIn[0], 1.0);
|
||||||
}
|
doVertex(1, rawTopIn[1], ecTopIn[1], positionTopIn[1], NormalIn[1],
|
||||||
createVertex(0, 1, canopy_height, 1.0);
|
ecNormalIn[1], 1.0);
|
||||||
createVertex(1, 2, canopy_height, 1.0);
|
doVertex(2, rawTopIn[2], ecTopIn[2], positionTopIn[2], NormalIn[2],
|
||||||
createVertex(2, 0, canopy_height, 1.0);
|
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();
|
EndPrimitive();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue