1
0
forked from 0ad/0ad

Updates the water settings: features can now be enabled individually for more modularity. Fixes a few bugs. Allows it to be run at an acceptable speed in Atlas.

This was SVN commit r12817.
This commit is contained in:
wraitii 2012-11-04 15:54:36 +00:00
parent 7848f4edef
commit ed7c66eb82
15 changed files with 659 additions and 369 deletions

View File

@ -41,8 +41,15 @@ bpp = 0
; System settings:
fancywater = true
superfancywater = false
waternormals = true
waterbinormals = true
waterrealdepth = true
waterfoam = false
watercoastalwaves = false
waterrefraction = true
waterreflection = true
watershadows = false
shadows = true
shadowpcf = true
vsync = false

View File

@ -23,7 +23,7 @@
Game Options
</object>
<object size="50%-190 50%-80 50%+140 50%+120">
<object size="50%-190 50%-80 50%+140 50%+95">
<!-- Settings / shadows -->
<object size="0 10 100%-80 35" type="text" style="RightLabelText" ghost="true">Enable Shadows</object>
@ -40,15 +40,15 @@
</object>
<!-- Settings / Water -->
<object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Enable Water Reflections</object>
<!-- <object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Enable Water Reflections</object>
<object name="fancyWaterCheckbox" size="100%-56 65 100%-30 90" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.fancyWater) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.fancyWater = this.checked;</action>
</object>
</object>-->
<!-- Settings / Music-->
<object size="0 85 100%-80 110" type="text" style="RightLabelText" ghost="true">Enable Music</object>
<object size="100%-56 90 100%-30 115" type="checkbox" style="StoneCrossBox" checked="true">
<object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Enable Music</object>
<object size="100%-56 65 100%-30 90" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Press">if (this.checked) startMusic(); else stopMusic();</action>
</object>

View File

@ -300,7 +300,7 @@
<object name="settingsDialogPanel"
style="StoneDialog"
type="image"
size="50%-180 50%-200 50%+180 50%+125"
size="50%-180 50%-225 50%+180 50%+250"
hidden="true"
>
<object type="text" style="TitleText" size="50%-96 -16 50%+96 16">Settings</object>
@ -323,43 +323,85 @@
<action on="Press">renderer.shadowPCF = this.checked;</action>
</object>
<!-- Settings / Water -->
<object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Enable Water Reflections</object>
<object name="fancyWaterCheckbox" size="100%-56 65 100%-30 90" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.fancyWater) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.fancyWater = this.checked; </action>
<!-- Settings / Water Normals -->
<object size="0 60 100%-80 85" type="text" style="RightLabelText" ghost="true">Water - 3D Waviness</object>
<object name="waterNormalCheckox" size="100%-56 65 100%-30 90" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.waternormal) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.waternormal = this.checked;</action>
</object>
<!-- Settings / Advanced Water -->
<object size="0 85 100%-80 110" type="text" style="RightLabelText" ghost="true">Enable Advanced Water</object>
<object name="superFancyWaterCheckbox" size="100%-56 90 100%-30 115" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.superFancyWater) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.superFancyWater = this.checked; </action>
<!-- Settings / Water Binormals -->
<object size="0 85 100%-80 110" type="text" style="RightLabelText" ghost="true">Water - HQ Waviness</object>
<object name="waterBinormalCheckox" size="100%-56 90 100%-30 115" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.waterbinormal) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.waterbinormal = this.checked;</action>
</object>
<!-- Settings / Real Depth -->
<object size="0 110 100%-80 135" type="text" style="RightLabelText" ghost="true">Water - Use Actual Depth</object>
<object name="waterRealDepthCheckbox" size="100%-56 115 100%-30 140" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.waterrealdepth) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.waterrealdepth = this.checked; </action>
</object>
<!-- Settings / Reflection -->
<object size="0 135 100%-80 160" type="text" style="RightLabelText" ghost="true">Water - Enable Reflections</object>
<object name="waterReflectionCheckbox" size="100%-56 140 100%-30 165" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.waterreflection) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.waterreflection = this.checked; </action>
</object>
<!-- Settings / Refraction -->
<object size="0 160 100%-80 185" type="text" style="RightLabelText" ghost="true">Water - Enable Refraction</object>
<object name="waterRefractionCheckbox" size="100%-56 165 100%-30 190" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.waterrefraction) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.waterrefraction = this.checked; </action>
</object>
<!-- Settings / Foam -->
<object size="0 185 100%-80 210" type="text" style="RightLabelText" ghost="true">Water - Enable Shore Foam</object>
<object name="waterFoamCheckbox" size="100%-56 190 100%-30 215" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.waterfoam) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.waterfoam = this.checked; </action>
</object>
<!-- Settings / Waves -->
<object size="0 210 100%-80 235" type="text" style="RightLabelText" ghost="true">Water - Enable Shore Waves</object>
<object name="waterCoastalWavesCheckbox" size="100%-56 215 100%-30 240" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.watercoastalwaves) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.watercoastalwaves = this.checked; </action>
</object>
<!-- Settings / Shadows -->
<object size="0 235 100%-80 260" type="text" style="RightLabelText" ghost="true">Water - Use Surface Shadows</object>
<object name="waterShadowsCheckbox" size="100%-56 240 100%-30 265" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.watershadow) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.watershadow = this.checked; </action>
</object>
<!-- Settings / Particles -->
<object size="0 110 100%-80 135" type="text" style="RightLabelText" ghost="true">Enable Particles</object>
<object name="particlesCheckbox" size="100%-56 115 100%-30 140" type="checkbox" style="StoneCrossBox" checked="true">
<object size="0 260 100%-80 285" type="text" style="RightLabelText" ghost="true">Enable Particles</object>
<object name="particlesCheckbox" size="100%-56 265 100%-30 290" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.particles) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.particles = this.checked;</action>
</object>
<!-- Settings / Unit Silhouettes -->
<object size="0 135 100%-80 160" type="text" style="RightLabelText" ghost="true">Enable Unit Silhouettes</object>
<object name="silhouettesCheckbox" size="100%-56 140 100%-30 165" type="checkbox" style="StoneCrossBox" checked="true">
<object size="0 285 100%-80 310" type="text" style="RightLabelText" ghost="true">Enable Unit Silhouettes</object>
<object name="silhouettesCheckbox" size="100%-56 290 100%-30 315" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Load">if (renderer.silhouettes) this.checked = true; else this.checked = false;</action>
<action on="Press">renderer.silhouettes = this.checked;</action>
</object>
<!-- Settings / Music-->
<object size="0 160 100%-80 185" type="text" style="RightLabelText" ghost="true">Enable Music</object>
<object size="100%-56 165 100%-30 190" type="checkbox" style="StoneCrossBox" checked="true">
<object size="0 310 100%-80 335" type="text" style="RightLabelText" ghost="true">Enable Music</object>
<object size="100%-56 315 100%-30 340" type="checkbox" style="StoneCrossBox" checked="true">
<action on="Press">if (this.checked) global.music.start(); else global.music.stop();</action>
</object>
<!-- Settings / Dev Overlay -->
<object size="0 185 100%-80 210" type="text" style="RightLabelText" ghost="true">Developer Overlay</object>
<object size="100%-56 190 100%-30 215" type="checkbox" style="StoneCrossBox" checked="false">
<object size="0 335 100%-80 360" type="text" style="RightLabelText" ghost="true">Developer Overlay</object>
<object size="100%-56 340 100%-30 365" type="checkbox" style="StoneCrossBox" checked="false">
<action on="Press">toggleDeveloperOverlay();</action>
</object>
</object>

