1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
|
// ARB shader receives groundAmbientColor multiplied
// by this constant; shading-texture intensities are
// also pre-dimmed
#define SMF_TEXSQR_SIZE 1024.0
#define SMF_INTENSITY_MUL (210.0 / 255.0)
#define SSMF_UNCOMPRESSED_NORMALS 0
#define SMF_SHALLOW_WATER_DEPTH (10.0 )
#define SMF_SHALLOW_WATER_DEPTH_INV ( 1.0 / SMF_SHALLOW_WATER_DEPTH)
#if (SMF_PARALLAX_MAPPING == 1)
#version 120
#endif
uniform vec4 lightDir;
uniform sampler2D diffuseTex;
uniform sampler2D normalsTex;
uniform sampler2DShadow shadowTex;
uniform sampler2D detailTex;
uniform sampler2D specularTex;
#if (HAVE_SHADOWS == 1)
uniform mat4 shadowMat;
uniform vec4 shadowParams;
#endif
uniform vec3 groundAmbientColor;
uniform vec3 groundDiffuseColor;
uniform vec3 groundSpecularColor;
uniform float groundShadowDensity;
#if (SMF_WATER_ABSORPTION == 1)
uniform vec3 waterMinColor;
uniform vec3 waterBaseColor;
uniform vec3 waterAbsorbColor;
#endif
#if (SMF_DETAIL_TEXTURE_SPLATTING == 1)
uniform sampler2D splatDetailTex;
uniform sampler2D splatDistrTex;
// per-channel splat intensity multipliers
uniform vec4 splatTexMults;
#endif
#if (SMF_SKY_REFLECTIONS == 1)
uniform samplerCube skyReflectTex;
uniform sampler2D skyReflectModTex;
#endif
#if (SMF_DETAIL_NORMALS == 1)
uniform sampler2D detailNormalTex;
#endif
#if (SMF_LIGHT_EMISSION == 1)
uniform sampler2D lightEmissionTex;
#endif
#if (SMF_PARALLAX_MAPPING == 1)
uniform sampler2D parallaxHeightTex;
uniform vec2 normalTexGen;
uniform vec2 specularTexGen;
#endif
uniform vec3 cameraPos;
varying vec3 halfDir;
varying float fogFactor;
varying vec4 vertexWorldPos;
varying vec2 diffuseTexCoords;
varying vec2 specularTexCoords;
varying vec2 normalTexCoords;
uniform int numMapDynLights;
#if (SMF_PARALLAX_MAPPING == 1)
vec2 GetParallaxUVOffset(vec2 uv, vec3 dir) {
vec4 texel = texture2D(parallaxHeightTex, uv);
// RG: height in [ 0.0, 1.0] (256^2 strata)
// B: scale in [ 0.0, 1.0] (256 strata), eg. 0.04 (~10.0/256.0)
// A: bias in [-0.5, 0.5] (256 strata), eg. -0.02 (~75.0/256.0)
//
#define RMUL 65280.0 // 255 * 256
#define GMUL 256.0
#define HDIV 65536.0
float heightValue = (texel.r * RMUL + texel.g * GMUL) / HDIV;
float heightScale = texel.b;
float heightBias = texel.a - 0.5;
float heightOffset = heightValue * heightScale + heightBias;
return ((dir.xy / dir.z) * heightOffset);
}
#endif
vec3 GetFragmentNormal(vec2 uv) {
vec3 normal;
#if (SSMF_UNCOMPRESSED_NORMALS == 1)
normal = normalize(texture2D(normalsTex, uv).xyz);
#else
normal.xz = texture2D(normalsTex, uv).ra;
normal.y = sqrt(1.0 - dot(normal.xz, normal.xz));
#endif
return normal;
}
vec4 GetDetailTextureColor(vec2 uv) {
#if (SMF_DETAIL_TEXTURE_SPLATTING == 0)
vec4 detailCol = (texture2D(detailTex, gl_TexCoord[0].st) * 2.0) - 1.0;
#else
vec4 splatDetails;
splatDetails.r = texture2D(splatDetailTex, gl_TexCoord[0].st).r;
splatDetails.g = texture2D(splatDetailTex, gl_TexCoord[0].pq).g;
splatDetails.b = texture2D(splatDetailTex, gl_TexCoord[1].st).b;
splatDetails.a = texture2D(splatDetailTex, gl_TexCoord[1].pq).a;
splatDetails = (splatDetails * 2.0) - 1.0;
vec4 splatCofac = texture2D(splatDistrTex, uv) * splatTexMults;
vec4 detailCol = vec4(dot(splatDetails, splatCofac));
#endif
return detailCol;
}
void main() {
vec2 diffTexCoords = diffuseTexCoords;
vec2 normTexCoords = normalTexCoords;
vec2 specTexCoords = specularTexCoords;
// not calculated in the vertex shader to save varying components (OpenGL2.0 allows just 32)
vec3 cameraDir = vertexWorldPos.xyz - cameraPos;
vec3 normal = GetFragmentNormal(normTexCoords);
#if (SMF_DETAIL_NORMALS == 1 || SMF_PARALLAX_MAPPING == 1)
// detail-normals are (assumed to be) defined within STN space
// (for a regular vertex normal equal to <0, 1, 0>, the S- and
// T-tangents are aligned with Spring's +x and +z (!) axes)
vec3 tTangent = cross(normal, vec3(-1.0, 0.0, 0.0));
vec3 sTangent = cross(normal, tTangent);
mat3 stnMatrix = mat3(sTangent, tTangent, normal);
#endif
#if (SMF_PARALLAX_MAPPING == 1)
{
// use specular-texture coordinates to index parallaxHeightTex
// (ie. specularTex and parallaxHeightTex must have equal size)
// cameraDir does not need to be normalized, x/z and y/z ratios
// do not change
vec2 uvOffset = GetParallaxUVOffset(specularTexCoords, transpose(stnMatrix) * cameraDir);
vec2 normTexSize = 1.0 / normalTexGen;
vec2 specTexSize = 1.0 / specularTexGen;
// scale the parallax offset since it is in spectex-space
diffTexCoords += (uvOffset * (specTexSize / SMF_TEXSQR_SIZE));
normTexCoords += (uvOffset * (specTexSize / normTexSize));
specTexCoords += (uvOffset);
normal = GetFragmentNormal(normTexCoords);
}
#endif
#if (SMF_DETAIL_NORMALS == 1)
{
vec4 dtSample = texture2D(detailNormalTex, normTexCoords);
vec3 dtNormal = (dtSample.xyz * 2.0) - 1.0;
// convert dtNormal from TS to WS before mixing
normal = normalize(mix(normal, stnMatrix * dtNormal, dtSample.a));
}
#endif
float cosAngleDiffuse = clamp(dot(normalize(lightDir.xyz), normal), 0.0, 1.0);
float cosAngleSpecular = clamp(dot(normalize(halfDir), normal), 0.0, 1.0);
vec4 diffuseCol = texture2D(diffuseTex, diffTexCoords);
vec4 specularCol = texture2D(specularTex, specTexCoords);
vec4 detailCol = GetDetailTextureColor(specTexCoords);
#if (SMF_SKY_REFLECTIONS == 1)
{
// cameraDir does not need to be normalized for reflect()
vec3 reflectDir = reflect(cameraDir, normal);
vec3 reflectCol = textureCube(skyReflectTex, gl_NormalMatrix * reflectDir).rgb;
vec3 reflectMod = texture2D(skyReflectModTex, specTexCoords).rgb;
diffuseCol.rgb = mix(diffuseCol.rgb, reflectCol, reflectMod);
}
#endif
float shadowCoeff = 1.0;
#if (HAVE_SHADOWS == 1)
{
vec2 p17 = vec2(shadowParams.z, shadowParams.z);
vec2 p18 = vec2(shadowParams.w, shadowParams.w);
vec4 vertexShadowPos = shadowMat * vertexWorldPos;
vertexShadowPos.st *= (inversesqrt(abs(vertexShadowPos.st) + p17) + p18);
vertexShadowPos.st += shadowParams.xy;
// same as ARB shader: shadowCoeff = 1 - (1 - shadowCoeff) * groundShadowDensity
shadowCoeff = shadow2DProj(shadowTex, vertexShadowPos).r;
shadowCoeff = mix(1.0, shadowCoeff, groundShadowDensity);
}
#endif
// Light Ambient + Diffuse
vec4 shadeInt;
shadeInt.rgb = groundAmbientColor + groundDiffuseColor * (shadowCoeff * cosAngleDiffuse);
shadeInt.rgb *= SMF_INTENSITY_MUL;
shadeInt.a = 1.0;
#if (SMF_WATER_ABSORPTION == 1)
if (vertexWorldPos.y < 0.0) {
float waterHeightAlpha = abs(vertexWorldPos.y) * SMF_SHALLOW_WATER_DEPTH_INV;
float waterShadeDecay = 0.2 + (waterHeightAlpha * 0.1);
float vertexStepHeight = min(1023.0, -floor(vertexWorldPos.y));
float waterLightInt = min((cosAngleDiffuse + 0.2) * 2.0, 1.0);
vec4 waterHeightColor;
waterHeightColor.a = max(0.0, (255.0 + SMF_SHALLOW_WATER_DEPTH * vertexWorldPos.y) / 255.0);
waterHeightColor.rgb = waterBaseColor.rgb - (waterAbsorbColor.rgb * vertexStepHeight);
waterHeightColor.rgb = max(waterMinColor.rgb, waterHeightColor.rgb);
waterHeightColor.rgb *= SMF_INTENSITY_MUL * waterLightInt;
// make shadowed areas darker over deeper water
waterHeightColor.rgb -= (waterHeightColor.rgb * waterShadeDecay * (1.0 - shadowCoeff));
// "shallow" water, interpolate between shadeInt and
// waterHeightColor (both are already cosine-weighted)
if (vertexWorldPos.y > -SMF_SHALLOW_WATER_DEPTH) {
waterHeightColor.rgb = mix(shadeInt.rgb, waterHeightColor.rgb, waterHeightAlpha);
}
shadeInt = waterHeightColor;
}
#endif
// GroundMaterialAmbientDiffuseColor * LightAmbientDiffuseColor
gl_FragColor = (diffuseCol + detailCol) * shadeInt;
#if (SMF_LIGHT_EMISSION == 1)
{
vec4 lightEmissionCol = texture2D(lightEmissionTex, specTexCoords);
vec3 scaledFragmentCol = gl_FragColor.rgb * (1.0 - lightEmissionCol.a);
gl_FragColor.rgb = scaledFragmentCol + lightEmissionCol.rgb;
}
#endif
#if (SMF_ARB_LIGHTING == 0)
// sun specular lighting contribution
float specularExp = specularCol.a * 16.0;
float specularPow = pow(cosAngleSpecular, specularExp);
vec3 specularInt = specularCol.rgb * specularPow;
specularInt *= shadowCoeff;
// no need to multiply by groundSpecularColor anymore
gl_FragColor.rgb += specularInt;
#endif
#if (MAX_DYNAMIC_MAP_LIGHTS > 0)
for (int i = 0; i < MAX_DYNAMIC_MAP_LIGHTS; i++) {
vec3 lightVec = gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].position.xyz - vertexWorldPos.xyz;
vec3 halfVec = gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].halfVector.xyz;
float lightRadius = gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].constantAttenuation;
float lightDistance = length(lightVec);
float lightScale = (lightDistance > lightRadius)? 0.0: 1.0;
float lightCosAngDiff = clamp(dot(normal, lightVec / lightDistance), 0.0, 1.0);
float lightCosAngSpec = clamp(dot(normal, normalize(halfVec)), 0.0, 1.0);
#ifdef OGL_SPEC_ATTENUATION
float lightAttenuation =
(gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].constantAttenuation) +
(gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].linearAttenuation * lightDistance) +
(gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].quadraticAttenuation * lightDistance * lightDistance);
lightAttenuation = 1.0 / max(lightAttenuation, 1.0);
#else
float lightAttenuation = 1.0 - min(1.0, ((lightDistance * lightDistance) / (lightRadius * lightRadius)));
#endif
float vectorDot = dot((-lightVec / lightDistance), gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].spotDirection);
float cutoffDot = gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].spotCosCutoff;
#if (SMF_ARB_LIGHTING == 0)
float lightSpecularPow = max(0.0, pow(lightCosAngSpec, specularExp));
#else
float lightSpecularPow = 0.0;
#endif
lightScale *= ((vectorDot < cutoffDot)? 0.0: 1.0);
gl_FragColor.rgb += (lightScale * gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].ambient.rgb);
gl_FragColor.rgb += (lightScale * lightAttenuation * (diffuseCol.rgb * gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].diffuse.rgb * lightCosAngDiff));
gl_FragColor.rgb += (lightScale * lightAttenuation * (specularCol.rgb * gl_LightSource[BASE_DYNAMIC_MAP_LIGHT + i].specular.rgb * lightSpecularPow));
}
#endif
gl_FragColor = mix(gl_Fog.color, gl_FragColor, fogFactor);
gl_FragColor.a = min(diffuseCol.a, (vertexWorldPos.y * 0.1) + 1.0);
}
|