forked from 0ad/0ad
279 lines
7.0 KiB
GLSL
279 lines
7.0 KiB
GLSL
#version 120
|
|
|
|
uniform sampler2D baseTex;
|
|
uniform sampler2D losTex;
|
|
uniform sampler2D aoTex;
|
|
uniform sampler2D normTex;
|
|
uniform sampler2D specTex;
|
|
|
|
#if USE_SHADOW
|
|
varying vec4 v_shadow;
|
|
#if USE_SHADOW_SAMPLER
|
|
uniform sampler2DShadow shadowTex;
|
|
#if USE_SHADOW_PCF
|
|
uniform vec4 shadowScale;
|
|
#endif
|
|
#else
|
|
uniform sampler2D shadowTex;
|
|
#endif
|
|
#endif
|
|
|
|
#if USE_OBJECTCOLOR
|
|
uniform vec3 objectColor;
|
|
#else
|
|
#if USE_PLAYERCOLOR
|
|
uniform vec3 playerColor;
|
|
#endif
|
|
#endif
|
|
|
|
uniform vec3 shadingColor;
|
|
uniform vec3 ambient;
|
|
uniform vec3 sunColor;
|
|
uniform vec3 sunDir;
|
|
|
|
uniform vec3 fogColor;
|
|
uniform vec2 fogParams;
|
|
|
|
varying vec4 v_lighting;
|
|
varying vec2 v_tex;
|
|
varying vec2 v_los;
|
|
|
|
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
|
|
varying vec2 v_tex2;
|
|
#endif
|
|
|
|
#if USE_SPECULAR
|
|
uniform float specularPower;
|
|
uniform vec3 specularColor;
|
|
#endif
|
|
|
|
#if USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP || USE_AO
|
|
uniform vec4 effectSettings;
|
|
#endif
|
|
|
|
#if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP
|
|
varying vec4 v_normal;
|
|
#if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX_MAP)
|
|
varying vec4 v_tangent;
|
|
//varying vec3 v_bitangent;
|
|
#endif
|
|
#if USE_SPECULAR || USE_SPECULAR_MAP
|
|
varying vec3 v_half;
|
|
#endif
|
|
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
|
|
varying vec3 v_eyeVec;
|
|
#endif
|
|
#endif
|
|
|
|
float get_shadow()
|
|
{
|
|
float shadowBias = 0.003;
|
|
#if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS
|
|
float biasedShdwZ = v_shadow.z - shadowBias;
|
|
#if USE_SHADOW_SAMPLER
|
|
#if USE_SHADOW_PCF
|
|
vec2 offset = fract(v_shadow.xy - 0.5);
|
|
vec4 size = vec4(offset + 1.0, 2.0 - offset);
|
|
vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (v_shadow.xy - 0.5*offset).xyxy) * shadowScale.zwzw;
|
|
return (1.0/9.0)*dot(size.zxzx*size.wwyy,
|
|
vec4(shadow2D(shadowTex, vec3(weight.zw, biasedShdwZ)).r,
|
|
shadow2D(shadowTex, vec3(weight.xw, biasedShdwZ)).r,
|
|
shadow2D(shadowTex, vec3(weight.zy, biasedShdwZ)).r,
|
|
shadow2D(shadowTex, vec3(weight.xy, biasedShdwZ)).r));
|
|
#else
|
|
return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r;
|
|
#endif
|
|
#else
|
|
if (biasedShdwZ >= 1.0)
|
|
return 1.0;
|
|
return (biasedShdwZ < texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0);
|
|
#endif
|
|
#else
|
|
return 1.0;
|
|
#endif
|
|
}
|
|
|
|
vec3 get_fog(vec3 color)
|
|
{
|
|
float density = fogParams.x;
|
|
float maxFog = fogParams.y;
|
|
|
|
const float LOG2 = 1.442695;
|
|
float z = gl_FragCoord.z / gl_FragCoord.w;
|
|
float fogFactor = exp2(-density * density * z * z * LOG2);
|
|
|
|
fogFactor = fogFactor * (1.0 - maxFog) + maxFog;
|
|
|
|
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
|
|
|
return mix(fogColor, color, fogFactor);
|
|
}
|
|
|
|
void main()
|
|
{
|
|
vec2 coord = v_tex;
|
|
|
|
#if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_PARALLAX_MAP || USE_NORMAL_MAP)
|
|
vec3 bitangent = vec3(v_normal.w, v_tangent.w, v_lighting.w);
|
|
mat3 tbn = mat3(v_tangent.xyz, bitangent, v_normal.xyz);
|
|
#endif
|
|
|
|
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
|
|
{
|
|
float h = texture2D(normTex, coord).a;
|
|
|
|
vec3 eyeDir = normalize(v_eyeVec * tbn);
|
|
float dist = length(v_eyeVec);
|
|
|
|
float s;
|
|
vec2 move;
|
|
float height = 1.0;
|
|
float scale = effectSettings.z;
|
|
|
|
scale = (scale * (float(PARALLAX_DIST_MAX) - dist)) / float(PARALLAX_DIST_MAX);
|
|
|
|
float iter = 8.0;
|
|
#if USE_HQ_PARALLAX
|
|
iter = 16.0;
|
|
#if USE_VHQ_PARALLAX
|
|
iter = 24.0;
|
|
#endif
|
|
#endif
|
|
|
|
s = 1.0 / iter;
|
|
float t = s;
|
|
move = vec2(-eyeDir.x, eyeDir.y) * scale / (eyeDir.z * iter);
|
|
vec2 nil = vec2(0.0);
|
|
|
|
#define PARALLAX_ITER {\
|
|
height -= t;\
|
|
t = (h < height) ? s : 0.0;\
|
|
vec2 temp = (h < height) ? move : nil;\
|
|
coord += temp;\
|
|
h = texture2D(normTex, coord).a;\
|
|
}
|
|
|
|
// 8 iterations of parallax
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
|
|
// an additional 8 iterations for the HQ parallax
|
|
#if USE_HQ_PARALLAX
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
|
|
#if USE_VHQ_PARALLAX
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
PARALLAX_ITER
|
|
#endif
|
|
#endif
|
|
|
|
// Move back to where we collided with the surface.
|
|
// This assumes the surface is linear between the sample point before we
|
|
// intersect the surface and after we intersect the surface
|
|
float hp = texture2D(normTex, coord - move).a;
|
|
coord -= move * ((h - height) / (s + h - hp));
|
|
}
|
|
#endif
|
|
|
|
vec4 tex = texture2D(baseTex, coord);
|
|
|
|
// Alpha-test as early as possible
|
|
#ifdef REQUIRE_ALPHA_GEQUAL
|
|
if (tex.a < REQUIRE_ALPHA_GEQUAL)
|
|
discard;
|
|
#endif
|
|
|
|
#if USE_TRANSPARENT
|
|
gl_FragColor.a = tex.a;
|
|
#else
|
|
gl_FragColor.a = 1.0;
|
|
#endif
|
|
|
|
vec3 texdiffuse = tex.rgb;
|
|
|
|
// Apply-coloring based on texture alpha
|
|
#if USE_OBJECTCOLOR
|
|
texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a);
|
|
#else
|
|
#if USE_PLAYERCOLOR
|
|
texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), tex.a);
|
|
#endif
|
|
#endif
|
|
|
|
#if USE_SPECULAR || USE_SPECULAR_MAP || USE_NORMAL_MAP
|
|
vec3 normal = v_normal.xyz;
|
|
#endif
|
|
|
|
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_NORMAL_MAP
|
|
vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0;
|
|
ntex.y = -ntex.y;
|
|
normal = normalize(tbn * ntex);
|
|
vec3 bumplight = max(dot(-sunDir, normal), 0.0) * sunColor;
|
|
vec3 sundiffuse = (bumplight - v_lighting.rgb) * effectSettings.x + v_lighting.rgb;
|
|
#else
|
|
vec3 sundiffuse = v_lighting.rgb;
|
|
#endif
|
|
|
|
vec4 specular = vec4(0.0);
|
|
#if USE_SPECULAR || USE_SPECULAR_MAP
|
|
vec3 specCol;
|
|
float specPow;
|
|
#if USE_SPECULAR_MAP
|
|
vec4 s = texture2D(specTex, coord);
|
|
specCol = s.rgb;
|
|
specular.a = s.a;
|
|
specPow = effectSettings.y;
|
|
#else
|
|
specCol = specularColor;
|
|
specPow = specularPower;
|
|
#endif
|
|
specular.rgb = sunColor * specCol * pow(max(0.0, dot(normalize(normal), v_half)), specPow);
|
|
#endif
|
|
|
|
vec3 color = (texdiffuse * sundiffuse + specular.rgb) * get_shadow();
|
|
vec3 ambColor = texdiffuse * ambient;
|
|
|
|
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
|
|
vec3 ao = texture2D(aoTex, v_tex2).rrr;
|
|
ao = mix(vec3(1.0), ao * 2.0, effectSettings.w);
|
|
ambColor *= ao;
|
|
#endif
|
|
|
|
color += ambColor;
|
|
|
|
#if USE_SPECULAR_MAP && USE_SELF_LIGHT
|
|
color = mix(texdiffuse, color, specular.a);
|
|
#endif
|
|
|
|
color = get_fog(color);
|
|
|
|
#if !IGNORE_LOS
|
|
float los = texture2D(losTex, v_los).a;
|
|
los = los < 0.03 ? 0.0 : los;
|
|
color *= los;
|
|
#endif
|
|
|
|
color *= shadingColor;
|
|
|
|
gl_FragColor.rgb = color;
|
|
}
|