View File

@ -4,9 +4,6 @@ uniform vec3 ambient;
uniform vec3 sunDir;
uniform vec3 sunColor;
uniform vec3 cameraPos;
uniform sampler2D normalMap;
uniform sampler2D reflectionMap;
uniform sampler2D refractionMap;
uniform sampler2D losMap;
uniform float shininess; // Blinn-Phong specular strength
uniform float specularStrength; // Scaling for specular reflection (specular color is (this,this,this))
@ -23,57 +20,64 @@ uniform vec2 fogParams;
uniform vec2 screenSize;
uniform float time;
#if USE_SUPERFANCYWATER
uniform sampler2D heightmap;
uniform sampler2D infoTex;
uniform sampler2D normalMap2;
uniform sampler2D Foam;
uniform sampler2D depthTex;
uniform sampler2D waveTex;
#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
#endif
varying vec3 worldPos;
varying float waterDepth;
#if USE_SUPERFANCYWATER
float get_shadow(vec4 coords)
{
#if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS
#if USE_SHADOW_SAMPLER
#if USE_SHADOW_PCF
vec2 offset = fract(coords.xy - 0.5);
vec4 size = vec4(offset + 1.0, 2.0 - offset);
vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (coords.xy - offset).xyxy) * shadowScale.zwzw;
return (1.0/9.0)*dot(size.zxzx*size.wwyy,
vec4(shadow2D(shadowTex, vec3(weight.zw, coords.z)).r,
shadow2D(shadowTex, vec3(weight.xw, coords.z)).r,
shadow2D(shadowTex, vec3(weight.zy, coords.z)).r,
shadow2D(shadowTex, vec3(weight.xy, coords.z)).r));
#else
return shadow2D(shadowTex, coords.xyz).r;
#endif
#else
if (coords.z >= 1.0)
return 1.0;
return (coords.z <= texture2D(shadowTex, coords.xy).x ? 1.0 : 0.0);
uniform sampler2D normalMap;
#if USE_BINORMALS
uniform sampler2D normalMap2;
#endif
#if USE_REFLECTION
uniform sampler2D reflectionMap;
#endif
#if USE_REFRACTION
uniform sampler2D refractionMap;
#endif
#if USE_REAL_DEPTH
uniform sampler2D depthTex;
#endif
#if USE_FOAM || USE_WAVES
uniform sampler2D heightmap;
uniform sampler2D infoTex;
uniform sampler2D Foam;
uniform sampler2D waveTex;
#endif
#if USE_SHADOWS
varying vec4 v_shadow;
#if USE_SHADOW_SAMPLER
uniform sampler2DShadow shadowTex;
#if USE_SHADOW_PCF
uniform vec4 shadowScale;
#endif
#else
return 1.0;
uniform sampler2D shadowTex;
#endif
}
float get_shadow(vec4 coords)
{
#if USE_SHADOWS && !DISABLE_RECEIVE_SHADOWS
#if USE_SHADOW_SAMPLER
#if USE_SHADOW_PCF
vec2 offset = fract(coords.xy - 0.5);
vec4 size = vec4(offset + 1.0, 2.0 - offset);
vec4 weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (coords.xy - offset).xyxy) * shadowScale.zwzw;
return (1.0/9.0)*dot(size.zxzx*size.wwyy,
vec4(shadow2D(shadowTex, vec3(weight.zw, coords.z)).r,
shadow2D(shadowTex, vec3(weight.xw, coords.z)).r,
shadow2D(shadowTex, vec3(weight.zy, coords.z)).r,
shadow2D(shadowTex, vec3(weight.xy, coords.z)).r));
#else
return shadow2D(shadowTex, coords.xyz).r;
#endif
#else
if (coords.z >= 1.0)
return 1.0;
return (coords.z <= texture2D(shadowTex, coords.xy).x ? 1.0 : 0.0);
#endif
#else
return 1.0;
#endif
}
#endif
vec3 get_fog(vec3 color)
@ -94,7 +98,7 @@ vec3 get_fog(vec3 color)
void main()
{
#if USE_SUPERFANCYWATER
#if USE_FOAM || USE_WAVES
vec4 heightmapval = texture2D(heightmap, gl_TexCoord[3].zw);
vec2 beachOrientation = heightmapval.rb - vec2(0.5,0.5);
float distToShore = heightmapval.a;
@ -108,32 +112,39 @@ void main()
vec3 reflColor, refrColor, specular;
float losMod;
float wavyFactor = waviness * 0.125;
// always done cause this is also used, even when not using normals, by the refraction.
vec3 ww = texture2D(normalMap, (gl_TexCoord[0].st) * mix(2.0,0.8,waviness/10.0) +gl_TexCoord[0].zw).xzy;
#if USE_SUPERFANCYWATER
vec3 ww2 = texture2D(normalMap2, (gl_TexCoord[0].st) * mix(2.0,0.8,waviness/10.0) +gl_TexCoord[0].zw).xzy;
ww = mix(ww, ww2, mod(time * 60.0, 8.0) / 8.0);
vec3 waves = texture2D(waveTex, gl_FragCoord.xy/screenSize).rbg - vec3(0.5,0.5,0.5);
float waveFoam = 0.0;//texture2D(waveTex, gl_FragCoord.xy/screenSize).a;
n = normalize(mix(waves, ww - vec3(0.5, 0.5, 0.5) , clamp(distToShore*3.0,0.4,1.0)));
#if USE_NORMALS
#if USE_BINORMALS
vec3 ww2 = texture2D(normalMap2, (gl_TexCoord[0].st) * mix(2.0,0.8,waviness/10.0) +gl_TexCoord[0].zw).xzy;
ww = mix(ww, ww2, mod(time * 60.0, 8.0) / 8.0);
#endif
#if USE_WAVES
vec3 waves = texture2D(waveTex, gl_FragCoord.xy/screenSize).rbg - vec3(0.5,0.5,0.5);
float waveFoam = 0.0;//texture2D(waveTex, gl_FragCoord.xy/screenSize).a;
n = normalize(mix(waves, ww - vec3(0.5, 0.5, 0.5) , clamp(distToShore*3.0,0.4,1.0)));
#else
n = normalize(ww - vec3(0.5, 0.5, 0.5));
#endif
n = mix(vec3(0.0,1.0,0.0),n,wavyFactor);
#else
n = normalize(ww - vec3(0.5, 0.5, 0.5));
n = vec3(0.0,1.0,0.0);
#endif
float wavyFactor = waviness * 0.125;
n = mix(vec3(0.0,1.0,0.0),n,wavyFactor);
l = -sunDir;
v = normalize(cameraPos - worldPos);
h = normalize(l + v);
ndotl = (dot(n, l) + 1.0) /2.0;
ndotl = (dot(n, l) + 1.0)/2.0;
ndoth = dot(n, h);
ndotv = dot(n, v);
#if USE_SUPERFANCYWATER
#if USE_REAL_DEPTH
// Don't change these two. They should match the values in the config (TODO: dec uniforms).
float zNear = 2.0;
float zFar = 4096.0;
@ -165,9 +176,9 @@ void main()
float distoFactor = clamp(waterDepth2/10.0,0.0,7.0);
#endif
fresnel = pow(1.0 - ndotv, 1.3333);// approximation
fresnel = pow(1.0 - ndotv, 1.3333); // approximation
#if USE_SUPERFANCYWATER
#if USE_FOAM
// texture is rotated 90°, moves slowly.
vec2 foam1RC = vec2(-gl_TexCoord[0].t,gl_TexCoord[0].s)*1.3 - 0.012*n.xz + vec2(time*0.004,time*0.003);
// texture is not rotated, moves twice faster in the opposite direction, translated.
@ -181,33 +192,50 @@ void main()
if ((1.0 - finalFoam.r) >= wavyFactor)
finalFoam = vec3(0.0);
// waves bypass the regular foam restrictions.
finalFoam += min( max(0.0,-waves.b) * texture2D(Foam, foam1RC).r, 1.0)*3.0 * max(0.0,wavyFactor-0.1);
#if USE_WAVES && USE_NORMALS
// waves bypass the regular foam restrictions.
finalFoam += min( max(0.0,-waves.b) * texture2D(Foam, foam1RC).r, 1.0)*3.0 * max(0.0,wavyFactor-0.1);
#endif
finalFoam *= sunColor;
#endif
#if USE_SUPERFANCYWATER
refrCoords = clamp( (0.5*gl_TexCoord[2].xy - n.xz * distoFactor) / gl_TexCoord[2].w + 0.5,0.0,1.0); // Unbias texture coords
#if USE_REFRACTION
#if USE_REAL_DEPTH
refrCoords = clamp( (0.5*gl_TexCoord[2].xy - n.xz * distoFactor) / gl_TexCoord[2].w + 0.5,0.0,1.0); // Unbias texture coords
vec3 refColor = texture2D(refractionMap, refrCoords).rgb;
float luminance = (1.0 - clamp((waterDepth2/mix(300.0,1.0, pow(murkiness,0.2) )), 0.0, 1.0));
float colorExtinction = clamp(waterDepth2*murkiness/5.0,0.0,1.0);
refrColor = (0.5 + 0.5*ndotl) * mix(color,mix(refColor,refColor*tint,colorExtinction),luminance*luminance);
#else
refrCoords = clamp( (0.5*gl_TexCoord[2].xy - n.xz * 6.0) / gl_TexCoord[2].w + 0.5,0.0,1.0); // Unbias texture coords
// fake it. It won't look as good but it will give a similar result.
float perceivedDepth = waterDepth / v.y;
vec3 refColor = texture2D(refractionMap, refrCoords).rgb;
float luminance = (1.0 - clamp((perceivedDepth/mix(300.0,1.0, pow(murkiness,0.2) )), 0.0, 1.0));
float colorExtinction = clamp(perceivedDepth*murkiness/5.0,0.0,1.0);
refrColor = (0.5 + 0.5*ndotl) * mix(color,mix(refColor,refColor*tint,colorExtinction),luminance*luminance);
#endif
#else
refrCoords = clamp( (0.5*gl_TexCoord[2].xy - n.xz * 6.0) / gl_TexCoord[2].w + 0.5,0.0,1.0); // Unbias texture coords
float alphaCoeff = 0.0;
#if USE_REAL_DEPTH
alphaCoeff = clamp(waterDepth2*murkiness/5.0,0.0,1.0);
#else
alphaCoeff = clamp((waterDepth / v.y)*murkiness/5.0,0.0,1.0);
#endif
refrColor = color;
#endif
reflCoords = clamp( (0.5*gl_TexCoord[1].xy + 10.0*n.xz) / gl_TexCoord[1].w + 0.5,0.0,1.0); // Unbias texture coords
reflColor = mix(texture2D(reflectionMap, reflCoords).rgb, sunColor * reflectionTint, reflectionTintStrength);
#if !USE_NORMALS
// we're not using normals. Simulate by applying a B&W effect.
refrColor *= (ww*2.0).x;
#endif
#if USE_SUPERFANCYWATER
vec3 refColor = texture2D(refractionMap, refrCoords).rgb;
float luminance = (1.0 - clamp((waterDepth2/mix(300.0,1.0, pow(murkiness,0.2) )), 0.0, 1.0));
float colorExtinction = clamp(waterDepth2*murkiness/5.0,0.0,1.0);
refrColor = (0.5 + 0.5*ndotl) * mix(color,mix(refColor,refColor*tint,colorExtinction),luminance*luminance);
#if USE_REFLECTION
reflCoords = clamp( (0.5*gl_TexCoord[1].xy + 10.0*n.xz) / gl_TexCoord[1].w + 0.5,0.0,1.0); // Unbias texture coords
reflColor = mix(texture2D(reflectionMap, reflCoords).rgb, sunColor * reflectionTint, reflectionTintStrength);
#else
// fake it. It won't look as good but it will give a similar result.
float perceivedDepth = waterDepth / v.y;
vec3 refColor = texture2D(refractionMap, refrCoords).rgb;
float luminance = (1.0 - clamp((perceivedDepth/mix(300.0,1.0, pow(murkiness,0.2) )), 0.0, 1.0));
float colorExtinction = clamp(perceivedDepth*murkiness/5.0,0.0,1.0);
refrColor = (0.5 + 0.5*ndotl) * mix(color,mix(refColor,refColor*tint,colorExtinction),luminance*luminance);
// TODO: implement some sort of skybox rendering.
reflColor = mix( (sunColor + vec3(0.565,0.843,0.961))/1.85, reflectionTint, reflectionTintStrength);
#endif
specular = pow(ndoth, shininess) * sunColor * specularStrength;
@ -215,23 +243,54 @@ void main()
losMod = texture2D(losMap, gl_TexCoord[3].st).a;
losMod = losMod < 0.03 ? 0.0 : losMod;
#if USE_SUPERFANCYWATER && USE_SHADOW
vec3 colour;
#if USE_SHADOWS
float shadow = get_shadow(vec4(v_shadow.xy - 8.0*waviness*n.xz, v_shadow.zw));
float fresShadow = mix(fresnel, fresnel*shadow, 0.05 + (murkiness * 0.15));
vec3 colour = mix(refrColor*(shadow/5.0 + 0.8) + fresnel*shadow*specular, reflColor + fresnel*shadow*specular, fresShadow) + max(ndotl,0.4)*(finalFoam)*(shadow/2.0 + 0.5);
colour = mix( texture2D(refractionMap, (0.5*gl_TexCoord[2].xy) / gl_TexCoord[2].w + 0.5).rgb ,colour, clamp(waterDepth2,0.0,1.0));
#if USE_FOAM
colour = mix(refrColor*(shadow/5.0 + 0.8) + fresnel*shadow*specular, reflColor + fresnel*shadow*specular, fresShadow) + max(ndotl,0.4)*(finalFoam)*(shadow/2.0 + 0.5);
#else
colour = mix(refrColor*(shadow/5.0 + 0.8) + fresnel*shadow*specular, reflColor + fresnel*shadow*specular, fresShadow);
#endif
#else
vec3 colour = mix(refrColor + fresnel*specular, reflColor + fresnel*specular, fresnel);
#if USE_FOAM
colour = mix(refrColor + fresnel*specular, reflColor + fresnel*specular, fresnel) + max(ndotl,0.4)*(finalFoam);
#else
colour = mix(refrColor + fresnel*specular, reflColor + fresnel*specular, fresnel);
#endif
#endif
#if USE_REFRACTION
#if USE_REAL_DEPTH
colour = mix(texture2D(refractionMap, (0.5*gl_TexCoord[2].xy) / gl_TexCoord[2].w + 0.5).rgb ,colour, clamp(waterDepth2,0.0,1.0));
#else
colour = mix(texture2D(refractionMap, (0.5*gl_TexCoord[2].xy) / gl_TexCoord[2].w + 0.5).rgb ,colour, clamp(perceivedDepth,0.0,1.0));
#endif
#else
// I'm not even sure what this does.
//colour = mix( texture2D(refractionMap, (0.5*gl_TexCoord[2].xy) / gl_TexCoord[2].w + 0.5).rgb ,colour, clamp(perceivedDepth,0.0,1.0));
#endif
gl_FragColor.rgb = get_fog(colour) * losMod;
#if USE_SUPERFANCYWATER
gl_FragColor.a = clamp(distToShore-0.012,waterDepth2/2.0,1.0) + finalFoam.r * losMod;
#if USE_REAL_DEPTH
float alpha = clamp(waterDepth2*(5.0*murkiness),0.0,1.0);
#if !USE_REFRACTION
alpha *= alphaCoeff;
#endif
#if USE_FOAM
alpha += finalFoam.r * losMod;
#endif
gl_FragColor.a = alpha;
#else
// 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.9 - v.y);
gl_FragColor.a = clamp(0.15 * waterDepth * (1.2 + t + fresnel),0.0,1.0);
t = 30.0 * max(0.0, 0.9 - v.y);
float alpha = clamp(0.15 * waterDepth * (1.2 + t + fresnel),0.0,1.0);
#if !USE_REFRACTION
gl_FragColor.a = alpha * alphaCoeff;
#else
gl_FragColor.a = alpha;
#endif
#endif
}

