Index: ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_fragment.h =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_fragment.h (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_fragment.h (revision 24732) @@ -0,0 +1,21 @@ +#ifndef INCLUDED_LOS_FRAGMENT +#define INCLUDED_LOS_FRAGMENT + +#if !IGNORE_LOS + uniform sampler2D losTex; + + varying vec2 v_los; +#endif + +float getLOS() +{ +#if !IGNORE_LOS + float los = texture2D(losTex, v_los).a; + float threshold = 0.03; + return (los - threshold) / (1.0 - threshold); +#else + return 1.0; +#endif +} + +#endif // INCLUDED_LOS_FRAGMENT Property changes on: ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_fragment.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_vertex.h =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_vertex.h (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_vertex.h (revision 24732) @@ -0,0 +1,17 @@ +#ifndef INCLUDED_LOS_VERTEX +#define INCLUDED_LOS_VERTEX + +#if !IGNORE_LOS + uniform vec2 losTransform; + + varying vec2 v_los; +#endif + +void calculateLOSCoordinates(vec2 position) +{ +#if !IGNORE_LOS + v_los = position * losTransform.x + losTransform.y; +#endif +} + +#endif // INCLUDED_LOS_VERTEX Property changes on: ps/trunk/binaries/data/mods/public/shaders/glsl/common/los_vertex.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 24732) @@ -1,183 +1,178 @@ #version 120 #include "common/fog.h" +#include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; -uniform sampler2D losTex; uniform sampler2D aoTex; uniform sampler2D normTex; uniform sampler2D specTex; #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; 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 || USE_AO uniform vec4 effectSettings; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX varying vec4 v_normal; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX) 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 varying vec3 v_eyeVec; #endif #endif void main() { vec2 coord = v_tex; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_PARALLAX || 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 { float h = texture2D(normTex, coord).a; vec3 eyeDir = normalize(v_eyeVec * tbn); float dist = length(v_eyeVec); vec2 move; float height = 1.0; float scale = effectSettings.z; int iter = int(min(20.0, 25.0 - dist/10.0)); if (iter > 0) { float s = 1.0/float(iter); float t = s; move = vec2(-eyeDir.x, eyeDir.y) * scale / (eyeDir.z * float(iter)); vec2 nil = vec2(0.0); for (int i = 0; i < iter; ++i) { height -= t; t = (h < height) ? s : 0.0; vec2 temp = (h < height) ? move : nil; coord += temp; h = texture2D(normTex, coord).a; } // 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 = applyFog(color); - #if !IGNORE_LOS - float los = texture2D(losTex, v_los).a; - los = los < 0.03 ? 0.0 : los; - color *= los; - #endif + color *= getLOS(); color *= shadingColor; gl_FragColor.rgb = color; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs (revision 24732) @@ -1,172 +1,171 @@ #version 120 +#include "common/los_vertex.h" #include "common/shadows_vertex.h" uniform mat4 transform; uniform vec3 cameraPos; #ifdef GL_ES uniform mediump vec3 sunDir; uniform mediump vec3 sunColor; #else uniform vec3 sunDir; uniform vec3 sunColor; #endif -uniform vec2 losTransform; uniform mat4 instancingTransform; #if USE_WIND uniform vec4 sim_time; uniform vec4 windData; #endif 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 || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX varying vec4 v_normal; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX) 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 varying vec3 v_eyeVec; #endif #endif attribute vec3 a_vertex; attribute vec3 a_normal; #if (USE_INSTANCING || USE_GPU_SKINNING) attribute vec4 a_tangent; #endif attribute vec2 a_uv0; attribute vec2 a_uv1; #if USE_GPU_SKINNING const int MAX_INFLUENCES = 4; const int MAX_BONES = 64; uniform mat4 skinBlendMatrices[MAX_BONES]; attribute vec4 a_skinJoints; attribute vec4 a_skinWeights; #endif vec4 fakeCos(vec4 x) { vec4 tri = abs(fract(x + 0.5) * 2.0 - 1.0); - return tri * tri *(3.0 - 2.0 * tri); + return tri * tri *(3.0 - 2.0 * tri); } void main() { #if USE_GPU_SKINNING vec3 p = vec3(0.0); vec3 n = vec3(0.0); for (int i = 0; i < MAX_INFLUENCES; ++i) { int joint = int(a_skinJoints[i]); if (joint != 0xff) { mat4 m = skinBlendMatrices[joint]; p += vec3(m * vec4(a_vertex, 1.0)) * a_skinWeights[i]; n += vec3(m * vec4(a_normal, 0.0)) * a_skinWeights[i]; } } vec4 position = instancingTransform * vec4(p, 1.0); mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); vec3 normal = normalMatrix * normalize(n); #if (USE_NORMAL_MAP || USE_PARALLAX) vec3 tangent = normalMatrix * a_tangent.xyz; #endif #else #if (USE_INSTANCING) vec4 position = instancingTransform * vec4(a_vertex, 1.0); mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); vec3 normal = normalMatrix * a_normal; #if (USE_NORMAL_MAP || USE_PARALLAX) vec3 tangent = normalMatrix * a_tangent.xyz; #endif #else vec4 position = vec4(a_vertex, 1.0); vec3 normal = a_normal; #endif #endif #if USE_WIND vec2 wind = windData.xy; // fractional part of model position, clamped to >.4 vec4 modelPos = instancingTransform[3]; modelPos = fract(modelPos); modelPos = clamp(modelPos, 0.4, 1.0); // crude measure of wind intensity float abswind = abs(wind.x) + abs(wind.y); vec4 cosVec; // these determine the speed of the wind's "cosine" waves. cosVec.w = 0.0; cosVec.x = sim_time.x * modelPos[0] + position.x; cosVec.y = sim_time.x * modelPos[2] / 3.0 + instancingTransform[3][0]; cosVec.z = sim_time.x * abswind / 4.0 + position.z; // calculate "cosines" in parallel, using a smoothed triangle wave cosVec = fakeCos(cosVec); float limit = clamp((a_vertex.x * a_vertex.z * a_vertex.y) / 3000.0, 0.0, 0.2); - float diff = cosVec.x * limit; + float diff = cosVec.x * limit; float diff2 = cosVec.y * clamp(a_vertex.y / 60.0, 0.0, 0.25); // fluttering of model parts based on distance from model center (ie longer branches) position.xyz += cosVec.z * limit * clamp(abswind, 1.2, 1.7); // swaying of trunk based on distance from ground (higher parts sway more) position.xz += diff + diff2 * wind; #endif gl_Position = transform * position; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX v_normal.xyz = normal; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX) v_tangent.xyz = tangent; vec3 bitangent = cross(v_normal.xyz, v_tangent.xyz) * a_tangent.w; v_normal.w = bitangent.x; v_tangent.w = bitangent.y; v_lighting.w = bitangent.z; #endif #if USE_SPECULAR || USE_SPECULAR_MAP || USE_PARALLAX vec3 eyeVec = cameraPos.xyz - position.xyz; - #if USE_SPECULAR || USE_SPECULAR_MAP + #if USE_SPECULAR || USE_SPECULAR_MAP vec3 sunVec = -sunDir; v_half = normalize(sunVec + normalize(eyeVec)); #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX v_eyeVec = eyeVec; #endif #endif #endif - + v_lighting.xyz = max(0.0, dot(normal, -sunDir)) * sunColor; v_tex = a_uv0; #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO v_tex2 = a_uv1; #endif calculatePositionInShadowSpace(position); - v_los = position.xz * losTransform.x + losTransform.y; + calculateLOSCoordinates(position.xz); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (revision 24732) @@ -1,108 +1,100 @@ #version 120 +#include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; -uniform sampler2D losTex; uniform sampler2D aoTex; uniform sampler2D normTex; uniform sampler2D specTex; uniform sampler2D waterTex; uniform samplerCube skyCube; #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 cameraPos; uniform float specularStrength; uniform float waviness; uniform vec3 waterTint; uniform float murkiness; uniform vec3 reflectionTint; uniform float reflectionTintStrength; -float waterDepth = 4.0; +float waterDepth = 4.0; float fullDepth = 5.0; // Depth at which to use full murkiness (shallower water will be clearer) varying vec4 worldPos; varying vec4 v_tex; -varying vec2 v_los; void main() { vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye) float ndotl, ndoth, ndotv; float fresnel; float t; // Temporary variable vec2 reflCoords, refrCoords; vec3 reflColor, refrColor, specular; - float losMod; //vec4 wtex = textureGrad(waterTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); vec4 wtex = texture2D(waterTex, fract(v_tex.xy)); n = normalize(wtex.xzy - vec3(0.5, 0.5, 0.5)); l = -sunDir; v = normalize(cameraPos - worldPos.xyz); h = normalize(l + v); - + ndotl = dot(n, l); ndoth = dot(n, h); ndotv = dot(n, v); - + fresnel = pow(1.0 - ndotv, 0.8); // A rather random Fresnel approximation - + //refrCoords = (0.5*gl_TexCoord[2].xy - 0.8*waviness*n.xz) / gl_TexCoord[2].w + 0.5; // Unbias texture coords //reflCoords = (0.5*gl_TexCoord[1].xy + waviness*n.xz) / gl_TexCoord[1].w + 0.5; // Unbias texture coords - + //vec3 dir = normalize(v + vec3(waviness*n.x, 0.0, waviness*n.z)); vec3 eye = reflect(v, n); - + vec3 tex = textureCube(skyCube, eye).rgb; - reflColor = mix(tex, sunColor * reflectionTint, + reflColor = mix(tex, sunColor * reflectionTint, reflectionTintStrength); //waterDepth = 4.0 + 2.0 * dot(abs(v_tex.zw - 0.5), vec2(0.5)); waterDepth = 4.0; - + //refrColor = (0.5 + 0.5*ndotl) * mix(texture2D(refractionMap, refrCoords).rgb, sunColor * tint, refrColor = (0.5 + 0.5*ndotl) * mix(vec3(0.3), sunColor * waterTint, murkiness * clamp(waterDepth / fullDepth, 0.0, 1.0)); // Murkiness and tint at this pixel (tweaked based on lighting and depth) - - specular = pow(max(0.0, ndoth), 150.0f) * sunColor * specularStrength; - losMod = texture2D(losTex, v_los).a; + specular = pow(max(0.0, ndoth), 150.0f) * sunColor * specularStrength; #if USE_SHADOW float shadow = get_shadow(); float fresShadow = mix(fresnel, fresnel*shadow, dot(sunColor, vec3(0.16666))); #else float fresShadow = fresnel; #endif - - vec3 color = mix(refrColor + 0.3*specular, reflColor + specular, fresShadow); - gl_FragColor.rgb = color * losMod; + vec3 color = mix(refrColor + 0.3*specular, reflColor + specular, fresShadow); + gl_FragColor.rgb = color * getLOS(); - //gl_FragColor.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel) * losMod; - // Make alpha vary based on both depth (so it blends with the shore) and view angle (make it // become opaque faster at lower view angles so we can't look "underneath" the water plane) t = 18.0 * max(0.0, 0.7 - v.y); gl_FragColor.a = 0.15 * waterDepth * (1.2 + t + fresnel); } - Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs (revision 24732) @@ -1,59 +1,58 @@ #if USE_GPU_SKINNING // Skinning requires GLSL 1.30 for ivec4 vertex attributes #version 130 #else #version 120 #endif +#include "common/los_vertex.h" #include "common/shadows_vertex.h" uniform mat4 transform; uniform vec3 cameraPos; uniform vec3 sunDir; uniform vec3 sunColor; -uniform vec2 losTransform; uniform mat4 instancingTransform; uniform float sim_time; uniform vec2 translation; attribute vec3 a_vertex; attribute vec3 a_normal; #if USE_INSTANCING attribute vec4 a_tangent; #endif attribute vec2 a_uv0; attribute vec2 a_uv1; #if USE_GPU_SKINNING const int MAX_INFLUENCES = 4; const int MAX_BONES = 64; uniform mat4 skinBlendMatrices[MAX_BONES]; attribute ivec4 a_skinJoints; attribute vec4 a_skinWeights; #endif varying vec4 worldPos; varying vec4 v_tex; -varying vec2 v_los; vec4 fakeCos(vec4 x) { vec4 tri = abs(fract(x + 0.5) * 2.0 - 1.0); - return tri * tri *(3.0 - 2.0 * tri); + return tri * tri *(3.0 - 2.0 * tri); } void main() { worldPos = instancingTransform * vec4(a_vertex, 1.0); - + v_tex.xy = (a_uv0 + worldPos.xz) / 5.0 + sim_time * translation; v_tex.zw = a_uv0; calculatePositionInShadowSpace(worldPos); - v_los = worldPos.xz * losTransform.x + losTransform.y; + calculateLOSCoordinates(worldPos.xz); gl_Position = transform * worldPos; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (revision 24732) @@ -1,47 +1,42 @@ #version 120 +#include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; -uniform sampler2D losTex; uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; uniform vec3 cameraPos; uniform float specularPower; uniform vec3 specularColor; varying vec4 v_tex; -varying vec2 v_los; varying vec3 v_half; varying vec3 v_normal; varying float v_transp; varying vec3 v_lighting; void main() { //vec4 texdiffuse = textureGrad(baseTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); vec4 texdiffuse = texture2D(baseTex, fract(v_tex.xy)); if (texdiffuse.a < 0.25) discard; texdiffuse.a *= v_transp; vec3 specular = sunColor * specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower); vec3 color = (texdiffuse.rgb * v_lighting + specular) * get_shadow(); color += texdiffuse.rgb * ambient; - #if !IGNORE_LOS - float los = texture2D(losTex, v_los).a; - los = los < 0.03 ? 0.0 : los; - color *= los; - #endif + color *= getLOS(); gl_FragColor.rgb = color; gl_FragColor.a = texdiffuse.a; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs (revision 24732) @@ -1,54 +1,52 @@ #if USE_GPU_SKINNING // Skinning requires GLSL 1.30 for ivec4 vertex attributes #version 130 #else #version 120 #endif +#include "common/los_vertex.h" #include "common/shadows_vertex.h" uniform mat4 transform; uniform vec3 cameraPos; uniform vec3 sunDir; uniform vec3 sunColor; -uniform vec2 losTransform; uniform mat4 instancingTransform; uniform float sim_time; uniform vec2 translation; attribute vec3 a_vertex; attribute vec3 a_normal; attribute vec2 a_uv0; attribute vec2 a_uv1; varying vec4 worldPos; varying vec4 v_tex; -varying vec2 v_los; varying vec3 v_half; varying vec3 v_normal; varying float v_transp; varying vec3 v_lighting; void main() { worldPos = instancingTransform * vec4(a_vertex, 1.0); - + v_tex.xy = a_uv0 + sim_time * translation; v_transp = a_uv1.x; calculatePositionInShadowSpace(worldPos); - v_los = worldPos.xz * losTransform.x + losTransform.y; + calculateLOSCoordinates(worldPos.xz); vec3 eyeVec = cameraPos.xyz - worldPos.xyz; - vec3 sunVec = -sunDir; - v_half = normalize(sunVec + normalize(eyeVec)); + vec3 sunVec = -sunDir; + v_half = normalize(sunVec + normalize(eyeVec)); mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); v_normal = normalMatrix * a_normal; v_lighting = max(0.0, dot(v_normal, -sunDir)) * sunColor; gl_Position = transform * worldPos; } - Index: ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.fs (revision 24732) @@ -1,40 +1,33 @@ #version 120 +#include "common/los_fragment.h" + uniform sampler2D baseTex; uniform sampler2D maskTex; -uniform sampler2D losTex; #if USE_OBJECTCOLOR uniform vec4 objectColor; #else varying vec4 v_color; #endif varying vec2 v_tex; -#if !IGNORE_LOS -varying vec2 v_los; -#endif - void main() { #if USE_OBJECTCOLOR vec3 color = objectColor.rgb; float alpha = objectColor.a; #else vec3 color = v_color.rgb; float alpha = v_color.a; #endif vec4 base = texture2D(baseTex, v_tex); vec4 mask = texture2D(maskTex, v_tex); color = mix(base.rgb, color, mask.r); -#if !IGNORE_LOS - float los = texture2D(losTex, v_los).a; - los = los < 0.03 ? 0.0 : los; - color *= los; -#endif + color *= getLOS(); gl_FragColor = vec4(color, alpha * base.a); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/overlayline.vs (revision 24732) @@ -1,31 +1,23 @@ #version 120 -#if !IGNORE_LOS -uniform vec2 losTransform; -#endif +#include "common/los_vertex.h" attribute vec3 a_vertex; attribute vec2 a_uv0; #if !USE_OBJECTCOLOR attribute vec4 a_color; varying vec4 v_color; #endif varying vec2 v_tex; -#if !IGNORE_LOS -varying vec2 v_los; -#endif - void main() { v_tex = a_uv0; -#if !IGNORE_LOS - v_los = a_vertex.xz * losTransform.x + losTransform.yy; -#endif + calculateLOSCoordinates(a_vertex.xz); #if !USE_OBJECTCOLOR v_color = a_color; #endif gl_Position = gl_ModelViewProjectionMatrix * vec4(a_vertex, 1.0); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/particle.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/particle.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/particle.fs (revision 24732) @@ -1,25 +1,21 @@ #version 110 #include "common/fog.h" +#include "common/los_fragment.h" uniform sampler2D baseTex; -uniform sampler2D losTex; varying vec2 v_tex; -varying vec2 v_los; varying vec4 v_color; uniform vec3 sunColor; void main() { vec4 color = texture2D(baseTex, v_tex) * vec4((v_color.rgb + sunColor)/2.0,v_color.a); - - float los = texture2D(losTex, v_los).a; - los = los < 0.03 ? 0.0 : los; - color.rgb *= los; color.rgb = applyFog(color.rgb); + color.rgb *= getLOS(); gl_FragColor = color; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/particle.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/particle.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/particle.vs (revision 24732) @@ -1,29 +1,30 @@ #version 110 +#include "common/los_vertex.h" + uniform mat4 transform; uniform mat4 modelViewMatrix; -uniform vec2 losTransform; varying vec2 v_tex; -varying vec2 v_los; varying vec4 v_color; attribute vec3 a_vertex; attribute vec4 a_color; attribute vec2 a_uv0; attribute vec2 a_uv1; void main() { vec3 axis1 = vec3(modelViewMatrix[0][0], modelViewMatrix[1][0], modelViewMatrix[2][0]); vec3 axis2 = vec3(modelViewMatrix[0][1], modelViewMatrix[1][1], modelViewMatrix[2][1]); vec2 offset = a_uv1; vec3 position = axis1*offset.x + axis1*offset.y + axis2*offset.x + axis2*-offset.y + a_vertex; - + gl_Position = transform * vec4(position, 1.0); - - v_los = position.xz * losTransform.x + losTransform.y; + + calculateLOSCoordinates(position.xz); + v_tex = a_uv0; v_color = a_color; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 24732) @@ -1,194 +1,191 @@ #version 120 #include "common/fog.h" +#include "common/los_fragment.h" #include "common/shadows_fragment.h" uniform sampler2D baseTex; uniform sampler2D blendTex; -uniform sampler2D losTex; uniform sampler2D normTex; uniform sampler2D specTex; uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; uniform vec2 textureTransform; varying vec3 v_lighting; -varying vec2 v_los; varying vec2 v_blend; #if USE_TRIPLANAR varying vec3 v_tex; #else varying vec2 v_tex; #endif #if USE_SPECULAR uniform float specularPower; uniform vec3 specularColor; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_AO uniform vec4 effectSettings; #endif varying vec3 v_normal; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP #if USE_NORMAL_MAP varying vec4 v_tangent; varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #endif #if USE_TRIPLANAR vec4 triplanar(sampler2D sampler, vec3 wpos) { float tighten = 0.4679; vec3 blending = abs(normalize(v_normal)) - tighten; blending = max(blending, 0.0); blending /= vec3(blending.x + blending.y + blending.z); vec3 signedBlending = sign(v_normal) * blending; vec3 coords = wpos; coords.xyz /= 32.0; // Ugh. vec4 col1 = texture2D(sampler, coords.yz); vec4 col2 = texture2D(sampler, coords.zx); vec4 col3 = texture2D(sampler, coords.yx); vec4 colBlended = col1 * blending.x + col2 * blending.y + col3 * blending.z; return colBlended; } vec4 triplanarNormals(sampler2D sampler, vec3 wpos) { float tighten = 0.4679; vec3 blending = abs(normalize(v_normal)) - tighten; blending = max(blending, 0.0); blending /= vec3(blending.x + blending.y + blending.z); vec3 signedBlending = sign(v_normal) * blending; vec3 coords = wpos; coords.xyz /= 32.0; // Ugh. vec4 col1 = texture2D(sampler, coords.yz).xyzw; col1.y = 1.0 - col1.y; vec4 col2 = texture2D(sampler, coords.zx).yxzw; col2.y = 1.0 - col2.y; vec4 col3 = texture2D(sampler, coords.yx).yxzw; col3.y = 1.0 - col3.y; vec4 colBlended = col1 * blending.x + col2 * blending.y + col3 * blending.z; return colBlended; } #endif void main() { #if BLEND // Use alpha from blend texture gl_FragColor.a = 1.0 - texture2D(blendTex, v_blend).a; #if USE_GRASS if (gl_FragColor.a < LAYER / 10.0) discard; #endif #else gl_FragColor.a = 1.0; #endif #if USE_TRIPLANAR vec4 tex = triplanar(baseTex, v_tex); #else vec4 tex = texture2D(baseTex, v_tex.xy); #endif #if USE_GRASS && LAYER if (tex.a < 0.05) discard; #endif #if DECAL // Use alpha from main texture gl_FragColor.a = tex.a; #endif vec3 texdiffuse = tex.rgb; #if USE_SPECULAR || USE_SPECULAR_MAP || USE_NORMAL_MAP vec3 normal = v_normal; #endif #if USE_NORMAL_MAP float sign = v_tangent.w; mat3 tbn = mat3(v_tangent.xyz, v_bitangent * -sign, v_normal); #if USE_TRIPLANAR vec3 ntex = triplanarNormals(normTex, v_tex).rgb * 2.0 - 1.0; #else vec3 ntex = texture2D(normTex, v_tex).rgb * 2.0 - 1.0; #endif 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; #endif vec4 specular = vec4(0.0); #if USE_SPECULAR || USE_SPECULAR_MAP vec3 specCol; float specPow; #if USE_SPECULAR_MAP #if USE_TRIPLANAR vec4 s = triplanar(specTex, v_tex); #else vec4 s = texture2D(specTex, v_tex); #endif 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() + texdiffuse * ambient; #if USE_SPECULAR_MAP && USE_SELF_LIGHT color = mix(texdiffuse, color, specular.a); #endif color = applyFog(color); - float los = texture2D(losTex, v_los).a; - los = los < 0.03 ? 0.0 : los; - color *= los; + color *= getLOS(); #if DECAL color *= shadingColor; #endif gl_FragColor.rgb = color; #if USE_GRASS gl_FragColor.a = tex.a; #endif } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.vs (revision 24732) @@ -1,106 +1,105 @@ #version 120 +#include "common/los_vertex.h" #include "common/shadows_vertex.h" uniform mat4 transform; uniform vec3 cameraPos; #ifdef GL_ES uniform mediump vec3 sunDir; uniform mediump vec3 sunColor; #else uniform vec3 sunDir; uniform vec3 sunColor; #endif uniform vec2 textureTransform; -uniform vec2 losTransform; varying vec3 v_lighting; -varying vec2 v_los; varying vec2 v_blend; #if USE_TRIPLANAR varying vec3 v_tex; #else varying vec2 v_tex; #endif varying vec3 v_normal; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP #if USE_NORMAL_MAP varying vec4 v_tangent; varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #endif attribute vec3 a_vertex; attribute vec3 a_normal; attribute vec2 a_uv0; attribute vec2 a_uv1; void main() { vec4 position = vec4(a_vertex, 1.0); #if USE_GRASS && LAYER position.y = a_vertex.y + (a_normal.y * 0.015 * LAYER); #endif gl_Position = transform * position; v_lighting = clamp(-dot(a_normal, sunDir), 0.0, 1.0) * sunColor; #if DECAL v_tex.xy = a_uv0; #else #if USE_TRIPLANAR v_tex = a_vertex; #else // Compute texcoords from position and terrain-texture-dependent transform float c = textureTransform.x; float s = -textureTransform.y; v_tex = vec2(a_vertex.x * c + a_vertex.z * -s, a_vertex.x * -s + a_vertex.z * -c); #endif #if GL_ES // XXX: Ugly hack to hide some precision issues in GLES #if USE_TRIPLANAR v_tex = mod(v_tex, vec3(9.0, 9.0, 9.0)); #else v_tex = mod(v_tex, vec2(9.0, 9.0)); #endif #endif #endif #if BLEND v_blend = a_uv1; #endif calculatePositionInShadowSpace(vec4(a_vertex, 1.0)); v_normal = a_normal; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_TRIPLANAR #if USE_NORMAL_MAP vec3 t = vec3(1.0, 0.0, 0.0); t = normalize(t - v_normal * dot(v_normal, t)); v_tangent = vec4(t, -1.0); v_bitangent = cross(v_normal, t); #endif #if USE_SPECULAR || USE_SPECULAR_MAP vec3 eyeVec = cameraPos.xyz - position.xyz; #if USE_SPECULAR || USE_SPECULAR_MAP vec3 sunVec = -sunDir; v_half = normalize(sunVec + normalize(eyeVec)); #endif #endif #endif - v_los = a_vertex.xz * losTransform.x + losTransform.yy; + calculateLOSCoordinates(a_vertex.xz); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs (revision 24732) @@ -1,335 +1,317 @@ #version 110 #include "common/fog.h" - +#include "common/los_fragment.h" #include "common/shadows_fragment.h" // Environment settings uniform vec3 ambient; uniform vec3 sunDir; uniform vec3 sunColor; uniform mat4 skyBoxRot; uniform vec3 cameraPos; -uniform sampler2D losTex; - uniform float waviness; // "Wildness" of the reflections and refractions; choose based on texture uniform vec3 color; // color of the water uniform vec3 tint; // Tint for refraction (used to simulate particles in water) uniform float murkiness; // Amount of tint to blend in with the refracted color uniform float windAngle; varying vec2 WindCosSin; uniform vec2 screenSize; varying float moddedTime; varying vec3 worldPos; varying float waterDepth; varying vec2 waterInfo; varying vec3 v_eyeVec; varying vec4 normalCoords; #if USE_REFLECTION varying vec3 reflectionCoords; #endif #if USE_REFRACTION varying vec3 refractionCoords; #endif -varying vec2 losCoords; varying float fwaviness; uniform samplerCube skyCube; uniform sampler2D normalMap; uniform sampler2D normalMap2; #if USE_FANCY_EFFECTS uniform sampler2D waterEffectsTex; #endif uniform vec4 waveParams1; // wavyEffect, BaseScale, Flattenism, Basebump uniform vec4 waveParams2; // Smallintensity, Smallbase, Bigmovement, Smallmovement #if USE_REFLECTION uniform sampler2D reflectionMap; #endif #if USE_REFRACTION uniform sampler2D refractionMap; #if USE_REAL_DEPTH uniform sampler2D depthTex; uniform mat4 projInvTransform; uniform mat4 viewInvTransform; #endif #endif -// TODO: convert this to something not only for AABBs -struct Ray { - vec3 Origin; - vec3 Direction; -}; - -float IntersectBox (in Ray ray, in vec3 minimum, in vec3 maximum) -{ - vec3 OMIN = ( minimum - ray.Origin ) / ray.Direction; - vec3 OMAX = ( maximum - ray.Origin ) / ray.Direction; - vec3 MAX = max ( OMAX, OMIN ); - return min ( MAX.x, min ( MAX.y, MAX.z ) ); -} - vec3 getNormal(vec4 fancyeffects) { float wavyEffect = waveParams1.r; float baseScale = waveParams1.g; float flattenism = waveParams1.b; float baseBump = waveParams1.a; float BigMovement = waveParams2.b; // This method uses 60 animated water frames. We're blending between each two frames // Scale the normal textures by waviness so that big waviness means bigger waves. vec3 ww1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; vec3 ww2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; vec3 wwInterp = mix(ww1, ww2, moddedTime) - vec3(0.5, 0.0, 0.5); ww1.x = wwInterp.x * WindCosSin.x - wwInterp.z * WindCosSin.y; ww1.z = wwInterp.x * WindCosSin.y + wwInterp.z * WindCosSin.x; ww1.y = wwInterp.y; // Flatten them based on waviness. vec3 normal = normalize(mix(vec3(0.0, 1.0, 0.0), ww1, clamp(baseBump + fwaviness / flattenism, 0.0, 1.0))); #if USE_FANCY_EFFECTS normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); normal.xz = mix(normal.xz, fancyeffects.rb, fancyeffects.a / 2.0); #else normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); #endif return vec3(-normal.x, normal.y, -normal.z); } vec3 getSpecular(vec3 normal, vec3 eyeVec) { // Specular lighting vectors vec3 specularVector = reflect(sunDir, normal); // pow is undefined for null or negative values, except on intel it seems. float specularIntensity = pow(max(dot(specularVector, eyeVec), 0.0), 100.0); // Workaround to fix too flattened water. specularIntensity = smoothstep(0.6, 1.0, specularIntensity) * 1.2; return clamp(specularIntensity * sunColor, 0.0, 1.0); } vec4 getReflection(vec3 normal, vec3 eyeVec) { // Reflections // 3 level of settings: // -If a player has refraction and reflection disabled, we return a gradient of blue based on the Y component. // -If a player has refraction OR reflection, we return a reflection of the actual skybox used. // -If a player has reflection enabled, we also return a reflection of actual entities where applicable. // reflMod reduces the intensity of reflections somewhat since they kind of wash refractions out otherwise. float reflMod = 0.75; vec3 eye = reflect(eyeVec, normal); #if USE_REFLECTION float refVY = clamp(eyeVec.y * 2.0, 0.05, 1.0); // Distort the reflection coords based on waves. vec2 reflCoords = (0.5 * reflectionCoords.xy - 15.0 * normal.zx / refVY) / reflectionCoords.z + 0.5; vec4 refTex = texture2D(reflectionMap, reflCoords); vec3 reflColor = refTex.rgb; // Interpolate between the sky color and nearby objects. // Only do this when alpha is rather low, or transparent leaves show up as extremely white. if (refTex.a < 0.4) reflColor = mix(textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb, refTex.rgb, refTex.a); // Let actual objects be reflected fully. reflMod = max(refTex.a, 0.75); #elif USE_REFRACTION vec3 reflColor = textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb; #else // !USE_REFLECTION && !USE_REFRACTION // Simplest case for reflection, return a gradient of blue based on Y component. vec3 reflColor = mix(vec3(0.76, 0.84, 0.92), vec3(0.24, 0.43, 0.71), -eye.y); #endif return vec4(reflColor, reflMod); } #if USE_REFRACTION && USE_REAL_DEPTH vec3 getWorldPositionFromRefractionDepth(vec2 uv) { float depth = texture2D(depthTex, uv).x; vec4 viewPosition = projInvTransform * (vec4((uv - vec2(0.5)) * 2.0, depth * 2.0 - 1.0, 1.0)); viewPosition /= viewPosition.w; vec3 refrWorldPos = (viewInvTransform * viewPosition).xyz; // Depth buffer precision errors can give heights above the water. refrWorldPos.y = min(refrWorldPos.y, worldPos.y); return refrWorldPos; } #endif vec4 getRefraction(vec3 normal, vec3 eyeVec, float depthLimit) { #if USE_REFRACTION && USE_REAL_DEPTH // Compute real depth at the target point. vec2 coords = (0.5 * refractionCoords.xy) / refractionCoords.z + 0.5; vec3 refrWorldPos = getWorldPositionFromRefractionDepth(coords); // Set depth to the depth at the undistorted point. float depth = distance(refrWorldPos, worldPos); #else // fake depth computation: take the value at the vertex, add some if we are looking at a more oblique angle. float depth = waterDepth / (min(0.5, eyeVec.y) * 1.5 * min(0.5, eyeVec.y) * 2.0); #endif #if USE_REFRACTION // for refraction we want to distort more as depth goes down. // 1) compute a distortion based on depth at the pixel. // 2) Re-sample the depth at the target point // 3) Sample refraction texture // distoFactor controls the amount of distortion relative to wave normals. float distoFactor = 0.5 + clamp(depth / 2.0, 0.0, 7.0); #if USE_REAL_DEPTH // Distort the texture coords under where the water is to simulate refraction. vec2 shiftedCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; vec3 refrWorldPos2 = getWorldPositionFromRefractionDepth(shiftedCoords); float newDepth = distance(refrWorldPos2, worldPos); // try to correct for fish. In general they'd look weirder without this fix. if (depth > newDepth + 3.0) distoFactor /= 2.0; // this in general will not fall on the fish but still look distorted. else depth = newDepth; #endif #if USE_FANCY_EFFECTS depth = max(depth, depthLimit); if (waterDepth < 0.0) depth = 0.0; #endif // Distort the texture coords under where the water is to simulate refraction. vec2 refrCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; vec3 refColor = texture2D(refractionMap, refrCoords).rgb; // Note, the refraction map is cleared using (255, 0, 0), so pixels outside of the water plane are pure red. // If we get a pure red fragment, use an undistorted/less distorted coord instead. // blur the refraction map, distoring using normal so that it looks more random than it really is // and thus looks much better. float blur = (0.1 + clamp(normal.x, -0.1, 0.1)) / refractionCoords.z; vec4 blurColor = vec4(refColor, 1.0); vec4 tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.x, blur + normal.z)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(-blur, blur + normal.z)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(-blur, -blur + normal.x)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.z, -blur)); blurColor += vec4(tex.rgb * tex.a, tex.a); blurColor /= blurColor.a; float blurFactor = (distoFactor / 7.0); refColor = (refColor + blurColor.rgb * blurFactor) / (1.0 + blurFactor); #else // !USE_REFRACTION #if USE_FANCY_EFFECTS depth = max(depth, depthLimit); #endif vec3 refColor = color; #endif // for refraction, we want to adjust the value by v.y slightly otherwise it gets too different between "from above" and "from the sides". // And it looks weird (again, we are not used to seeing water from above). float fixedVy = max(eyeVec.y, 0.01); float murky = mix(200.0, 0.1, pow(murkiness, 0.25)); // Apply water tint and murk color. float extFact = max(0.0, 1.0 - (depth * fixedVy / murky)); float ColextFact = max(0.0, 1.0 - (depth * fixedVy / murky)); vec3 colll = mix(refColor * tint, refColor, ColextFact); vec3 refrColor = mix(color, colll, extFact); float alpha = clamp(depth, 0.0, 1.0); #if !USE_REFRACTION alpha = (1.4 - extFact) * alpha; #endif return vec4(refrColor, alpha); } vec4 getFoam(vec4 fancyeffects, float shadow) { #if USE_FANCY_EFFECTS float wavyEffect = waveParams1.r; float baseScale = waveParams1.g; float BigMovement = waveParams2.b; vec3 foam1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; vec3 foam2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; vec3 foam3 = texture2D(normalMap, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; vec3 foam4 = texture2D(normalMap2, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; vec3 foaminterp = mix(foam1, foam2, moddedTime); foaminterp *= mix(foam3, foam4, moddedTime); foam1.x = abs(foaminterp.x * WindCosSin.x) + abs(foaminterp.z * WindCosSin.y); float alpha = (fancyeffects.g + pow(foam1.x * (3.0 + waviness), 2.6 - waviness / 5.5)) * 2.0; return vec4(sunColor * shadow + ambient, clamp(alpha, 0.0, 1.0)); #else return vec4(0.0); #endif } void main() { #if USE_FANCY_EFFECTS vec4 fancyeffects = texture2D(waterEffectsTex, gl_FragCoord.xy / screenSize); #else vec4 fancyeffects = vec4(0.0); #endif vec3 eyeVec = normalize(v_eyeVec); vec3 normal = getNormal(fancyeffects); vec4 refrColor = getRefraction(normal, eyeVec, fancyeffects.a); vec4 reflColor = getReflection(normal, eyeVec); // How perpendicular to the normal our view is. Used for fresnel. float ndotv = clamp(dot(normal, eyeVec), 0.0, 1.0); // Fresnel for "how much reflection vs how much refraction". float fresnel = clamp(((pow(1.1 - ndotv, 2.0)) * 1.5), 0.1, 0.75); // Approximation. I'm using 1.1 and not 1.0 because it causes artifacts, see #1714 vec3 specular = getSpecular(normal, eyeVec); #if USE_SHADOW float shadow = get_shadow(); - float fresShadow = mix(fresnel, fresnel * shadow, 0.05 + murkiness * 0.2); + float fresShadow = mix(fresnel, fresnel * shadow, 0.05 + 10.0 * murkiness * 0.2); + fresShadow = fresnel; vec3 color = mix(refrColor.rgb, reflColor.rgb, fresShadow * reflColor.a); color += shadow * specular; + //color = vec3(fresShadow); vec4 foam = getFoam(fancyeffects, shadow); #else vec3 color = mix(refrColor.rgb, reflColor.rgb, fresnel * reflColor.a); color += specular; vec4 foam = getFoam(fancyeffects, 1.0); #endif color = clamp(mix(color, foam.rgb, foam.a), 0.0, 1.0); color = applyFog(color); - float alpha = refrColor.a; - float losMod = texture2D(losTex, losCoords.st).a; - losMod = losMod < 0.03 ? 0.0 : losMod; - gl_FragColor = vec4(color * losMod, alpha); + gl_FragColor = vec4(color * getLOS(), refrColor.a); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.vs (revision 24732) @@ -1,75 +1,74 @@ #version 110 +#include "common/los_vertex.h" #include "common/shadows_vertex.h" uniform mat4 reflectionMatrix; uniform mat4 refractionMatrix; -uniform mat4 losMatrix; uniform float repeatScale; uniform float windAngle; // "Wildness" of the reflections and refractions; choose based on texture uniform float waviness; uniform vec3 sunDir; uniform float time; uniform mat4 transform; uniform vec3 cameraPos; varying float moddedTime; varying vec3 worldPos; varying float waterDepth; varying vec2 waterInfo; varying vec3 v_eyeVec; varying vec4 normalCoords; #if USE_REFLECTION varying vec3 reflectionCoords; #endif #if USE_REFRACTION varying vec3 refractionCoords; #endif -varying vec2 losCoords; varying float fwaviness; varying vec2 WindCosSin; attribute vec3 a_vertex; attribute vec2 a_waterInfo; attribute vec3 a_otherPosition; void main() { worldPos = a_vertex; waterInfo = a_waterInfo; waterDepth = a_waterInfo.g; WindCosSin = vec2(cos(-windAngle), sin(-windAngle)); float newX = a_vertex.x * WindCosSin.x - a_vertex.z * WindCosSin.y; float newY = a_vertex.x * WindCosSin.y + a_vertex.z * WindCosSin.x; normalCoords = vec4(newX, newY, time, 0.0); normalCoords.xy *= repeatScale; // Projective texturing #if USE_REFLECTION reflectionCoords = (reflectionMatrix * vec4(a_vertex, 1.0)).rga; #endif #if USE_REFRACTION refractionCoords = (refractionMatrix * vec4(a_vertex, 1.0)).rga; #endif - losCoords = (losMatrix * vec4(a_vertex, 1.0)).rg; + calculateLOSCoordinates(a_vertex.xz); calculatePositionInShadowSpace(vec4(a_vertex, 1.0)); v_eyeVec = normalize(cameraPos - worldPos); moddedTime = mod(time * 60.0, 8.0) / 8.0; // Fix the waviness for local wind strength fwaviness = waviness * (0.15 + a_waterInfo.r / 1.15); gl_Position = transform * vec4(a_vertex, 1.0); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/water_simple.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/water_simple.fs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/water_simple.fs (revision 24732) @@ -1,15 +1,13 @@ #version 110 +#include "common/los_fragment.h" + uniform sampler2D baseTex; -uniform sampler2D losTex; uniform vec3 color; varying vec2 v_coords; -varying vec2 v_losCoords; void main() { - float losMod = texture2D(losTex, v_losCoords.st).a; - losMod = losMod < 0.03 ? 0.0 : losMod; - gl_FragColor = vec4(texture2D(baseTex, v_coords).rgb * color * losMod, 1.0); + gl_FragColor = vec4(texture2D(baseTex, v_coords).rgb * color * getLOS(), 1.0); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/water_simple.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/water_simple.vs (revision 24731) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/water_simple.vs (revision 24732) @@ -1,22 +1,22 @@ #version 110 +#include "common/los_vertex.h" + attribute vec3 a_vertex; uniform mat4 transform; -uniform mat4 losMatrix; uniform float time; varying vec2 v_coords; -varying vec2 v_losCoords; void main() { // Shift the texture coordinates by these amounts to make the water "flow" float tx = -mod(time, 81.0) / 81.0; float tz = -mod(time, 34.0) / 34.0; float repeatPeriod = 16.0; v_coords = a_vertex.xz / repeatPeriod + vec2(tx, tz); - v_losCoords = (losMatrix * vec4(a_vertex, 1.0)).rg; + calculateLOSCoordinates(a_vertex.xz); gl_Position = transform * vec4(a_vertex, 1.0); } Index: ps/trunk/source/ps/CStrInternStatic.h =================================================================== --- ps/trunk/source/ps/CStrInternStatic.h (revision 24731) +++ ps/trunk/source/ps/CStrInternStatic.h (revision 24732) @@ -1,166 +1,165 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ // This file defines global CStrIntern variables, to avoid the cost of // constructing CStrInterns frequently at runtime. // // A line like // X(foo) // defines a variable str_foo with value "foo". // // A line like // X2(foo_0, "foo[0]") // defines a variable str_foo_0 with value "foo[0]". X(0) X(1) X(2) X(ALPHABLEND_PASS_BLEND) X(ALPHABLEND_PASS_OPAQUE) X(BLEND) X(BLOOM_NOP) X(BLOOM_PASS_H) X(BLOOM_PASS_V) X(DECAL) X(DISABLE_RECEIVE_SHADOWS) X(IGNORE_LOS) X(MINIMAP_BASE) X(MINIMAP_LINE) X(MINIMAP_LOS) X(MINIMAP_MASK) X(MINIMAP_POINT) X(MODE_SHADOWCAST) X(MODE_SILHOUETTEDISPLAY) X(MODE_SILHOUETTEOCCLUDER) X(MODE_WIREFRAME) X(SYS_HAS_ARB) X(SYS_HAS_GLSL) X(SYS_PREFER_GLSL) X(USE_FANCY_EFFECTS) X(USE_FP_SHADOW) X(USE_GPU_SKINNING) X(USE_INSTANCING) X(USE_NORMALS) X(USE_OBJECTCOLOR) X(USE_REAL_DEPTH) X(USE_REFLECTION) X(USE_REFRACTION) X(USE_SHADOW) X(USE_SHADOW_PCF) X(USE_SHADOW_SAMPLER) X(USE_FOG) X(WATERTYPE_CLAP) X(WATERTYPE_LAKE) X2(_emptystring, "") X(a_apexPosition) X(a_otherPosition) X(a_retreatPosition) X(a_skinJoints) X(a_skinWeights) X(a_splashPosition) X(a_tangent) X(a_waterInfo) X(ambient) X(baseTex) X(blendTex) X(bloom) X(blurTex2) X(blurTex4) X(blurTex8) X(brightness) X(cameraPos) X(color) X(colorAdd) X(colorMul) X(debug_overlay) X(delta) X(depthTex) X(foamTex) X(fogColor) X(fogParams) X(foreground_overlay) X(gui_add) X(gui_basic) X(gui_grayscale) X(gui_solid) X(gui_solid_mask) X(gui_text) X(hdr) X(height) X(instancingTransform) -X(losMatrix) X(losTex) X(losTex1) X(losTex2) X(losTransform) X(los_interp) X(mapSize) X(maskTex) X(maskTextureTransform) X(minimap) X(modelViewMatrix) X(murkiness) X(normalMap) X(normalMap2) X(objectColor) X(overlay_solid) X(particle) X(particle_solid) X(playerColor) X(pointSize) X(projInvTransform) X(qualityLevel) X(reflectionMap) X(reflectionMatrix) X(refractionMap) X(refractionMatrix) X(renderedTex) X(repeatScale) X2(sans_10, "sans-10"); X(saturation) X(screenSize) X(shadingColor) X(shadowScale) X(shadowTex) X(shadowTransform) X(sharpness) X(skinBlendMatrices) X2(skinBlendMatrices_0, "skinBlendMatrices[0]") X(skyBoxRot) X(skyCube) X(sky_simple) X(sunColor) X(sunDir) X(tex) X(texSize) X(textureTransform) X(time) X(tint) X(transform) X(translation) X(viewInvTransform) X(water_simple) X(waterEffectsTex) X(waterTex) X(waveTex) X(waviness) X(waveParams1) X(waveParams2) X(width) X(windAngle) X(zFar) X(zNear) Index: ps/trunk/source/renderer/TerrainRenderer.cpp =================================================================== --- ps/trunk/source/renderer/TerrainRenderer.cpp (revision 24731) +++ ps/trunk/source/renderer/TerrainRenderer.cpp (revision 24732) @@ -1,696 +1,696 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /* * Terrain rendering (everything related to patches and water) is * encapsulated in TerrainRenderer */ #include "precompiled.h" #include "graphics/Camera.h" #include "graphics/Decal.h" #include "graphics/LightEnv.h" #include "graphics/LOSTexture.h" #include "graphics/Patch.h" #include "graphics/GameView.h" #include "graphics/Model.h" #include "graphics/ShaderManager.h" #include "renderer/ShadowMap.h" #include "renderer/SkyManager.h" #include "graphics/TerritoryTexture.h" #include "graphics/TextRenderer.h" #include "maths/MathUtil.h" #include "ps/Filesystem.h" #include "ps/CLogger.h" #include "ps/Game.h" #include "ps/Profile.h" #include "ps/World.h" #include "renderer/DecalRData.h" #include "renderer/PatchRData.h" #include "renderer/Renderer.h" #include "renderer/RenderingOptions.h" #include "renderer/ShadowMap.h" #include "renderer/TerrainRenderer.h" #include "renderer/VertexArray.h" #include "renderer/WaterManager.h" #include "tools/atlas/GameInterface/GameLoop.h" extern GameLoopState* g_AtlasGameLoop; /////////////////////////////////////////////////////////////////////////////////////////////// // TerrainRenderer implementation namespace { CShaderProgramPtr GetDummyShader() { const char* shaderName; if (g_RenderingOptions.GetPreferGLSL()) shaderName = "glsl/dummy"; else shaderName = "arb/dummy"; return g_Renderer.GetShaderManager().LoadProgram(shaderName, CShaderDefines()); } } // anonymous namespace /** * TerrainRenderer keeps track of which phase it is in, to detect * when Submit, PrepareForRendering etc. are called in the wrong order. */ enum Phase { Phase_Submit, Phase_Render }; /** * Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class. */ struct TerrainRendererInternals { /// Which phase (submitting or rendering patches) are we in right now? Phase phase; /// Patches that were submitted for this frame std::vector visiblePatches[CRenderer::CULL_MAX]; /// Decals that were submitted for this frame std::vector visibleDecals[CRenderer::CULL_MAX]; /// Fancy water shader CShaderProgramPtr fancyWaterShader; CSimulation2* simulation; }; /////////////////////////////////////////////////////////////////// // Construction/Destruction TerrainRenderer::TerrainRenderer() { m = new TerrainRendererInternals(); m->phase = Phase_Submit; } TerrainRenderer::~TerrainRenderer() { delete m; } void TerrainRenderer::SetSimulation(CSimulation2* simulation) { m->simulation = simulation; } /////////////////////////////////////////////////////////////////// // Submit a patch for rendering void TerrainRenderer::Submit(int cullGroup, CPatch* patch) { ENSURE(m->phase == Phase_Submit); CPatchRData* data = (CPatchRData*)patch->GetRenderData(); if (data == 0) { // no renderdata for patch, create it now data = new CPatchRData(patch, m->simulation); patch->SetRenderData(data); } data->Update(m->simulation); m->visiblePatches[cullGroup].push_back(data); } /////////////////////////////////////////////////////////////////// // Submit a decal for rendering void TerrainRenderer::Submit(int cullGroup, CModelDecal* decal) { ENSURE(m->phase == Phase_Submit); CDecalRData* data = (CDecalRData*)decal->GetRenderData(); if (data == 0) { // no renderdata for decal, create it now data = new CDecalRData(decal, m->simulation); decal->SetRenderData(data); } data->Update(m->simulation); m->visibleDecals[cullGroup].push_back(data); } /////////////////////////////////////////////////////////////////// // Prepare for rendering void TerrainRenderer::PrepareForRendering() { ENSURE(m->phase == Phase_Submit); m->phase = Phase_Render; } /////////////////////////////////////////////////////////////////// // Clear submissions lists void TerrainRenderer::EndFrame() { ENSURE(m->phase == Phase_Render || m->phase == Phase_Submit); for (int i = 0; i < CRenderer::CULL_MAX; ++i) { m->visiblePatches[i].clear(); m->visibleDecals[i].clear(); } m->phase = Phase_Submit; } void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix, GLuint texture) { #if CONFIG2_GLES #warning TODO: implement TerrainRenderer::RenderTerrainOverlayTexture for GLES UNUSED2(cullGroup); UNUSED2(textureMatrix); UNUSED2(texture); #else ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(0); glDisable(GL_DEPTH_TEST); CShaderTechniquePtr debugOverlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_overlay); debugOverlayTech->BeginPass(); CShaderProgramPtr debugOverlayShader = debugOverlayTech->GetShader(); debugOverlayShader->Bind(); debugOverlayShader->BindTexture(str_baseTex, texture); debugOverlayShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); debugOverlayShader->Uniform(str_textureTransform, textureMatrix); CPatchRData::RenderStreams(visiblePatches, debugOverlayShader, STREAM_POS | STREAM_POSTOUV0); glEnable(GL_DEPTH_TEST); // To make the overlay visible over water, render an additional map-sized // water-height patch. CBoundingBoxAligned waterBounds; for (CPatchRData* data : visiblePatches) waterBounds += data->GetWaterBounds(); if (!waterBounds.IsEmpty()) { // Add a delta to avoid z-fighting. const float height = g_Renderer.GetWaterManager()->m_WaterHeight + 0.05f; const float waterPos[] = { waterBounds[0].X, height, waterBounds[0].Z, waterBounds[1].X, height, waterBounds[0].Z, waterBounds[0].X, height, waterBounds[1].Z, waterBounds[1].X, height, waterBounds[1].Z }; const GLsizei stride = sizeof(float) * 3; debugOverlayShader->VertexPointer(3, GL_FLOAT, stride, waterPos); debugOverlayShader->TexCoordPointer(GL_TEXTURE0, 3, GL_FLOAT, stride, waterPos); debugOverlayShader->AssertPointersBound(); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } debugOverlayShader->Unbind(); debugOverlayTech->EndPass(); glDepthMask(1); glDisable(GL_BLEND); #endif } /////////////////////////////////////////////////////////////////// /** * Set up all the uniforms for a shader pass. */ void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow) { shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); shader->Uniform(str_cameraPos, g_Renderer.GetViewCamera().GetOrientation().GetTranslation()); const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); if (shadow) shadow->BindTo(shader); CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture(); shader->BindTexture(str_losTex, los.GetTextureSmooth()); shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); shader->Uniform(str_ambient, lightEnv.m_AmbientColor); shader->Uniform(str_sunColor, lightEnv.m_SunColor); shader->Uniform(str_sunDir, lightEnv.GetSunDir()); shader->Uniform(str_fogColor, lightEnv.m_FogColor); shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); } void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; std::vector& visibleDecals = m->visibleDecals[cullGroup]; if (visiblePatches.empty() && visibleDecals.empty()) return; // render the solid black sides of the map first CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid); techSolid->BeginPass(); CShaderProgramPtr shaderSolid = techSolid->GetShader(); shaderSolid->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f); PROFILE_START("render terrain sides"); for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderSides(shaderSolid); PROFILE_END("render terrain sides"); techSolid->EndPass(); PROFILE_START("render terrain base"); CPatchRData::RenderBases(visiblePatches, context, shadow); PROFILE_END("render terrain base"); // no need to write to the depth buffer a second time glDepthMask(0); // render blend passes for each patch PROFILE_START("render terrain blends"); CPatchRData::RenderBlends(visiblePatches, context, shadow, false); PROFILE_END("render terrain blends"); PROFILE_START("render terrain decals"); CDecalRData::RenderDecals(visibleDecals, context, shadow, false); PROFILE_END("render terrain decals"); // restore OpenGL state g_Renderer.BindTexture(1, 0); g_Renderer.BindTexture(2, 0); g_Renderer.BindTexture(3, 0); glDepthMask(1); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); } /////////////////////////////////////////////////////////////////// // Render un-textured patches as polygons void TerrainRenderer::RenderPatches(int cullGroup, const CColor& color) { ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; if (visiblePatches.empty()) return; #if CONFIG2_GLES #warning TODO: implement TerrainRenderer::RenderPatches for GLES #else CShaderProgramPtr dummyShader = GetDummyShader(); dummyShader->Bind(); dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); dummyShader->Uniform(str_color, color); glEnableClientState(GL_VERTEX_ARRAY); CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS); glDisableClientState(GL_VERTEX_ARRAY); dummyShader->Unbind(); #endif } /////////////////////////////////////////////////////////////////// // Render outlines of submitted patches as lines void TerrainRenderer::RenderOutlines(int cullGroup) { ENSURE(m->phase == Phase_Render); std::vector& visiblePatches = m->visiblePatches[cullGroup]; if (visiblePatches.empty()) return; #if CONFIG2_GLES #warning TODO: implement TerrainRenderer::RenderOutlines for GLES #else glEnableClientState(GL_VERTEX_ARRAY); for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderOutline(); glDisableClientState(GL_VERTEX_ARRAY); #endif } /////////////////////////////////////////////////////////////////// // Scissor rectangle of water patches CBoundingBoxAligned TerrainRenderer::ScissorWater(int cullGroup, const CMatrix3D &viewproj) { std::vector& visiblePatches = m->visiblePatches[cullGroup]; CBoundingBoxAligned scissor; for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; const CBoundingBoxAligned& waterBounds = data->GetWaterBounds(); if (waterBounds.IsEmpty()) continue; CVector4D v1 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f)); CVector4D v2 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f)); CVector4D v3 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f)); CVector4D v4 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f)); CBoundingBoxAligned screenBounds; #define ADDBOUND(v1, v2, v3, v4) \ if (v1.Z >= -v1.W) \ screenBounds += CVector3D(v1.X, v1.Y, v1.Z) * (1.0f / v1.W); \ else \ { \ float t = v1.Z + v1.W; \ if (v2.Z > -v2.W) \ { \ CVector4D c2 = v1 + (v2 - v1) * (t / (t - (v2.Z + v2.W))); \ screenBounds += CVector3D(c2.X, c2.Y, c2.Z) * (1.0f / c2.W); \ } \ if (v3.Z > -v3.W) \ { \ CVector4D c3 = v1 + (v3 - v1) * (t / (t - (v3.Z + v3.W))); \ screenBounds += CVector3D(c3.X, c3.Y, c3.Z) * (1.0f / c3.W); \ } \ if (v4.Z > -v4.W) \ { \ CVector4D c4 = v1 + (v4 - v1) * (t / (t - (v4.Z + v4.W))); \ screenBounds += CVector3D(c4.X, c4.Y, c4.Z) * (1.0f / c4.W); \ } \ } ADDBOUND(v1, v2, v3, v4); ADDBOUND(v2, v1, v3, v4); ADDBOUND(v3, v1, v2, v4); ADDBOUND(v4, v1, v2, v3); #undef ADDBOUND if (screenBounds[0].X >= 1.0f || screenBounds[1].X <= -1.0f || screenBounds[0].Y >= 1.0f || screenBounds[1].Y <= -1.0f) continue; scissor += screenBounds; } return CBoundingBoxAligned(CVector3D(Clamp(scissor[0].X, -1.0f, 1.0f), Clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f), CVector3D(Clamp(scissor[1].X, -1.0f, 1.0f), Clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f)); } // Render fancy water bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { PROFILE3_GPU("fancy water"); WaterManager* WaterMgr = g_Renderer.GetWaterManager(); CShaderDefines defines = context; // If we're using fancy water, make sure its shader is loaded if (!m->fancyWaterShader || WaterMgr->m_NeedsReloading) { if (WaterMgr->m_WaterRealDepth) defines.Add(str_USE_REAL_DEPTH, str_1); if (WaterMgr->m_WaterFancyEffects) defines.Add(str_USE_FANCY_EFFECTS, str_1); if (WaterMgr->m_WaterRefraction) defines.Add(str_USE_REFRACTION, str_1); if (WaterMgr->m_WaterReflection) defines.Add(str_USE_REFLECTION, str_1); // haven't updated the ARB shader yet so I'll always load the GLSL /*if (!g_RenderingOptions.GetPreferGLSL() && !superFancy) m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("arb/water_high", defines); else*/ m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("glsl/water_high", defines); if (!m->fancyWaterShader) { LOGERROR("Failed to load water shader. Falling back to fixed pipeline water.\n"); WaterMgr->m_RenderWater = false; return false; } WaterMgr->m_NeedsReloading = false; } CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture(); // Calculating the advanced informations about Foam and all if the quality calls for it. /*if (WaterMgr->m_NeedInfoUpdate && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)) { WaterMgr->m_NeedInfoUpdate = false; WaterMgr->CreateSuperfancyInfo(); }*/ double time = WaterMgr->m_WaterTexTimer; double period = 8; int curTex = (int)(time*60/period) % 60; int nexTex = (curTex + 1) % 60; float repeatPeriod = WaterMgr->m_RepeatPeriod; // Render normals and foam to a framebuffer if we're in fancy effects if (WaterMgr->m_WaterFancyEffects) { // Save the post-processing framebuffer. GLint fbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo); pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, WaterMgr->m_FancyEffectsFBO); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glDisable(GL_CULL_FACE); // Overwrite waves that would be behind the ground. CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("glsl/gui_solid", CShaderDefines()); dummyShader->Bind(); dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; data->RenderWater(dummyShader, true, true); } dummyShader->Unbind(); glEnable(GL_CULL_FACE); pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); m->fancyWaterShader->Bind(); const CCamera& camera = g_Renderer.GetViewCamera(); m->fancyWaterShader->BindTexture(str_normalMap, WaterMgr->m_NormalMap[curTex]); m->fancyWaterShader->BindTexture(str_normalMap2, WaterMgr->m_NormalMap[nexTex]); if (WaterMgr->m_WaterFancyEffects) { m->fancyWaterShader->BindTexture(str_waterEffectsTex, WaterMgr->m_FancyTexture); } if (WaterMgr->m_WaterRefraction && WaterMgr->m_WaterRealDepth) { m->fancyWaterShader->BindTexture(str_depthTex, WaterMgr->m_RefrFboDepthTexture); m->fancyWaterShader->Uniform(str_projInvTransform, WaterMgr->m_RefractionProjInvMatrix); m->fancyWaterShader->Uniform(str_viewInvTransform, WaterMgr->m_RefractionViewInvMatrix); } if (WaterMgr->m_WaterRefraction) m->fancyWaterShader->BindTexture(str_refractionMap, WaterMgr->m_RefractionTexture); if (WaterMgr->m_WaterReflection) m->fancyWaterShader->BindTexture(str_reflectionMap, WaterMgr->m_ReflectionTexture); m->fancyWaterShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); m->fancyWaterShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); //TODO: bind only what's needed if (WaterMgr->m_WaterRefraction || WaterMgr->m_WaterReflection) { m->fancyWaterShader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube()); // TODO: check that this rotates in the right direction. CMatrix3D skyBoxRotation; skyBoxRotation.SetIdentity(); skyBoxRotation.RotateY(M_PI + lightEnv.GetRotation()); m->fancyWaterShader->Uniform(str_skyBoxRot, skyBoxRotation); if (WaterMgr->m_WaterRefraction) m->fancyWaterShader->Uniform(str_refractionMatrix, WaterMgr->m_RefractionMatrix); if (WaterMgr->m_WaterReflection) m->fancyWaterShader->Uniform(str_reflectionMatrix, WaterMgr->m_ReflectionMatrix); } m->fancyWaterShader->Uniform(str_ambient, lightEnv.m_AmbientColor); m->fancyWaterShader->Uniform(str_sunDir, lightEnv.GetSunDir()); m->fancyWaterShader->Uniform(str_sunColor, lightEnv.m_SunColor); m->fancyWaterShader->Uniform(str_color, WaterMgr->m_WaterColor); m->fancyWaterShader->Uniform(str_tint, WaterMgr->m_WaterTint); m->fancyWaterShader->Uniform(str_waviness, WaterMgr->m_Waviness); m->fancyWaterShader->Uniform(str_murkiness, WaterMgr->m_Murkiness); m->fancyWaterShader->Uniform(str_windAngle, WaterMgr->m_WindAngle); m->fancyWaterShader->Uniform(str_repeatScale, 1.0f / repeatPeriod); - m->fancyWaterShader->Uniform(str_losMatrix, losTexture.GetTextureMatrix()); + m->fancyWaterShader->Uniform(str_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f); m->fancyWaterShader->Uniform(str_cameraPos, camera.GetOrientation().GetTranslation()); m->fancyWaterShader->Uniform(str_fogColor, lightEnv.m_FogColor); m->fancyWaterShader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); m->fancyWaterShader->Uniform(str_time, (float)time); m->fancyWaterShader->Uniform(str_screenSize, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0.0f, 0.0f); if (WaterMgr->m_WaterType == L"clap") { m->fancyWaterShader->Uniform(str_waveParams1, 30.0f,1.5f,20.0f,0.03f); m->fancyWaterShader->Uniform(str_waveParams2, 0.5f,0.0f,0.0f,0.0f); } else if (WaterMgr->m_WaterType == L"lake") { m->fancyWaterShader->Uniform(str_waveParams1, 8.5f,1.5f,15.0f,0.03f); m->fancyWaterShader->Uniform(str_waveParams2, 0.2f,0.0f,0.0f,0.07f); } else { m->fancyWaterShader->Uniform(str_waveParams1, 15.0f,0.8f,10.0f,0.1f); m->fancyWaterShader->Uniform(str_waveParams2, 0.3f,0.0f,0.1f,0.3f); } if (shadow) shadow->BindTo(m->fancyWaterShader); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; data->RenderWater(m->fancyWaterShader); } m->fancyWaterShader->Unbind(); glDepthFunc(GL_LEQUAL); glDisable(GL_BLEND); return true; } void TerrainRenderer::RenderSimpleWater(int cullGroup) { #if CONFIG2_GLES UNUSED2(cullGroup); #else PROFILE3_GPU("simple water"); WaterManager* WaterMgr = g_Renderer.GetWaterManager(); CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); double time = WaterMgr->m_WaterTexTimer; double period = 1.6f; int curTex = (int)(time*60/period) % 60; CShaderTechniquePtr waterSimpleTech = g_Renderer.GetShaderManager().LoadEffect(str_water_simple); waterSimpleTech->BeginPass(); CShaderProgramPtr waterSimpleShader = waterSimpleTech->GetShader(); waterSimpleShader->Bind(); waterSimpleShader->BindTexture(str_baseTex, WaterMgr->m_WaterTexture[curTex]); waterSimpleShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); waterSimpleShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection()); - waterSimpleShader->Uniform(str_losMatrix, losTexture.GetTextureMatrix()); + waterSimpleShader->Uniform(str_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f); waterSimpleShader->Uniform(str_time, static_cast(time)); waterSimpleShader->Uniform(str_color, WaterMgr->m_WaterColor); glEnableClientState(GL_VERTEX_ARRAY); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; data->RenderWater(waterSimpleShader, false, true); } glDisableClientState(GL_VERTEX_ARRAY); waterSimpleShader->Unbind(); g_Renderer.BindTexture(1, 0); pglActiveTextureARB(GL_TEXTURE0_ARB); glDisable(GL_TEXTURE_2D); waterSimpleTech->EndPass(); #endif } /////////////////////////////////////////////////////////////////// // Render water that is part of the terrain void TerrainRenderer::RenderWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow) { WaterManager* WaterMgr = g_Renderer.GetWaterManager(); WaterMgr->UpdateQuality(); if (!WaterMgr->WillRenderFancyWater()) RenderSimpleWater(cullGroup); else RenderFancyWater(context, cullGroup, shadow); } void TerrainRenderer::RenderPriorities(int cullGroup) { PROFILE("priorities"); ENSURE(m->phase == Phase_Render); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text); tech->BeginPass(); CTextRenderer textRenderer(tech->GetShader()); textRenderer.Font(CStrIntern("mono-stroke-10")); textRenderer.Color(1.0f, 1.0f, 0.0f); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) visiblePatches[i]->RenderPriorities(textRenderer); textRenderer.Render(); tech->EndPass(); }