My terrain fragment shader stores the terrain normal in a texture. Per-vertex normals will not work because the terrain uses LOD and real-time lighting, and per-vertex normals would not light well. For texture layers that have a vertical mapping option enabled, the terrain normal from the normal map is used to determine which axes should be used for the diffuse texture texcoords. If the major axis of the normal is x, then the texture layer is mapped with the ZY axes.
A very strange artifact appears when using this technique on my 8800 GTS. I have not tested on any other cards. It looks as a wireframe render is being drawn. This seems to be a result of the if logic; it works fine if I force it to always use any of the three possible mapping axes.
This code is used to determine the mapping axes:
if (abs(worldNormal.z)>abs(worldNormal.x)) {
coord = texcoord0.xy;
}
else {
coord = texcoord0.zy;
}
I also tried rendering the major axis of the normal with red, green, or blue for x, y, and z, and it appeared as I would expect.
Here is my fragment shader:
uniform sampler2D texture0;// normal map
uniform sampler2D texture1;// alpha map
uniform sampler2D texture2;// texture0
uniform sampler2D texture3;// bumpmap0
uniform sampler2D texture4;// texture1
uniform sampler2D texture5;// bumpmap1
uniform sampler2D texture6;// texture2
uniform sampler2D texture7;// bumpmap2
//uniform sampler2D texture8;// texture3
//uniform sampler2D texture9;// bumpmap3
uniform sampler2DShadow texture8;
uniform sampler2DShadow texture9;
uniform sampler2DShadow texture10;
uniform sampler2DShadow texture11;
uniform sampler2DShadow texture12;
uniform sampler2DShadow texture13;
uniform sampler2DShadow texture14;
uniform sampler2DShadow texture15;
uniform sampler2DShadow texture16;
varying vec3 VertexPosition;
uniform vec3 CameraPosition;
uniform vec2 LayerPosition[ LW_TERRAINLAYERS ];
uniform vec2 LayerScale[ LW_TERRAINLAYERS ];
uniform float LayerRotation[ LW_TERRAINLAYERS ];
varying vec3 texcoord0;
varying vec2 texcoord1;
uniform mat4 LightMatrix[ LW_LIGHTMATRIXARRAYSIZE ];
varying vec4 ModelVertex;
varying vec3 T,B;
Include "light.txt"
Include "DirectionalShadow.txt"
Include "PointShadow.txt"
Include "SpotShadow.txt"
void main(void) {
vec4 AmbientLight = gl_LightSource[0].ambient;
float dirshadowoffset = 0.0001;
vec4 lightcolor = vec4(0.0,0.0,0.0,0.0);
vec4 albedo;
vec4 alpha = texture2D(texture1,texcoord1);
vec4 bumpcolor;
vec3 normal;
vec3 worldNormal = ((texture2D(texture0,texcoord1).xyz - 0.5) * 2.0).xyz;
vec3 N = normalize( gl_NormalMatrix * worldNormal);
vec3 bumpnormal = vec3(1.0,1.0,1.0);
float shininess = 0.0;
normal=N;
vec2 coord;
albedo = vec4(1.0);
#ifdef LW_LAYER0
#ifndef LW_LAYER0_VERTICAL
coord=texcoord0.xz;
#endif
#ifdef LW_LAYER0_VERTICAL
if (abs(worldNormal.z)>abs(worldNormal.x)) {
coord = texcoord0.xy;
}
else {
coord = texcoord0.zy;
}
#endif
albedo = texture2D(LW_LAYER0,coord / gl_LightSource[1].ambient.x);
#endif
#ifdef LW_LAYER1
#ifndef LW_LAYER1_VERTICAL
coord=texcoord0.xz;
#endif
#ifdef LW_LAYER1_VERTICAL
if (abs(worldNormal.z)>abs(worldNormal.x)) {
coord = texcoord0.xy;
}
else {
coord = texcoord0.zy;
}
#endif
albedo = (1.0 - alpha.x) * albedo + (alpha.x * texture2D(LW_LAYER1,coord / gl_LightSource[1].ambient.y));
#endif
#ifdef LW_LAYER2
#ifndef LW_LAYER2_VERTICAL
coord=texcoord0.xz;
#endif
#ifdef LW_LAYER2_VERTICAL
if (abs(worldNormal.z)>abs(worldNormal.x)) {
coord = texcoord0.xy;
}
else {
coord = texcoord0.zy;
}
#endif
albedo = (1.0 - alpha.y) * albedo + (alpha.y * texture2D(LW_LAYER2,coord / gl_LightSource[1].ambient.z));
#endif
#ifdef LW_LAYER3
#ifndef LW_LAYER3_VERTICAL
coord=texcoord0.xz;
#endif
#ifdef LW_LAYER3_VERTICAL
if (abs(worldNormal.z)>abs(worldNormal.x)) {
coord = texcoord0.xy;
}
else {
coord = texcoord0.zy;
}
#endif
albedo = (1.0 - alpha.z) * albedo + (alpha.z * texture2D(LW_LAYER3,coord / gl_LightSource[1].ambient.w));
#endif
//bumpcolor = texture2D(texture3,texcoord0);
//bumpnormal = normalize(bumpcolor.xyz - 0.5);
//#ifdef LW_LAYER1
// if (alpha.x>0.01) {
// vec2 coord;
// coord.y=texcoord0.y;
// if (abs(worldNormal.z)>abs(worldNormal.x)) {
// coord.x = texcoord0.x;
// }
// else {
// coord.x = texcoord0.z;
// }
//
// albedo = (1.0 - alpha.x) * albedo + (alpha.x * texture2D(texture3,coord / gl_LightSource[1].ambient.y));
// bumpcolor = texture2D(texture5,texcoord0);
// bumpnormal = bumpnormal * (1.0 - alpha) + normalize(bumpcolor.xyz - 0.5) * alpha;
// }
//#endif
normal = N;
//normal = T * bumpnormal.x + B * bumpnormal.y + N * bumpnormal.z;
//#ifdef LW_LAYER2
// albedo = (1.0 - alpha.y) * albedo + (alpha.y * texture2D(texture6,texcoord0*0.5));
// bumpcolor = texture2D(texture7,texcoord0);
// normal = normalize(bumpcolor.xyz - 0.5);
// normal = normal * (1.0 - alpha.y) + (alpha.y * (T * normal.x + B * normal.y + N * normal.z));
//#endif
//#ifdef LW_LAYER3
// albedo = (1.0 - alpha.z) * albedo + (alpha.z * texture2D(texture8,texcoord0*0.5));
// bumpcolor = texture2D(texture9,texcoord0);
// normal = normalize(bumpcolor.xyz - 0.5);
// normal = normal * (1.0 - alpha.z) + (alpha.z * (T * normal.x + B * normal.y + N * normal.z));
//#endif
Include "ProcessLights.txt"
gl_FragColor = albedo * AmbientLight + albedo * lightcolor;
//gl_FragColor = AmbientLight * 0.5 + lightcolor * 0.5;
//if (abs(worldNormal.x)>abs(worldNormal.z)) {
// gl_FragColor = vec4(1.0,0.0,0.0,1.0);
//}
//else {
// gl_FragColor = vec4(0.0,0.0,1.0,1.0);
//}
Include "Fog.txt"
//gl_FragColor=alpha;
}