View File

@ -17,8 +17,9 @@ uniform float mapSize;
varying vec3 worldPos;
varying float waterDepth;
varying vec4 v_shadow;
#if USE_SHADOW
varying vec4 v_shadow;
#endif
attribute vec3 a_vertex;
attribute vec4 a_encodedDepth;
@ -34,7 +35,7 @@ void main()
gl_TexCoord[3].zw = vec2(a_vertex.xz)/mapSize;
#if USE_SHADOW && USE_SUPERFANCYWATER
#if USE_SHADOW && USE_SHADOWS
v_shadow = shadowTransform * vec4(a_vertex, 1.0);
#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF
v_shadow.xy *= shadowScale.xy;

View File

@ -38,8 +38,16 @@ CStr g_PlayerName = "";
bool g_Shadows = false;
bool g_ShadowPCF = false;
bool g_FancyWater = false;
bool g_SuperFancyWater = false;
bool g_WaterNormal = false;
bool g_WaterBinormal = false;
bool g_WaterRealDepth = false;
bool g_WaterFoam = false;
bool g_WaterCoastalWaves = false;
bool g_WaterRefraction = false;
bool g_WaterReflection = false;
bool g_WaterShadows = false;
bool g_Particles = false;
bool g_Silhouettes = false;
bool g_ShowSky = false;
@ -81,11 +89,20 @@ static void LoadGlobals()
CFG_GET_USER_VAL("playername", String, g_PlayerName);
CFG_GET_USER_VAL("shadows", Bool, g_Shadows);
CFG_GET_USER_VAL("shadowpcf", Bool, g_ShadowPCF);
CFG_GET_USER_VAL("fancywater", Bool, g_FancyWater);
CFG_GET_USER_VAL("superfancywater", Bool, g_SuperFancyWater);
if (g_SuperFancyWater && !g_FancyWater) {
g_SuperFancyWater = false;
}
CFG_GET_USER_VAL("waternormals",Bool, g_WaterNormal);
CFG_GET_USER_VAL("waterbinormals",Bool, g_WaterBinormal);
if (g_WaterBinormal && !g_WaterNormal)
g_WaterBinormal = false;
CFG_GET_USER_VAL("waterrealdepth",Bool, g_WaterRealDepth);
CFG_GET_USER_VAL("waterfoam",Bool, g_WaterFoam);
CFG_GET_USER_VAL("watercoastalwaves",Bool, g_WaterCoastalWaves);
if (g_WaterCoastalWaves && !g_WaterNormal)
g_WaterCoastalWaves = false;
CFG_GET_USER_VAL("waterrefraction",Bool, g_WaterRefraction);
CFG_GET_USER_VAL("waterreflection",Bool, g_WaterReflection);
CFG_GET_USER_VAL("watershadows",Bool, g_WaterShadows);
CFG_GET_USER_VAL("renderpath", String, g_RenderPath);
CFG_GET_USER_VAL("particles", Bool, g_Particles);
CFG_GET_USER_VAL("silhouettes", Bool, g_Silhouettes);

View File

@ -49,10 +49,24 @@ extern CStr g_PlayerName;
// flag to switch on shadows
extern bool g_Shadows;
// flag to switch on reflective/refractive water
extern bool g_FancyWater;
// flag to switch on foam, normal interpolation, shadows on water
extern bool g_SuperFancyWater;
// Use real normals for ocean-wave rendering, instead of applying them as a flat texture.
extern bool g_WaterNormal;
// Use interpolated normals, smoother. Requires g_WaterNormal.
extern bool g_WaterBinormal;
// Use real depth for water rendering.
extern bool g_WaterRealDepth;
// Show foam near the shores depending on waviness.
extern bool g_WaterFoam;
// Show coastal breaking waves.
extern bool g_WaterCoastalWaves;
// Use a real refraction map and not transparency.
extern bool g_WaterRefraction;
// Use a real reflection map and not a skybox texture.
extern bool g_WaterReflection;
// Enable on-water shadows.
extern bool g_WaterShadows;
// flag to switch on shadow PCF
extern bool g_ShadowPCF;
// flag to switch on particles rendering

View File

@ -574,8 +574,16 @@ static void InitRenderer()
// set renderer options from command line options - NOVBO must be set before opening the renderer
g_Renderer.SetOptionBool(CRenderer::OPT_NOVBO, g_NoGLVBO);
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, g_Shadows);
g_Renderer.SetOptionBool(CRenderer::OPT_FANCYWATER, g_FancyWater);
g_Renderer.SetOptionBool(CRenderer::OPT_SUPERFANCYWATER, (g_SuperFancyWater && g_FancyWater) );
g_Renderer.SetOptionBool(CRenderer::OPT_WATERNORMAL, g_WaterNormal);
g_Renderer.SetOptionBool(CRenderer::OPT_WATERBINORMAL, g_WaterBinormal);
g_Renderer.SetOptionBool(CRenderer::OPT_WATERREALDEPTH, g_WaterRealDepth);
g_Renderer.SetOptionBool(CRenderer::OPT_WATERFOAM, g_WaterFoam);
g_Renderer.SetOptionBool(CRenderer::OPT_WATERCOASTALWAVES, g_WaterCoastalWaves);
g_Renderer.SetOptionBool(CRenderer::OPT_WATERREFLECTION, g_WaterRefraction);
g_Renderer.SetOptionBool(CRenderer::OPT_WATERREFRACTION, g_WaterReflection);
g_Renderer.SetOptionBool(CRenderer::OPT_WATERSHADOW, g_WaterShadows);
g_Renderer.SetRenderPath(CRenderer::GetRenderPathByName(g_RenderPath));
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWPCF, g_ShadowPCF);
g_Renderer.SetOptionBool(CRenderer::OPT_PARTICLES, g_Particles);

View File

@ -123,16 +123,31 @@ void SetDisableShadowPCF(void* UNUSED(cbdata), bool disabled)
void SetDisableFancyWater(void* UNUSED(cbdata), bool disabled)
{
if (!IsOverridden("fancywater")) {
g_FancyWater = !disabled;
g_SuperFancyWater = !disabled;
if (!IsOverridden("waternormals"))
{
g_WaterNormal = !disabled;
if (!g_WaterNormal)
g_WaterBinormal = false;
}
if (!IsOverridden("waterbinormals"))
g_WaterBinormal = !disabled;
if (!IsOverridden("waterrealdepth"))
g_WaterRealDepth = !disabled;
if (!IsOverridden("waterfoam"))
g_WaterFoam = !disabled;
if (!IsOverridden("watercoastalwaves"))
g_WaterCoastalWaves = !disabled;
if (!IsOverridden("waterrefraction"))
g_WaterRefraction = !disabled;
if (!IsOverridden("waterreflection"))
g_WaterReflection = !disabled;
if (!IsOverridden("watershadows"))
g_WaterShadows = !disabled;
}
void SetRenderPath(void* UNUSED(cbdata), std::string renderpath)
{
if (!IsOverridden("fancywater"))
g_RenderPath = renderpath;
g_RenderPath = renderpath;
}
void RunHardwareDetection()

View File

@ -429,8 +429,6 @@ CRenderer::CRenderer()
m_Options.m_NoVBO = false;
m_Options.m_RenderPath = RP_DEFAULT;
m_Options.m_FancyWater = false;
m_Options.m_SuperFancyWater = false;
m_Options.m_Shadows = false;
m_Options.m_ShadowAlphaFix = true;
m_Options.m_ARBProgramShadow = true;
@ -469,8 +467,16 @@ CRenderer::CRenderer()
m_Stats.Reset();
AddLocalProperty(L"particles", &m_Options.m_Particles, false);
AddLocalProperty(L"fancyWater", &m_Options.m_FancyWater, false);
AddLocalProperty(L"superFancyWater", &m_Options.m_SuperFancyWater, false);
AddLocalProperty(L"waternormal", &m_Options.m_WaterNormal, false);
AddLocalProperty(L"waterbinormal", &m_Options.m_WaterBinormal, false);
AddLocalProperty(L"waterrealdepth", &m_Options.m_WaterRealDepth, false);
AddLocalProperty(L"waterreflection", &m_Options.m_WaterReflection, false);
AddLocalProperty(L"waterrefraction", &m_Options.m_WaterRefraction, false);
AddLocalProperty(L"waterfoam", &m_Options.m_WaterFoam, false);
AddLocalProperty(L"watercoastalwaves", &m_Options.m_WaterCoastalWaves, false);
AddLocalProperty(L"watershadow", &m_Options.m_WaterShadow, false);
AddLocalProperty(L"horizonHeight", &m->skyManager.m_HorizonHeight, false);
AddLocalProperty(L"waterMurkiness", &m->waterManager.m_Murkiness, false);
AddLocalProperty(L"waterReflTintStrength", &m->waterManager.m_ReflectionTintStrength, false);
@ -682,11 +688,29 @@ void CRenderer::SetOptionBool(enum Option opt,bool value)
m_Options.m_Shadows = value;
MakeShadersDirty();
break;
case OPT_FANCYWATER:
m_Options.m_FancyWater = value;
case OPT_WATERNORMAL:
m_Options.m_WaterNormal = value;
break;
case OPT_SUPERFANCYWATER:
m_Options.m_SuperFancyWater = value;
case OPT_WATERBINORMAL:
m_Options.m_WaterBinormal = value;
break;
case OPT_WATERREALDEPTH:
m_Options.m_WaterRealDepth = value;
break;
case OPT_WATERFOAM:
m_Options.m_WaterFoam = value;
break;
case OPT_WATERCOASTALWAVES:
m_Options.m_WaterCoastalWaves = value;
break;
case OPT_WATERREFLECTION:
m_Options.m_WaterReflection = value;
break;
case OPT_WATERREFRACTION:
m_Options.m_WaterRefraction = value;
break;
case OPT_WATERSHADOW:
m_Options.m_WaterShadow = value;
break;
case OPT_SHADOWPCF:
m_Options.m_ShadowPCF = value;
@ -716,10 +740,22 @@ bool CRenderer::GetOptionBool(enum Option opt) const
return m_Options.m_NoVBO;
case OPT_SHADOWS:
return m_Options.m_Shadows;
case OPT_FANCYWATER:
return m_Options.m_FancyWater;
case OPT_SUPERFANCYWATER:
return m_Options.m_SuperFancyWater;
case OPT_WATERNORMAL:
return m_Options.m_WaterNormal;
case OPT_WATERBINORMAL:
return m_Options.m_WaterBinormal;
case OPT_WATERREALDEPTH:
return m_Options.m_WaterRealDepth;
case OPT_WATERFOAM:
return m_Options.m_WaterFoam;
case OPT_WATERCOASTALWAVES:
return m_Options.m_WaterCoastalWaves;
case OPT_WATERREFLECTION:
return m_Options.m_WaterReflection;
case OPT_WATERREFRACTION:
return m_Options.m_WaterRefraction;
case OPT_WATERSHADOW:
return m_Options.m_WaterShadow;
case OPT_SHADOWPCF:
return m_Options.m_ShadowPCF;
case OPT_PARTICLES:
@ -815,10 +851,6 @@ void CRenderer::BeginFrame()
if (m->ShadersDirty)
ReloadShaders();
// this is ugly, I should do otherwise
if (g_GameRestarted)
m_WaterManager->m_NeedsReloading = true;
m->Model.ModShader->SetShadowMap(&m->shadow);
m->Model.ModShader->SetLightEnv(m_LightEnv);
}
@ -1446,9 +1478,13 @@ void CRenderer::RenderSubmissions()
waterScissor = m->terrainRenderer.ScissorWater(m_ViewCamera.GetViewProjection());
if (waterScissor.GetVolume() > 0 && m_WaterManager->WillRenderFancyWater())
{
SScreenRect reflectionScissor = RenderReflections(context, waterScissor);
SScreenRect refractionScissor = RenderRefractions(context, waterScissor);
SScreenRect reflectionScissor;
if (m_Options.m_WaterReflection)
reflectionScissor = RenderReflections(context, waterScissor);
SScreenRect refractionScissor;
if (m_Options.m_WaterRefraction)
refractionScissor = RenderRefractions(context, waterScissor);
PROFILE3_GPU("water scissor");
SScreenRect dirty;
dirty.x1 = std::min(reflectionScissor.x1, refractionScissor.x1);

View File

@ -80,8 +80,14 @@ public:
enum Option {
OPT_NOVBO,
OPT_SHADOWS,
OPT_FANCYWATER,
OPT_SUPERFANCYWATER,
OPT_WATERNORMAL,
OPT_WATERBINORMAL,
OPT_WATERREALDEPTH,
OPT_WATERFOAM,
OPT_WATERCOASTALWAVES,
OPT_WATERREFLECTION,
OPT_WATERREFRACTION,
OPT_WATERSHADOW,
OPT_SHADOWPCF,
OPT_PARTICLES,
OPT_SILHOUETTES,
@ -124,8 +130,16 @@ public:
struct Options {
bool m_NoVBO;
bool m_Shadows;
bool m_FancyWater;
bool m_SuperFancyWater;
bool m_WaterNormal;
bool m_WaterBinormal;
bool m_WaterRealDepth;
bool m_WaterFoam;
bool m_WaterCoastalWaves;
bool m_WaterRefraction;
bool m_WaterReflection;
bool m_WaterShadow;
RenderPath m_RenderPath;
bool m_ShadowAlphaFix;
bool m_ARBProgramShadow;

View File

@ -651,28 +651,36 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
CShaderDefines defines = context;
// deactivate superfancy in Atlas so it won't lag.
bool superFancy = WaterMgr->WillRenderSuperFancyWater() && !g_AtlasGameLoop->running;
// Don't use m_NeedsReloading since that also restarts the map texture generation (slow).
bool reload = false;
if (superFancy && !WaterMgr->m_RunningSuperFancy)
{
reload = true;
WaterMgr->m_RunningSuperFancy = true;
}
else if (!superFancy && WaterMgr->m_RunningSuperFancy)
{
reload = true;
WaterMgr->m_RunningSuperFancy = false;
}
WaterMgr->updateQuality();
// If we're using fancy water, make sure its shader is loaded
if (!m->fancyWaterShader || WaterMgr->m_NeedsReloading || reload)
if (!m->fancyWaterShader || (WaterMgr->m_NeedsReloading && (!g_AtlasGameLoop->running || !WaterMgr->m_TerrainChangeThisTurn) ))
{
if (superFancy)
defines.Add("USE_SUPERFANCYWATER", "1");
else
defines.Add("USE_SUPERFANCYWATER", "0");
if(WaterMgr->m_WaterNormal)
defines.Add("USE_NORMALS","1");
if(WaterMgr->m_WaterBinormal)
defines.Add("USE_BINORMALS","1");
if(WaterMgr->m_WaterRealDepth)
defines.Add("USE_REAL_DEPTH","1");
if(WaterMgr->m_WaterFoam)
defines.Add("USE_FOAM","1");
if(WaterMgr->m_WaterCoastalWaves)
defines.Add("USE_WAVES","1");
if(WaterMgr->m_WaterRefraction)
defines.Add("USE_REFRACTION","1");
if(WaterMgr->m_WaterReflection)
defines.Add("USE_REFLECTION","1");
if(shadow && WaterMgr->m_WaterShadows)
defines.Add("USE_SHADOWS","1");
m->wavesShader = g_Renderer.GetShaderManager().LoadProgram("glsl/waves", defines);
if (!m->wavesShader)
{
LOGERROR(L"Failed to load waves shader. Deactivating waves.\n");
g_Renderer.SetOptionBool(CRenderer::OPT_WATERCOASTALWAVES, false);
defines.Add("USE_WAVES","0");
}
// haven't updated the ARB shader yet so I'll always load the GLSL
/*if (!g_Renderer.m_Options.m_PreferGLSL && !superFancy)
@ -680,32 +688,34 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
else*/
m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("glsl/water_high", defines);
m->wavesShader = g_Renderer.GetShaderManager().LoadProgram("glsl/waves", defines);
if (!m->fancyWaterShader)
{
LOGERROR(L"Failed to load water shader. Falling back to non-fancy water.\n");
g_Renderer.m_Options.m_FancyWater = false;
g_Renderer.m_Options.m_SuperFancyWater = false;
WaterMgr->m_RenderWater = false;
return false;
}
if (WaterMgr->m_NeedsReloading)
// we need to actually recompute the whole map settings.
if (WaterMgr->m_NeedsFullReloading)
{
delete[] WaterMgr->m_Heightmap;
WaterMgr->m_Heightmap = NULL;
glDeleteTextures(1, &WaterMgr->m_HeightmapTexture);
WaterMgr->m_NeedsReloading = false;
WaterMgr->m_NeedsFullReloading = false;
WaterMgr->m_waveTT = 0;
WaterMgr->m_depthTT = 0;
}
}
if (g_AtlasGameLoop->running)
WaterMgr->m_TerrainChangeThisTurn = false;
CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();
GLuint depthTex;
// TODO: ultimately, this should go in the water manager for readibility.
if (superFancy)
// creating the real depth texture using the depth buffer.
if (WaterMgr->m_WaterRealDepth)
{
if (WaterMgr->m_depthTT == 0)
{
@ -725,12 +735,11 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight(), 0);
glBindTexture(GL_TEXTURE_2D, 0);
// If we have not already calculated the heightmap, do it once and for all.
// TODO: in Atlas this is recomputed every frame, which is way too slow. Temporary fix is disabling it in Atlas.
if (WaterMgr->m_Heightmap == NULL)
WaterMgr->CreateSuperfancyInfo();
}
// Calculating the advanced informations about Foam and all if the quality calls for it.
if (WaterMgr->m_Heightmap == NULL && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves))
WaterMgr->CreateSuperfancyInfo();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
@ -743,8 +752,8 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
GLuint FramebufferName = 0;
// rendering waves to a framebuffer if super fancy water is activated
if (superFancy)
// rendering waves to a framebuffer
if (WaterMgr->m_WaterCoastalWaves)
{
// Save the post-processing framebuffer.
GLint fbo;
@ -803,36 +812,41 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
m->fancyWaterShader->Bind();
m->fancyWaterShader->BindTexture("normalMap", WaterMgr->m_NormalMap[curTex]);
if (superFancy)
{
m->fancyWaterShader->BindTexture("normalMap2", WaterMgr->m_NormalMap[nexTex]);
m->fancyWaterShader->BindTexture("Foam", WaterMgr->m_Foam);
m->fancyWaterShader->BindTexture("heightmap", WaterMgr->m_HeightmapTexture);
m->fancyWaterShader->BindTexture("infoTex", WaterMgr->m_OtherInfoTex);
m->fancyWaterShader->BindTexture("depthTex", WaterMgr->m_depthTT);
m->fancyWaterShader->BindTexture("waveTex", WaterMgr->m_waveTT);
m->fancyWaterShader->Uniform("mapSize", (float)(WaterMgr->m_TexSize));
}
// Shift the texture coordinates by these amounts to make the water "flow"
float tx = -fmod(time, 81.0 / (WaterMgr->m_Waviness/20.0 + 0.8) )/(81.0/ (WaterMgr->m_Waviness/20.0 + 0.8) );
float ty = -fmod(time, 34.0 / (WaterMgr->m_Waviness/20.0 + 0.8) )/(34.0/ (WaterMgr->m_Waviness/20.0 + 0.8) );
float repeatPeriod = WaterMgr->m_RepeatPeriod;
const CCamera& camera = g_Renderer.GetViewCamera();
CVector3D camPos = camera.m_Orientation.GetTranslation();
// Bind reflection and refraction textures
m->fancyWaterShader->BindTexture("normalMap", WaterMgr->m_NormalMap[curTex]);
if (WaterMgr->m_WaterBinormal)
m->fancyWaterShader->BindTexture("normalMap2", WaterMgr->m_NormalMap[nexTex]);
if (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)
{
m->fancyWaterShader->BindTexture("Foam", WaterMgr->m_Foam);
m->fancyWaterShader->BindTexture("heightmap", WaterMgr->m_HeightmapTexture);
m->fancyWaterShader->BindTexture("infoTex", WaterMgr->m_OtherInfoTex);
m->fancyWaterShader->Uniform("mapSize", (float)(WaterMgr->m_TexSize));
}
if (WaterMgr->m_WaterRealDepth)
m->fancyWaterShader->BindTexture("depthTex", WaterMgr->m_depthTT);
if (WaterMgr->m_WaterCoastalWaves)
m->fancyWaterShader->BindTexture("waveTex", WaterMgr->m_waveTT);
if (WaterMgr->m_WaterReflection)
m->fancyWaterShader->BindTexture("reflectionMap", WaterMgr->m_ReflectionTexture);
if (WaterMgr->m_WaterRefraction)
m->fancyWaterShader->BindTexture("refractionMap", WaterMgr->m_RefractionTexture);
m->fancyWaterShader->BindTexture("losMap", losTexture.GetTextureSmooth());
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
// TODO: only bind what's really needed for that.
m->fancyWaterShader->Uniform("sunDir", lightEnv.GetSunDir());
m->fancyWaterShader->Uniform("sunColor", lightEnv.m_SunColor.X);
m->fancyWaterShader->Uniform("color", WaterMgr->m_WaterColor);
@ -854,7 +868,7 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap*
m->fancyWaterShader->Uniform("time", (float)time);
m->fancyWaterShader->Uniform("screenSize", (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0.0f, 0.0f);
if (shadow && superFancy)
if (shadow && WaterMgr->m_WaterShadows)
{
m->fancyWaterShader->BindTexture("shadowTex", shadow->GetTexture());
m->fancyWaterShader->Uniform("shadowTransform", shadow->GetTextureMatrix());
@ -989,8 +1003,10 @@ void TerrainRenderer::RenderWater(const CShaderDefines& context, ShadowMap* shad
{
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
if (!WaterMgr->WillRenderFancyWater() || !RenderFancyWater(context, shadow))
if (!WaterMgr->WillRenderFancyWater())
RenderSimpleWater();
else
RenderFancyWater(context, shadow);
}
void TerrainRenderer::RenderPriorities()

View File

@ -77,8 +77,19 @@ WaterManager::WaterManager()
m_Heightmap = NULL;
m_HeightmapTexture = 0;
m_OtherInfoTex = NULL;
m_RunningSuperFancy = WillRenderSuperFancyWater();
m_WaterNormal = false;
m_WaterBinormal = false;
m_WaterRealDepth = false;
m_WaterFoam = false;
m_WaterCoastalWaves = false;
m_WaterRefraction = false;
m_WaterReflection = false;
m_WaterShadows = false;
m_NeedsReloading = false;
m_NeedsFullReloading = false;
m_TerrainChangeThisTurn = false;
m_VBWaves = NULL;
m_VBWavesIndices = NULL;
@ -269,84 +280,6 @@ void WaterManager::CreateSuperfancyInfo()
waveForceHQ[j*mapSize + i] = 255 - color * 7;
}
}
// okay let's create the waves squares. i'll divide the map in arbitrary squares
// For each of these squares, check if waves are needed.
// If yes, look for the best positionning (in order to have a nice blending with the shore)
// Then clean-up: remove squares that are too close to each other
std::vector<CVector2D> waveSquares;
int size = 8; // I think this is the size of the squares.
for (int i = 0; i < mapSize/size; ++i)
{
for (int j = 0; j < mapSize/size; ++j)
{
int landTexel = 0;
int waterTexel = 0;
CVector3D avnormal (0.0f,0.0f,0.0f);
CVector2D landPosition(0.0f,0.0f);
CVector2D waterPosition(0.0f,0.0f);
for (int xx = 0; xx < size; ++xx)
{
for (int yy = 0; yy < size; ++yy)
{
if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > this->m_WaterHeight)
{
landTexel++;
landPosition += CVector2D(i*size+xx,j*size+yy);
}
else
{
waterPosition += CVector2D(i*size+xx,j*size+yy);
waterTexel++;
}
avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f);
}
}
landPosition /= landTexel;
waterPosition /= waterTexel;
avnormal[1] = 1.0f;
avnormal.Normalize();
avnormal[1] = 0.0f;
if (landTexel < size/2)
continue;
// this should help ensure that the shore is pretty flat.
if (avnormal.Length() <= 0.2f)
continue;
// To get the best position for squares, I start at the mean "ocean" position
// And step by step go to the mean "land" position. I keep the position where I change from water to land.
// If this never happens, the square is scrapped.
if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > this->m_WaterHeight)
continue;
CVector2D squarePos(-1,-1);
for (u8 i = 0; i < 40; i++)
{
squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f));
if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > this->m_WaterHeight)
break;
}
if (squarePos.X == -1)
continue;
u8 enter = 1;
// okaaaaaay. Got a square. Check for proximity.
for (unsigned long i = 0; i < waveSquares.size(); i++)
{
if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 100) {
enter = 0;
break;
}
}
if (enter == 1)
waveSquares.push_back(squarePos);
}
}
// this creates information for waves and stores it in a texture.
// texture "newHeightmap" is [x vector of wave direction, coefficient of "water raise", y vector of waves, distance to shore.]
// texture "OtherInfo" stores the intensity of actual waves and of foam.
@ -459,82 +392,204 @@ void WaterManager::CreateSuperfancyInfo()
glBindTexture(GL_TEXTURE_2D, 0);
// Actually create the waves' meshes.
std::vector<SWavesVertex> waves_vertex_data;
std::vector<GLushort> waves_indices;
// loop through each square point. Look in the square around it, calculate the normal
// create the square.
for (unsigned long i = 0; i < waveSquares.size(); i++)
if (this->m_WaterCoastalWaves)
{
CVector2D pos(waveSquares[i]);
// okay let's create the waves squares. i'll divide the map in arbitrary squares
// For each of these squares, check if waves are needed.
// If yes, look for the best positionning (in order to have a nice blending with the shore)
// Then clean-up: remove squares that are too close to each other
CVector3D avgnorm(0.0f,0.0f,0.0f);
for (int xx = -size/2; xx < size/2; ++xx)
std::vector<CVector2D> waveSquares;
int size = 8; // I think this is the size of the squares.
for (int i = 0; i < mapSize/size; ++i)
{
for (int yy = -size/2; yy < size/2; ++yy)
for (int j = 0; j < mapSize/size; ++j)
{
avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f);
int landTexel = 0;
int waterTexel = 0;
CVector3D avnormal (0.0f,0.0f,0.0f);
CVector2D landPosition(0.0f,0.0f);
CVector2D waterPosition(0.0f,0.0f);
for (int xx = 0; xx < size; ++xx)
{
for (int yy = 0; yy < size; ++yy)
{
if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > this->m_WaterHeight)
{
landTexel++;
landPosition += CVector2D(i*size+xx,j*size+yy);
}
else
{
waterPosition += CVector2D(i*size+xx,j*size+yy);
waterTexel++;
}
avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f);
}
}
landPosition /= landTexel;
waterPosition /= waterTexel;
avnormal[1] = 1.0f;
avnormal.Normalize();
avnormal[1] = 0.0f;
if (landTexel < size/2)
continue;
// this should help ensure that the shore is pretty flat.
if (avnormal.Length() <= 0.2f)
continue;
// To get the best position for squares, I start at the mean "ocean" position
// And step by step go to the mean "land" position. I keep the position where I change from water to land.
// If this never happens, the square is scrapped.
if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > this->m_WaterHeight)
continue;
CVector2D squarePos(-1,-1);
for (u8 i = 0; i < 40; i++)
{
squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f));
if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > this->m_WaterHeight)
break;
}
if (squarePos.X == -1)
continue;
u8 enter = 1;
// okaaaaaay. Got a square. Check for proximity.
for (unsigned long i = 0; i < waveSquares.size(); i++)
{
if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 100) {
enter = 0;
break;
}
}
if (enter == 1)
waveSquares.push_back(squarePos);
}
}
avgnorm[1] = 0.1f;
// okay crank out a square.
// we have the direction of the square. We'll get the perpendicular vector too
CVector2D perp(-avgnorm[2],avgnorm[0]);
perp = perp.Normalized();
avgnorm = avgnorm.Normalized();
// Actually create the waves' meshes.
std::vector<SWavesVertex> waves_vertex_data;
std::vector<GLushort> waves_indices;
SWavesVertex vertex[4];
vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
vertex[0].m_Position *= 4.0f;
vertex[0].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[0].m_UV[1] = 1;
vertex[0].m_UV[0] = 0;
// loop through each square point. Look in the square around it, calculate the normal
// create the square.
for (unsigned long i = 0; i < waveSquares.size(); i++)
{
CVector2D pos(waveSquares[i]);
CVector3D avgnorm(0.0f,0.0f,0.0f);
for (int xx = -size/2; xx < size/2; ++xx)
{
for (int yy = -size/2; yy < size/2; ++yy)
{
avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f);
}
}
avgnorm[1] = 0.1f;
// okay crank out a square.
// we have the direction of the square. We'll get the perpendicular vector too
CVector2D perp(-avgnorm[2],avgnorm[0]);
perp = perp.Normalized();
avgnorm = avgnorm.Normalized();
SWavesVertex vertex[4];
vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
vertex[0].m_Position *= 4.0f;
vertex[0].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[0].m_UV[1] = 1;
vertex[0].m_UV[0] = 0;
vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
vertex[1].m_Position *= 4.0f;
vertex[1].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[1].m_UV[1] = 1;
vertex[1].m_UV[0] = 1;
vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
vertex[3].m_Position *= 4.0f;
vertex[3].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[3].m_UV[1] = 0;
vertex[3].m_UV[0] = 0;
vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
vertex[2].m_Position *= 4.0f;
vertex[2].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[2].m_UV[1] = 0;
vertex[2].m_UV[0] = 1;
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[0]);
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[1]);
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[2]);
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[3]);
}
vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f);
vertex[1].m_Position *= 4.0f;
vertex[1].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[1].m_UV[1] = 1;
vertex[1].m_UV[0] = 1;
// waves
// allocate vertex buffer
this->m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
this->m_VBWaves->m_Owner->UpdateChunkVertices(this->m_VBWaves, &waves_vertex_data[0]);
vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
vertex[3].m_Position *= 4.0f;
vertex[3].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[3].m_UV[1] = 0;
vertex[3].m_UV[0] = 0;
vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f));
vertex[2].m_Position *= 4.0f;
vertex[2].m_Position.Y = this->m_WaterHeight + 1.0f;
vertex[2].m_UV[1] = 0;
vertex[2].m_UV[0] = 1;
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[0]);
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[1]);
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[2]);
waves_indices.push_back(waves_vertex_data.size());
waves_vertex_data.push_back(vertex[3]);
// Construct indices buffer
this->m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
this->m_VBWavesIndices->m_Owner->UpdateChunkVertices(this->m_VBWavesIndices, &waves_indices[0]);
}
}
////////////////////////////////////////////////////////////////////////
// This will set the bools properly
void WaterManager::updateQuality()
{
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERNORMAL) != m_WaterNormal) {
m_WaterNormal = g_Renderer.GetOptionBool(CRenderer::OPT_WATERNORMAL);
m_NeedsReloading = true;
}
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERBINORMAL) != m_WaterBinormal) {
m_WaterBinormal = g_Renderer.GetOptionBool(CRenderer::OPT_WATERBINORMAL);
m_NeedsReloading = true;
}
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERREALDEPTH) != m_WaterRealDepth) {
m_WaterRealDepth = g_Renderer.GetOptionBool(CRenderer::OPT_WATERREALDEPTH);
m_NeedsReloading = true;
}
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERFOAM) != m_WaterFoam) {
m_WaterFoam = g_Renderer.GetOptionBool(CRenderer::OPT_WATERFOAM);
m_NeedsReloading = true;
m_NeedsFullReloading = true;
}
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERCOASTALWAVES) != m_WaterCoastalWaves) {
m_WaterCoastalWaves = g_Renderer.GetOptionBool(CRenderer::OPT_WATERCOASTALWAVES);
m_NeedsReloading = true;
m_NeedsFullReloading = true;
}
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFRACTION) != m_WaterRefraction) {
m_WaterRefraction = g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFRACTION);
m_NeedsReloading = true;
}
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFLECTION) != m_WaterReflection) {
m_WaterReflection = g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFLECTION);
m_NeedsReloading = true;
}
if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERSHADOW) != m_WaterShadows) {
m_WaterShadows = g_Renderer.GetOptionBool(CRenderer::OPT_WATERSHADOW);
m_NeedsReloading = true;
}
// waves
// allocate vertex buffer
this->m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
this->m_VBWaves->m_Owner->UpdateChunkVertices(this->m_VBWaves, &waves_vertex_data[0]);
// Construct indices buffer
this->m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
this->m_VBWavesIndices->m_Owner->UpdateChunkVertices(this->m_VBWavesIndices, &waves_indices[0]);
}
bool WaterManager::WillRenderFancyWater()
{
return (g_Renderer.GetCapabilities().m_FragmentShader && g_Renderer.GetOptionBool(CRenderer::OPT_FANCYWATER));
if (!g_Renderer.GetCapabilities().m_FragmentShader)
return false;
if (g_Renderer.GetRenderPath() == 1)
return false;
if (!m_RenderWater)
return false;
return true;
}
bool WaterManager::WillRenderSuperFancyWater()
{
return (WillRenderFancyWater() && g_Renderer.GetOptionBool(CRenderer::OPT_SUPERFANCYWATER));
}

View File

@ -65,8 +65,23 @@ public:
int m_WaterCurrentTex;
CColor m_WaterColor;
bool m_RenderWater;
bool m_RunningSuperFancy;
// Those variables register the current quality level. If there is a change, I have to recompile the shader.
bool m_WaterNormal;
bool m_WaterBinormal;
bool m_WaterRealDepth;
bool m_WaterFoam;
bool m_WaterCoastalWaves;
bool m_WaterRefraction;
bool m_WaterReflection;
bool m_WaterShadows;
bool m_NeedsReloading;
// requires also recreating the super fancy information.
bool m_NeedsFullReloading;
// used only by Atlas to know when to update the water map.
bool m_TerrainChangeThisTurn;
bool m_WaterScroll;
float m_WaterHeight;
float m_WaterMaxAlpha;
@ -131,17 +146,16 @@ public:
*/
void CreateSuperfancyInfo();
/**
* Updates the settings to the one from the renderer, and sets m_NeedsReloading.
*/
void updateQuality();
/**
* Returns true if fancy water shaders will be used (i.e. the hardware is capable
* and it hasn't been configured off)
*/
bool WillRenderFancyWater();
/**
* Returns true if super fancy water shaders will be used (i.e. the hardware is capable
* and it hasn't been configured off)
*/
bool WillRenderSuperFancyWater();
};

View File

@ -86,7 +86,6 @@ def report_performance(request):
mapname = 'unknown' # e.g. random maps
msecs = None
shadows = False
fancywater = False
for name,table in json['profiler'].items():
m = re.match(r'Profiling Information for: root \(Time in node: (\d+\.\d+) msec/frame\)', name)
if m:
@ -101,18 +100,11 @@ def report_performance(request):
except (KeyError, TypeError):
pass
try:
if float(table['data']['render'][0]['render submissions'][0]['render reflections'][2]):
fancywater = True
except (KeyError, TypeError):
pass
if msecs is None:
return None
options = []
if shadows: options.append('S')
if fancywater: options.append('W')
return {
'msecs': msecs,