1
0
forked from 0ad/0ad

Commit coastal waves when activating fancy effects, and incidentally completely change how this effect work. Refs #48.

This was SVN commit r15576.
This commit is contained in:
wraitii 2014-07-28 10:14:00 +00:00
parent 91ead32b1a
commit 9ce51f4357
19 changed files with 1095 additions and 517 deletions

Binary file not shown.

View File

@ -1,68 +0,0 @@
#version 110
// This is a lightened version of water_high.fs that generates only the "n" vector (ie the normal) and the foam coverage.
// It's thus uncommented.
uniform float waviness;
uniform vec2 screenSize;
uniform float time;
varying vec3 worldPos;
varying vec4 waterInfo;
uniform float mapSize;
uniform sampler2D normalMap;
uniform sampler2D normalMap2;
/*#if USE_FOAM || USE_WAVES
uniform sampler2D Foam;
uniform sampler2D waveTex;
#endif*/
uniform vec4 waveParams1; // wavyEffect, BaseScale, Flattenism, Basebump
uniform vec4 waveParams2; // Smallintensity, Smallbase, Bigmovement, Smallmovement
void main()
{
// Fix the waviness for local wind strength
float fwaviness = waviness * ((0.15+waterInfo.r/1.15));
float wavyEffect = waveParams1.r;
float baseScale = waveParams1.g;
float flattenism = waveParams1.b;
float baseBump = waveParams1.a;
float smallIntensity = waveParams2.r;
float smallBase = waveParams2.g;
float BigMovement = waveParams2.b;
float SmallMovement = waveParams2.a;
// This method uses 60 animated water frames. We're blending between each two frames
// TODO: could probably have fewer frames thanks to this blending.
// Scale the normal textures by waviness so that big waviness means bigger waves.
vec3 ww1 = texture2D(normalMap, (gl_TexCoord[0].st + gl_TexCoord[0].zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).xzy;
vec3 ww2 = texture2D(normalMap2, (gl_TexCoord[0].st + gl_TexCoord[0].zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).xzy;
vec3 smallWW = texture2D(normalMap, (gl_TexCoord[0].st + gl_TexCoord[0].zw * SmallMovement*waviness/10.0) * baseScale*3.0).xzy;
vec3 smallWW2 = texture2D(normalMap2, (gl_TexCoord[0].st + gl_TexCoord[0].zw * SmallMovement*waviness/10.0) * baseScale*3.0).xzy;
ww1 = mix(ww1, ww2, mod(time * 60.0, 8.0) / 8.0);
smallWW = mix(smallWW, smallWW2, mod(time * 60.0, 8.0) / 8.0) - vec3(0.5);
ww1 += vec3(smallWW.x,0.0,smallWW.z)*(fwaviness/10.0*smallIntensity + smallBase);
ww1 = mix(smallWW + vec3(0.5,0.0,0.5), ww1, waterInfo.r);
// Flatten them based on waviness.
vec3 n = normalize(mix(vec3(0.0,1.0,0.0),ww1 - vec3(0.5,0.0,0.5), clamp(baseBump + fwaviness/flattenism,0.0,1.0)));
float foamFact1 = texture2D(normalMap, (gl_TexCoord[0].st) * 0.3).a;
float foamFact2 = texture2D(normalMap2, (gl_TexCoord[0].st) * 0.3).a;
float foamFact = mix(foamFact1, foamFact2, mod(time * 60.0, 8.0) / 8.0);
float foamUniversal1 = texture2D(normalMap, (gl_TexCoord[0].st) * 0.05).a;
float foamUniversal2 = texture2D(normalMap2, (gl_TexCoord[0].st) * 0.05).a;
float foamUniversal = mix(foamUniversal1, foamUniversal2, mod(time * 60.0, 8.0) / 8.0);
gl_FragColor.rgba = vec4((n + 1.0)/2.0,foamFact*foamUniversal*30.0);
}

View File

@ -1,31 +0,0 @@
#version 110
// This is a lightened version of water_high.vs
uniform float repeatScale;
uniform float windAngle;
uniform float time;
uniform float mapSize;
varying vec3 worldPos;
varying vec4 waterInfo;
attribute vec3 a_vertex;
attribute vec4 a_waterInfo;
void main()
{
worldPos = a_vertex;
waterInfo = a_waterInfo;
float newX = a_vertex.x * cos(-windAngle) - a_vertex.z * sin(-windAngle);
float newY = a_vertex.x * sin(-windAngle) + a_vertex.z * cos(-windAngle);
gl_TexCoord[0] = vec4(newX,newY,time,0.0);
gl_TexCoord[0].xy *= repeatScale;
gl_TexCoord[3].zw = vec2(a_vertex.xz)/mapSize;
gl_Position = gl_ModelViewProjectionMatrix * vec4(a_vertex, 1.0);
}

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<program type="glsl">
<vertex file="glsl/water_effects.vs">
<stream name="pos"/>
<attrib name="a_vertex" semantics="gl_Vertex"/>
<attrib name="a_waterInfo" semantics="CustomAttribute0"/>
</vertex>
<fragment file="glsl/water_effects.fs"/>
</program>

View File

@ -4,6 +4,7 @@
uniform vec3 ambient;
uniform vec3 sunDir;
uniform vec3 sunColor;
uniform mat4 skyBoxRot;
uniform vec3 cameraPos;
@ -14,6 +15,9 @@ 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 colour
uniform float windAngle;
varying vec2 WindCosSin;
uniform vec3 fogColor;
uniform vec2 fogParams;
@ -22,7 +26,9 @@ uniform float time;
varying vec3 worldPos;
varying float waterDepth;
varying vec4 waterInfo;
varying vec2 waterInfo;
varying float fwaviness;
uniform float mapSize;
@ -32,15 +38,15 @@ uniform sampler2D normalMap;
uniform sampler2D normalMap2;
#if USE_FANCY_EFFECTS
uniform sampler2D waterEffectsTex;
uniform sampler2D waterEffectsTexNorm;
uniform sampler2D waterEffectsTexOther;
#endif
uniform vec4 waveParams1; // wavyEffect, BaseScale, Flattenism, Basebump
uniform vec4 waveParams2; // Smallintensity, Smallbase, Bigmovement, Smallmovement
#if USE_REFLECTION
uniform sampler2D reflectionMap;
#endif
uniform sampler2D reflectionMap;
#if USE_REFRACTION
uniform sampler2D refractionMap;
#endif
@ -98,17 +104,6 @@ float IntersectBox (in Ray ray, in vec3 minimum, in vec3 maximum)
vec3 MAX = max ( OMAX, OMIN );
return min ( MAX.x, min ( MAX.y, MAX.z ) );
}
// This is sorta useless since it's hardcoded for 45°. Change it to sun orientation too.
mat3 rotationMatrix()
{
vec3 axis = vec3(0.0,1.0,0.0);
float s = sin(1.12);
float c = cos(1.12);
return mat3(c, 0.0, s,
0.0, 1.0, 0.0,
-s, 0.0, c);
}
vec3 get_fog(vec3 color)
{
@ -128,7 +123,7 @@ vec3 get_fog(vec3 color)
void main()
{
//gl_FragColor = vec4(waterInfo.rrr,1.0);
//gl_FragColor = texture2D(waterEffectsTex, gl_FragCoord.xy/screenSize);
//return;
float fresnel;
@ -141,14 +136,8 @@ void main()
vec3 v = normalize(cameraPos - worldPos);
vec3 h = normalize(l + v);
// Fix the waviness for local wind strength
float fwaviness = waviness * ((0.15+waterInfo.r/1.15));
// Calculate water normals.
#if USE_FANCY_EFFECTS
vec4 fancyeffects = texture2D(waterEffectsTex, gl_FragCoord.xy/screenSize);
vec3 n = (fancyeffects.rgb-0.5)*2.0;
#else
float wavyEffect = waveParams1.r;
float baseScale = waveParams1.g;
float flattenism = waveParams1.b;
@ -159,29 +148,45 @@ void main()
float BigMovement = waveParams2.b;
float SmallMovement = waveParams2.a;
float moddedTime = mod(time * 60.0, 8.0) / 8.0;
// This method uses 60 animated water frames. We're blending between each two frames
// TODO: could probably have fewer frames thanks to this blending.
// Scale the normal textures by waviness so that big waviness means bigger waves.
vec3 ww1 = texture2D(normalMap, (gl_TexCoord[0].st + gl_TexCoord[0].zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).xzy;
vec3 ww2 = texture2D(normalMap2, (gl_TexCoord[0].st + gl_TexCoord[0].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;
#if USE_SUPERNORMAL
vec3 smallWW = texture2D(normalMap, (gl_TexCoord[0].st + gl_TexCoord[0].zw * SmallMovement*waviness/10.0) * baseScale*3.0).xzy;
vec3 smallWW2 = texture2D(normalMap2, (gl_TexCoord[0].st + gl_TexCoord[0].zw * SmallMovement*waviness/10.0) * baseScale*3.0).xzy;
vec3 smallWWInterp = mix(smallWW, smallWW2, moddedTime) - vec3(0.5,0.0,0.5);
ww1 = mix(ww1, ww2, mod(time * 60.0, 8.0) / 8.0);
smallWW = mix(smallWW, smallWW2, mod(time * 60.0, 8.0) / 8.0) - vec3(0.5);
ww1 += vec3(smallWW.x,0.0,smallWW.z)*(fwaviness/10.0*smallIntensity + smallBase);
smallWW.x = smallWWInterp.x * WindCosSin.x - smallWWInterp.z * WindCosSin.y;
smallWW.z = smallWWInterp.x * WindCosSin.y + smallWWInterp.z * WindCosSin.x;
smallWW.y = smallWWInterp.y;
ww1 = mix(smallWW + vec3(0.5,0.0,0.5), ww1, waterInfo.r);
ww1 += vec3(smallWW)*(fwaviness/10.0*smallIntensity + smallBase);
// Flatten them based on waviness.
vec3 n = normalize(mix(vec3(0.0,1.0,0.0),ww1 - vec3(0.5,0.0,0.5), clamp(baseBump + fwaviness/flattenism,0.0,1.0)));
// Fix our normals.
//n = normalize(n - vec3(0.5, 0.5, 0.5));
ww1 = mix(smallWW, ww1, waterInfo.r);
#endif
// Flatten them based on waviness.
vec3 n = normalize(mix(vec3(0.0,1.0,0.0),ww1, clamp(baseBump + fwaviness/flattenism,0.0,1.0)));
n = mix(vec3(0.0,1.0,0.0), n,0.5 + waterInfo.r/2.0);
#if USE_FANCY_EFFECTS
vec4 fancyeffects = texture2D(waterEffectsTexNorm, gl_FragCoord.xy/screenSize);
n = mix(vec3(0.0,1.0,0.0), n,0.5 + waterInfo.r/2.0);
n.xz = mix(n.xz, fancyeffects.rb,fancyeffects.a/2.0);
#else
n = mix(vec3(0.0,1.0,0.0), n,0.5 + waterInfo.r/2.0);
#endif
n = vec3(-n.x,n.y,-n.z);
// simulates how parallel the "point->sun", "view->point" vectors are.
float ndoth = dot(n , h);
@ -225,7 +230,11 @@ void main()
#else
depth = waterDepth / (min(0.5,v.y)*1.5*min(0.5,v.y)*2.0);
#endif
#if USE_FANCY_EFFECTS
depth = max(depth,fancyeffects.a);
#endif
// Fresnel for "how much reflection vs how much refraction".
// Since we're not trying to simulate a realistic ocean 100%, aim for something that gives a little too much reflection
// because we're not used to seeing the see from above.
@ -233,7 +242,7 @@ void main()
// multiply by v.y so that in the distance refraction wins.
// TODO: this is a hack because reflections don't work in the distance.
fresnel *= min(1.0,log(1.0 + v.y*5.0));
fresnel = 0.2 + fresnel * 0.8;
fresnel = 0.1 + fresnel * 0.8;
//gl_FragColor = vec4(fresnel,fresnel,fresnel,1.0);
//return;
@ -244,7 +253,7 @@ void main()
// 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 = clamp(v.y,0.1,1.0);
float fixedVy = max(v.y,0.1);
float distoFactor = clamp(depth/2.0,0.0,7.0);
@ -282,30 +291,33 @@ void main()
refrColor = color;
#endif
#if USE_REFLECTION
// Reflections
vec3 eye = reflect(v,n);
//eye.y = min(-0.2,eye.y);
// let's calculate where we intersect with the skycube.
Ray myRay = Ray(vec3(worldPos.x/4.0,worldPos.y,worldPos.z/4.0),eye);
vec3 start = vec3(-1500.0 + mapSize/2.0,-100.0,-1500.0 + mapSize/2.0);
vec3 end = vec3(1500.0 + mapSize/2.0,500.0,1500.0 + mapSize/2.0);
float tmin = IntersectBox(myRay,start,end);
vec3 newpos = vec3(-worldPos.x/4.0,worldPos.y,-worldPos.z/4.0) + eye * tmin - vec3(-mapSize/2.0,worldPos.y,-mapSize/2.0);
//newpos = normalize(newpos);
newpos.y *= 6.0;
newpos *= rotationMatrix();
reflColor = textureCube(skyCube, newpos).rgb;
//float disttt = distance(worldPos,cameraPos);
//tex = mix(tex,vec3(0.7,0.7,0.9),clamp(disttt/300.0*disttt/300.0*disttt/300.0,0.0,0.9));
//gl_FragColor = vec4(clamp(disttt/300.0*disttt/300.0,0.0,1.0),clamp(disttt/300.0*disttt/300.0,0.0,1.0),clamp(disttt/300.0*disttt/300.0,0.0,1.0),1.0);
//return;
reflCoords = clamp( (0.5*gl_TexCoord[1].xy - waviness * mix(4.0, 1.0,waviness/10.0) * n.zx) / gl_TexCoord[1].w + 0.5,0.0,1.0); // Unbias texture coords
vec4 refTex = texture2D(reflectionMap, reflCoords);
reflColor = refTex.rgb * refTex.a + reflColor*(1.0-refTex.a);
#endif
#if USE_REFLECTION
// Reflections
vec3 eye = reflect(v,n);
//eye.y = min(-0.2,eye.y);
// let's calculate where we intersect with the skycube.
Ray myRay = Ray(vec3(worldPos.x/4.0,worldPos.y,worldPos.z/4.0),eye);
vec3 start = vec3(-1500.0 + mapSize/2.0,-100.0,-1500.0 + mapSize/2.0);
vec3 end = vec3(1500.0 + mapSize/2.0,500.0,1500.0 + mapSize/2.0);
float tmin = IntersectBox(myRay,start,end);
vec4 newpos = vec4(-worldPos.x/4.0,worldPos.y,-worldPos.z/4.0,1.0) + vec4(eye * tmin,0.0) - vec4(-mapSize/2.0,worldPos.y,-mapSize/2.0,0.0);
//newpos = normalize(newpos);
newpos *= skyBoxRot;
newpos.y *= 4.0;
reflColor = textureCube(skyCube, newpos.rgb).rgb;
//float disttt = distance(worldPos,cameraPos);
//tex = mix(tex,vec3(0.7,0.7,0.9),clamp(disttt/300.0*disttt/300.0*disttt/300.0,0.0,0.9));
//gl_FragColor = vec4(clamp(disttt/300.0*disttt/300.0,0.0,1.0),clamp(disttt/300.0*disttt/300.0,0.0,1.0),clamp(disttt/300.0*disttt/300.0,0.0,1.0),1.0);
//return;
reflCoords = clamp( (0.5*gl_TexCoord[1].xy - waviness * mix(1.0, 4.0,waviness/10.0) * n.zx) / gl_TexCoord[1].w + 0.5,0.0,1.0); // Unbias texture coords
vec4 refTex = texture2D(reflectionMap, reflCoords);
reflColor = refTex.rgb * refTex.a + reflColor*(1.0-refTex.a);
#else
reflCoords = clamp( (0.5*gl_TexCoord[1].xy - waviness * mix(1.0, 20.0,waviness/10.0) * n.zx) / gl_TexCoord[1].w + 0.5,0.0,1.0); // Unbias texture coords
vec3 refTex = texture2D(reflectionMap, reflCoords).rgb;
reflColor = refTex.rgb;
#endif
// TODO: At very low angles the reflection stuff doesn't really work any more:
// IRL you would get a blur of the sky, but we don't have that precision (would require mad oversampling)
@ -323,18 +335,18 @@ void main()
losMod = texture2D(losMap, gl_TexCoord[3].st).a;
losMod = losMod < 0.03 ? 0.0 : losMod;
float wavesFresnel = 1.0;
#if USE_FANCY_EFFECTS
wavesFresnel = mix(1.0-fancyeffects.a,1.0,clamp(depth,0.0,1.0));
#endif
vec3 colour;
#if USE_SHADOWS_ON_WATER && USE_SHADOW
float fresShadow = mix(fresnel, fresnel*shadow, 0.05 + murkiness*0.2);
/* #if USE_FOAM
colour = mix(refrColor, reflColor, fresShadow) + max(ndotl,0.4)*(finalFoam)*(shadow/2.0 + 0.5);
#else*/
colour = mix(refrColor, reflColor, fresShadow);
colour = mix(refrColor, reflColor, fresShadow * wavesFresnel);
#else
/*#if USE_FOAM
colour = mix(refrColor, reflColor, fresnel) + max(ndotl,0.4)*(finalFoam);
#else*/
colour = mix(refrColor, reflColor, fresnel);
colour = mix(refrColor, reflColor, fresnel * wavesFresnel);
#endif
#if USE_SHADOWS_ON_WATER && USE_SHADOW
@ -343,9 +355,23 @@ void main()
colour += specular;
#endif
// TODO: work the foam in somewhere else.
#if USE_FANCY_EFFECTS
gl_FragColor.rgb = get_fog(colour) * losMod + fancyeffects.a * losMod;
vec4 FoamEffects = texture2D(waterEffectsTexOther, gl_FragCoord.xy/screenSize);
vec3 foam1 = texture2D(normalMap, (gl_TexCoord[0].st + gl_TexCoord[0].zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).aaa;
vec3 foam2 = texture2D(normalMap2, (gl_TexCoord[0].st + gl_TexCoord[0].zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).aaa;
vec3 foam3 = texture2D(normalMap, gl_TexCoord[0].st/6.0 - gl_TexCoord[0].zw * 0.02).aaa;
vec3 foam4 = texture2D(normalMap2, gl_TexCoord[0].st/6.0 - gl_TexCoord[0].zw * 0.02).aaa;
vec3 foaminterp = mix(foam1, foam2, moddedTime);
foaminterp *= mix(foam3, foam4, moddedTime);
foam1.x = foaminterp.x * WindCosSin.x - foaminterp.z * WindCosSin.y;
//foam1.z = foaminterp.x * WindCosSin.y + foaminterp.z * WindCosSin.x;
//foam1.y = foaminterp.y;
float foam = FoamEffects.r * FoamEffects.a*0.4 + pow(foam1.x*(5.0+waviness),(2.6 - waviness/5.5));
foam *= ndotl;
gl_FragColor.rgb = get_fog(colour) * losMod + foam * losMod;// + fancyeffects.a * losMod;
#else
gl_FragColor.rgb = get_fog(colour) * losMod;
#endif
@ -353,6 +379,13 @@ void main()
#if !USE_REFRACTION
gl_FragColor.a = clamp(depth*2.0,0.0,1.0) * alphaCoeff;
#else
gl_FragColor.a = clamp(depth*5.0 + n.x * 5.0,0.0,1.0);
gl_FragColor.a = clamp(depth*5.0,0.0,1.0);
#endif
#if USE_FANCY_EFFECTS
if (fancyeffects.a < 0.05 && waterDepth < -1.0 )
gl_FragColor.a = 0.0;
#endif
//gl_FragColor = vec4(sunColor,1.0);
}

View File

@ -7,6 +7,7 @@ uniform mat4 shadowTransform;
uniform float repeatScale;
uniform float windAngle;
uniform float waviness; // "Wildness" of the reflections and refractions; choose based on texture
uniform vec3 sunDir;
#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF
uniform vec4 shadowScale;
@ -15,23 +16,33 @@ uniform float waviness; // "Wildness" of the reflections and refractions; choo
uniform float time;
uniform float mapSize;
uniform mat4 transform;
varying vec3 worldPos;
varying float waterDepth;
varying vec4 waterInfo;
varying vec2 waterInfo;
varying float fwaviness;
varying vec2 WindCosSin;
#if USE_SHADOW && USE_SHADOWS_ON_WATER
varying vec4 v_shadow;
#endif
attribute vec3 a_vertex;
attribute vec4 a_waterInfo;
attribute vec2 a_waterInfo;
attribute vec3 a_otherPosition;
void main()
{
worldPos = a_vertex;
worldPos = vec3(a_vertex.x,15.0,a_vertex.z);
waterInfo = a_waterInfo;
waterDepth = a_waterInfo.a;
waterDepth = a_waterInfo.g;
float newX = a_vertex.x * cos(-windAngle) - a_vertex.z * sin(-windAngle);
float newY = a_vertex.x * sin(-windAngle) + a_vertex.z * cos(-windAngle);
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;
gl_TexCoord[0] = vec4(newX,newY,time,0.0);
gl_TexCoord[0].xy *= repeatScale;
@ -48,5 +59,8 @@ void main()
#endif
#endif
gl_Position = gl_ModelViewProjectionMatrix * vec4(a_vertex, 1.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);
}

View File

@ -0,0 +1,43 @@
#version 110
uniform sampler2D waveTex;
uniform sampler2D foamTex;
uniform float translation;
uniform float width;
varying float ttime;
varying vec2 normal;
void main()
{
vec4 Tex = texture2D(waveTex, -gl_TexCoord[0].xy/8.0).rbga;
Tex.rgb -= vec3(0.5,0.0,0.5);
Tex.rb *= -1.0;
float halfwidth = (width-1.0) / 2.0;
float forceAlpha = min(1.0,2.0-abs(gl_TexCoord[0].x-halfwidth)/(halfwidth/2.0));
float val = min(1.0,gl_TexCoord[0].y);
forceAlpha *= val;
float timeAlpha = 1.0 - clamp((ttime - 6.0)/4.0,0.0,1.0);
timeAlpha *= clamp(ttime/2.0,0.0,1.0);
float foamAlpha = Tex.a * forceAlpha * timeAlpha;
Tex.a = forceAlpha * timeAlpha;
vec2 norm = Tex.rb;
Tex.r = norm.x * normal.x - norm.y * normal.x;
Tex.b = norm.x * normal.y + norm.y * normal.y;
vec3 foam = texture2D(foamTex, -gl_TexCoord[0].xy/vec2(2.5,7.0) + vec2(0.05,-0.3)*-cos(ttime/2.0)).rbg;
foam *= texture2D(foamTex, -gl_TexCoord[0].xy/5.0 + vec2(0.8,-0.8) + vec2(-0.05,-0.25)*-cos(ttime/2.0)*1.2).rbg;
gl_FragData[0] = vec4(Tex);
gl_FragData[1] = vec4(foam*3.0,foamAlpha);
return;
}

View File

@ -0,0 +1,34 @@
#version 110
attribute vec2 a_uv0;
attribute vec2 a_normal;
attribute vec3 a_basePosition;
attribute vec3 a_apexPosition;
attribute vec3 a_splashPosition;
attribute vec3 a_retreatPosition;
uniform float time;
uniform float translation;
uniform float width;
uniform mat4 transform;
varying float ttime;
varying vec2 normal;
void main()
{
normal = a_normal;
gl_TexCoord[0].xy = a_uv0.xy;
float tttime = mod(time + translation ,10.0);
ttime = tttime;
vec3 pos = mix(a_basePosition,a_apexPosition, clamp(ttime/3.0,0.0,1.0));
pos = mix (pos, a_splashPosition, clamp(sin((min(ttime,6.1415926536)-3.0)/2.0),0.0,1.0));
pos = mix (pos, a_retreatPosition, clamp( 1.0 - cos(max(0.0,ttime-6.1415926536)/2.0) ,0.0,1.0));
gl_Position = transform * vec4(pos, 1.0);
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<program type="glsl">
<vertex file="glsl/waves.vs">
<stream name="pos"/>
<stream name="uv0"/>
<attrib name="a_basePosition" semantics="gl_Vertex"/>
<attrib name="a_apexPosition" semantics="CustomAttribute0"/>
<attrib name="a_splashPosition" semantics="CustomAttribute1"/>
<attrib name="a_retreatPosition" semantics="CustomAttribute2"/>
<attrib name="a_normal" semantics="gl_Normal"/>
<attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
</vertex>
<fragment file="glsl/waves.fs"/>
</program>

View File

@ -37,7 +37,6 @@ X(BLOOM_PASS_H)
X(BLOOM_PASS_V)
X(DECAL)
X(DISABLE_RECEIVE_SHADOWS)
X(Foam)
X(IGNORE_LOS)
X(MINIMAP_BASE)
X(MINIMAP_LINE)
@ -60,14 +59,18 @@ X(USE_REAL_DEPTH)
X(USE_REFLECTION)
X(USE_REFRACTION)
X(USE_SHADOW)
X(USE_SHADOWS_ON_WATER)
X(USE_SHADOW_PCF)
X(USE_SHADOW_SAMPLER)
X(USE_SHADOWS_ON_WATER)
X(WATERTYPE_CLAP)
X(WATERTYPE_LAKE)
X2(_emptystring, "")
X(a_apexPosition)
X(a_otherPosition)
X(a_skinJoints)
X(a_skinWeights)
X(a_retreatPosition)
X(a_splashPosition)
X(a_tangent)
X(a_waterInfo)
X(ambient)
@ -84,6 +87,7 @@ X(colorAdd)
X(colorMul)
X(delta)
X(depthTex)
X(foamTex)
X(fogColor)
X(fogParams)
X(foreground_overlay)
@ -106,7 +110,6 @@ X(mapSize)
X(maskTex)
X(minimap)
X(murkiness)
X(windAngle)
X(normalMap)
X(normalMap2)
X(objectColor)
@ -130,6 +133,7 @@ X(shadowTex)
X(shadowTransform)
X(skinBlendMatrices)
X2(skinBlendMatrices_0, "skinBlendMatrices[0]")
X(skyBoxRot)
X(skyCube)
X(sky_simple)
X(sunColor)
@ -141,11 +145,14 @@ X(time)
X(tint)
X(transform)
X(translation)
X(waterEffectsTexNorm)
X(waterEffectsTexOther)
X(waterTex)
X(waterEffectsTex)
X(waveTex)
X(waviness)
X(waveParams1)
X(waveParams2)
X(width)
X(windAngle)
X(zFar)
X(zNear)

View File

@ -64,6 +64,7 @@ CPatchRData::CPatchRData(CPatch* patch, CSimulation2* simulation) :
m_VBBase(0), m_VBBaseIndices(0),
m_VBBlends(0), m_VBBlendIndices(0),
m_VBWater(0), m_VBWaterIndices(0),
m_VBWaterShore(0), m_VBWaterIndicesShore(0),
m_Simulation(simulation)
{
ENSURE(patch);
@ -82,6 +83,8 @@ CPatchRData::~CPatchRData()
if (m_VBBlendIndices) g_VBMan.Release(m_VBBlendIndices);
if (m_VBWater) g_VBMan.Release(m_VBWater);
if (m_VBWaterIndices) g_VBMan.Release(m_VBWaterIndices);
if (m_VBWaterShore) g_VBMan.Release(m_VBWaterShore);
if (m_VBWaterIndicesShore) g_VBMan.Release(m_VBWaterIndicesShore);
}
/**
@ -1288,6 +1291,16 @@ void CPatchRData::BuildWater()
g_VBMan.Release(m_VBWaterIndices);
m_VBWaterIndices = 0;
}
if (m_VBWaterShore)
{
g_VBMan.Release(m_VBWaterShore);
m_VBWaterShore = 0;
}
if (m_VBWaterIndicesShore)
{
g_VBMan.Release(m_VBWaterIndicesShore);
m_VBWaterIndicesShore = 0;
}
m_WaterBounds.SetEmpty();
// We need to use this to access the water manager or we may not have the
@ -1302,14 +1315,14 @@ void CPatchRData::BuildWater()
u16 water_index_map[PATCH_SIZE+1][PATCH_SIZE+1];
memset(water_index_map, 0xFF, sizeof(water_index_map));
// TODO: This is not (yet) exported via the ICmp interface so... we stick to these values which can be compiled in defaults
// Build data for shore
std::vector<SWaterVertex> water_vertex_data_shore;
std::vector<GLushort> water_indices_shore;
u16 water_shore_index_map[PATCH_SIZE+1][PATCH_SIZE+1];
memset(water_shore_index_map, 0xFF, sizeof(water_shore_index_map));
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
/*if (WaterMgr->m_NeedInfoUpdate)
{
WaterMgr->m_NeedInfoUpdate = false;
WaterMgr->CreateSuperfancyInfo(m_Simulation);
}*/
CPatch* patch = m_Patch;
CTerrain* terrain = patch->m_Parent;
@ -1322,7 +1335,10 @@ void CPatchRData::BuildWater()
// to whoever implements different water heights, this is a TODO: water height)
float waterHeight = cmpWaterManager->GetExactWaterLevel(0.0f,0.0f);
// The 4 points making a water tile.
int moves[4][2] = { {0,0}, {water_cell_size,0}, {0,water_cell_size}, {water_cell_size,water_cell_size} };
// Where to look for when checking for water for shore tiles.
int check[10][2] = { {0,0},{water_cell_size,0},{water_cell_size*2,0},{0,water_cell_size},{0,water_cell_size*2},{water_cell_size,water_cell_size},{water_cell_size*2,water_cell_size*2}, {-water_cell_size,0}, {0,-water_cell_size}, {-water_cell_size,-water_cell_size} };
// build vertices, uv, and shader varying
for (ssize_t z = 0; z < PATCH_SIZE; z += water_cell_size)
@ -1330,11 +1346,12 @@ void CPatchRData::BuildWater()
for (ssize_t x = 0; x < PATCH_SIZE; x += water_cell_size)
{
// Check that this tile has at least one vertice underwater.
if (terrain->GetVertexGroundLevel(x+x1, z+z1) >= waterHeight
&& terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) >= waterHeight
&& terrain->GetVertexGroundLevel(x+x1 + water_cell_size, z+z1) >= waterHeight
&& terrain->GetVertexGroundLevel(x+x1 + water_cell_size, z+z1 + water_cell_size) >= waterHeight)
// Check that this tile is close to water
bool nearWat = false;
for (size_t test = 0; test < 10; ++test)
if (terrain->GetVertexGroundLevel(x+x1+check[test][0], z+z1+check[test][1]) < waterHeight)
nearWat = true;
if (!nearWat)
continue;
// This is actually lying and I should call CcmpTerrain
@ -1344,164 +1361,145 @@ void CPatchRData::BuildWater()
&& !terrain->IsOnMap(x+x1 + water_cell_size, z+z1 + water_cell_size))
continue;*/
// Figure out our points. We might want to draw only one of two triangles per tile.
// In order: the one on the diagonal on top, the one of the diagonal on bottom, other on top, other on bottom.
// The numbers refer to "moves" above. -1 means "not rendering".
// by default the diagonal is the "x,z->x+1,z+1" one.
int points[4] = { 0, 3, 1, 2 };
// If the other diagonal is over water completely, that means we have the wrong diagonal.
if (terrain->GetVertexGroundLevel(x+x1 + water_cell_size, z+z1) >= waterHeight
&& terrain->GetVertexGroundLevel(x+x1, z+z1 + water_cell_size) >= waterHeight)
{
points[0] = 1; points[1] = 2; points[2] = 0; points[3] = 3;
}
// check if the diagonal is completely out of the water, and if so, check which triangles we want to render (1 or 2)
if (terrain->GetVertexGroundLevel(x+x1 + moves[points[0]][0], z+z1 + moves[points[0]][1]) >= waterHeight
&& terrain->GetVertexGroundLevel(x+x1 + moves[points[1]][0], z+z1 + moves[points[1]][1]) >= waterHeight)
{
if (terrain->GetVertexGroundLevel(x+x1 + moves[points[2]][0], z+z1 + moves[points[2]][1]) >= waterHeight)
points[2] = -1;
else if (terrain->GetVertexGroundLevel(x+x1 + moves[points[3]][0], z+z1 + moves[points[3]][1]) >= waterHeight)
points[3] = -1;
}
// Compute data.
for (int i = 0; i < 4; ++i)
{
if (points[i] == -1)
if (water_index_map[z+moves[i][1]][x+moves[i][0]] != 0xFFFF)
continue;
// Check if we already computed this vertex from an earlier strip
if (water_index_map[z+moves[points[i]][1]][x+moves[points[i]][0]] != 0xFFFF)
continue;
ssize_t zz = z+z1+moves[points[i]][1];
ssize_t xx = x+x1+moves[points[i]][0];
ssize_t zz = z+z1+moves[i][1];
ssize_t xx = x+x1+moves[i][0];
SWaterVertex vertex;
terrain->CalcPosition(xx,zz, vertex.m_Position);
float depth = waterHeight - vertex.m_Position.Y;
// Try and get the point on the shore if it's over water.
// In some cases this won't be possible.
if (depth < 0.0f)
{
float temp = 0.0f;
float left_t = 0.0f,right_t = 0.0f,top_t = 0.0f,bottom_t = 0.0f;
if (xx > 0)
{
temp = terrain->GetVertexGroundLevel(xx-1,zz);
if (temp < waterHeight)
left_t = 1.0f-(temp-waterHeight)/(temp-vertex.m_Position.Y);
}
if (xx < mapSize - 1)
{
temp = terrain->GetVertexGroundLevel(xx+1,zz);
if (temp < waterHeight)
right_t = 1.0f-(temp-waterHeight)/(temp-vertex.m_Position.Y);
}
if (zz > 0)
{
temp = terrain->GetVertexGroundLevel(xx,zz-1);
if (temp < waterHeight)
top_t = 1.0f-(temp-waterHeight)/(temp-vertex.m_Position.Y);
}
if (zz < mapSize - 1)
{
temp = terrain->GetVertexGroundLevel(xx,zz-1);
if (temp < waterHeight)
bottom_t = 1.0f-(temp-waterHeight)/(temp-vertex.m_Position.Y);
}
vertex.m_Position.X = vertex.m_Position.X + 4.0 * (right_t - left_t);
vertex.m_Position.Z = vertex.m_Position.Z + 4.0 * (bottom_t - top_t);
}
vertex.m_Position.Y = waterHeight;
m_WaterBounds += vertex.m_Position;
vertex.m_WaterData = CVector4D(WaterMgr->m_WindStrength[xx + zz*mapSize],
0.0f,
WaterMgr->m_DistanceHeightmap[xx + zz*mapSize],
depth);
vertex.m_WaterData = CVector2D(WaterMgr->m_WindStrength[xx + zz*mapSize], depth);
water_index_map[z+moves[points[i]][1]][x+moves[points[i]][0]] = water_vertex_data.size();
water_index_map[z+moves[i][1]][x+moves[i][0]] = water_vertex_data.size();
water_vertex_data.push_back(vertex);
}
// Render them.
if (points[2] == 0) // Top point is wanted, render corresponding triangle
water_indices.push_back(water_index_map[z + moves[2][1]][x + moves[2][0]]);
water_indices.push_back(water_index_map[z + moves[0][1]][x + moves[0][0]]);
water_indices.push_back(water_index_map[z + moves[1][1]][x + moves[1][0]]);
water_indices.push_back(water_index_map[z + moves[1][1]][x + moves[1][0]]);
water_indices.push_back(water_index_map[z + moves[3][1]][x + moves[3][0]]);
water_indices.push_back(water_index_map[z + moves[2][1]][x + moves[2][0]]);
// Check id this tile is partly over land.
// If so add a square over the terrain. This is necessary to render waves that go on shore.
if (terrain->GetVertexGroundLevel(x+x1, z+z1) < waterHeight
&& terrain->GetVertexGroundLevel(x+x1 + water_cell_size, z+z1) < waterHeight
&& terrain->GetVertexGroundLevel(x+x1, z+z1+water_cell_size) < waterHeight
&& terrain->GetVertexGroundLevel(x+x1 + water_cell_size, z+z1+water_cell_size) < waterHeight)
continue;
for (int i = 0; i < 4; ++i)
{
water_indices.push_back(water_index_map[z + moves[points[1]][1]][x + moves[points[1]][0]]);
water_indices.push_back(water_index_map[z + moves[points[2]][1]][x + moves[points[2]][0]]);
water_indices.push_back(water_index_map[z + moves[points[0]][1]][x + moves[points[0]][0]]);
if (water_shore_index_map[z+moves[i][1]][x+moves[i][0]] != 0xFFFF)
continue;
ssize_t zz = z+z1+moves[i][1];
ssize_t xx = x+x1+moves[i][0];
SWaterVertex vertex;
terrain->CalcPosition(xx,zz, vertex.m_Position);
vertex.m_Position.Y += 0.02f;
m_WaterBounds += vertex.m_Position;
vertex.m_WaterData = CVector2D(0.0f, -5.0f);
water_shore_index_map[z+moves[i][1]][x+moves[i][0]] = water_vertex_data_shore.size();
water_vertex_data_shore.push_back(vertex);
}
else if (points[2] == 1)
if (terrain->GetTriangulationDir(x+x1,z+z1))
{
water_indices.push_back(water_index_map[z + moves[points[1]][1]][x + moves[points[1]][0]]);
water_indices.push_back(water_index_map[z + moves[points[0]][1]][x + moves[points[0]][0]]);
water_indices.push_back(water_index_map[z + moves[points[2]][1]][x + moves[points[2]][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[2][1]][x + moves[2][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[0][1]][x + moves[0][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[1][1]][x + moves[1][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[1][1]][x + moves[1][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[3][1]][x + moves[3][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[2][1]][x + moves[2][0]]);
}
if (points[3] == 3) // Bottom point is wanted, render corresponding triangle.
else
{
water_indices.push_back(water_index_map[z + moves[points[1]][1]][x + moves[points[1]][0]]);
water_indices.push_back(water_index_map[z + moves[points[0]][1]][x + moves[points[0]][0]]);
water_indices.push_back(water_index_map[z + moves[points[3]][1]][x + moves[points[3]][0]]);
}
else if (points[3] == 2)
{
water_indices.push_back(water_index_map[z + moves[points[1]][1]][x + moves[points[1]][0]]);
water_indices.push_back(water_index_map[z + moves[points[3]][1]][x + moves[points[3]][0]]);
water_indices.push_back(water_index_map[z + moves[points[0]][1]][x + moves[points[0]][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[3][1]][x + moves[3][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[2][1]][x + moves[2][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[0][1]][x + moves[0][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[3][1]][x + moves[3][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[0][1]][x + moves[0][0]]);
water_indices_shore.push_back(water_shore_index_map[z + moves[1][1]][x + moves[1][0]]);
}
}
}
// no vertex buffers if no data generated
if (water_indices.size() == 0)
return;
if (water_indices.size() != 0)
{
m_VBWater = g_VBMan.Allocate(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater, &water_vertex_data[0]);
m_VBWaterIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices, &water_indices[0]);
}
// allocate vertex buffer
m_VBWater = g_VBMan.Allocate(sizeof(SWaterVertex), water_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
m_VBWater->m_Owner->UpdateChunkVertices(m_VBWater, &water_vertex_data[0]);
if (water_indices_shore.size() != 0)
{
m_VBWaterShore = g_VBMan.Allocate(sizeof(SWaterVertex), water_vertex_data_shore.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
m_VBWaterShore->m_Owner->UpdateChunkVertices(m_VBWaterShore, &water_vertex_data_shore[0]);
// Construct indices buffer
m_VBWaterIndicesShore = g_VBMan.Allocate(sizeof(GLushort), water_indices_shore.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
m_VBWaterIndicesShore->m_Owner->UpdateChunkVertices(m_VBWaterIndicesShore, &water_indices_shore[0]);
}}
// Construct indices buffer
m_VBWaterIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
m_VBWaterIndices->m_Owner->UpdateChunkVertices(m_VBWaterIndices, &water_indices[0]);
}
void CPatchRData::RenderWater(CShaderProgramPtr& shader, bool fixedPipeline)
void CPatchRData::RenderWater(CShaderProgramPtr& shader, bool onlyShore, bool fixedPipeline)
{
ASSERT(m_UpdateFlags==0);
if (!m_VBWater)
if (g_Renderer.m_SkipSubmit || (!m_VBWater && !m_VBWaterShore))
return;
SWaterVertex *base=(SWaterVertex *)m_VBWater->m_Owner->Bind();
// This is debug code. If it ends up in SVN, remove it.
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// setup data pointers
GLsizei stride = sizeof(SWaterVertex);
shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_Position);
if (!fixedPipeline)
shader->VertexAttribPointer(str_a_waterInfo, 4, GL_FLOAT, false, stride, &base[m_VBWater->m_Index].m_WaterData);
shader->AssertPointersBound();
// render
if (!g_Renderer.m_SkipSubmit)
if (m_VBWater != 0x0 && !onlyShore)
{
SWaterVertex *base=(SWaterVertex *)m_VBWater->m_Owner->Bind();
// setup data pointers
GLsizei stride = sizeof(SWaterVertex);
shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWater->m_Index].m_Position);
if (!fixedPipeline)
shader->VertexAttribPointer(str_a_waterInfo, 2, GL_FLOAT, false, stride, &base[m_VBWater->m_Index].m_WaterData);
shader->AssertPointersBound();
u8* indexBase = m_VBWaterIndices->m_Owner->Bind();
glDrawElements(GL_TRIANGLES, (GLsizei) m_VBWaterIndices->m_Count,
GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndices->m_Index));
GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndices->m_Index));
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 3;
}
if (m_VBWaterShore != 0x0 && g_Renderer.GetWaterManager()->m_WaterFancyEffects && !g_Renderer.GetWaterManager()->m_WaterUgly)
{
SWaterVertex *base=(SWaterVertex *)m_VBWaterShore->m_Owner->Bind();
GLsizei stride = sizeof(SWaterVertex);
shader->VertexPointer(3, GL_FLOAT, stride, &base[m_VBWaterShore->m_Index].m_Position);
if (!fixedPipeline)
shader->VertexAttribPointer(str_a_waterInfo, 2, GL_FLOAT, false, stride, &base[m_VBWaterShore->m_Index].m_WaterData);
shader->AssertPointersBound();
u8* indexBase = m_VBWaterIndicesShore->m_Owner->Bind();
glDrawElements(GL_TRIANGLES, (GLsizei) m_VBWaterIndicesShore->m_Count,
GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_VBWaterIndicesShore->m_Index));
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndicesShore->m_Count / 3;
}
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// bump stats
g_Renderer.m_Stats.m_DrawCalls++;
g_Renderer.m_Stats.m_WaterTris += m_VBWaterIndices->m_Count / 2;
CVertexBuffer::Unbind();
}

View File

@ -21,6 +21,7 @@
#include <vector>
#include "graphics/SColor.h"
#include "maths/Vector3D.h"
#include "maths/Vector2D.h"
#include "graphics/RenderableObject.h"
#include "graphics/ShaderProgramPtr.h"
#include "VertexBufferManager.h"
@ -45,7 +46,7 @@ public:
void RenderSides(CShaderProgramPtr& shader);
void RenderPriorities(CTextRenderer& textRenderer);
void RenderWater(CShaderProgramPtr& shader, bool fixedPipeline = false);
void RenderWater(CShaderProgramPtr& shader, bool onlyShore = false, bool fixedPipeline = false);
static void RenderBases(const std::vector<CPatchRData*>& patches, const CShaderDefines& context,
ShadowMap* shadow, bool isDummyShader=false, const CShaderProgramPtr& dummy=CShaderProgramPtr());
@ -105,9 +106,9 @@ private:
struct SWaterVertex {
// vertex position
CVector3D m_Position;
CVector4D m_WaterData;
CVector2D m_WaterData;
};
cassert(sizeof(SWaterVertex) == 28);
cassert(sizeof(SWaterVertex) == 20);
// build this renderdata object
void Build();
@ -151,9 +152,11 @@ private:
// Water vertex buffer
CVertexBuffer::VBChunk* m_VBWater;
CVertexBuffer::VBChunk* m_VBWaterShore;
// Water indices buffer
CVertexBuffer::VBChunk* m_VBWaterIndices;
CVertexBuffer::VBChunk* m_VBWaterIndicesShore;
CSimulation2* m_Simulation;

View File

@ -1158,14 +1158,11 @@ void CRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAlign
CMatrix3D scaleMat;
scaleMat.SetScaling(m_Height/float(std::max(1, m_Width)), 1.0f, 1.0f);
camera.m_ProjMat = scaleMat * camera.m_ProjMat;
CVector4D camPlane(0, -1, 0, wm.m_WaterHeight + 0.5f);
SetObliqueFrustumClipping(camera, camPlane);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// RenderReflections: render the water reflections to the reflection texture
SScreenRect CRenderer::RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor)
void CRenderer::RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor)
{
PROFILE3_GPU("water reflections");
@ -1202,19 +1199,24 @@ SScreenRect CRenderer::RenderReflections(const CShaderDefines& context, const CB
glClearColor(0.5f,0.5f,1.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFrontFace(GL_CW);
// Render sky, terrain and models
//m->skyManager.RenderSky();
//ogl_WarnIfError();
RenderPatches(context, CULL_REFLECTIONS);
ogl_WarnIfError();
RenderModels(context, CULL_REFLECTIONS);
ogl_WarnIfError();
RenderTransparentModels(context, CULL_REFLECTIONS, TRANSPARENT, true);
ogl_WarnIfError();
if (!m_Options.m_WaterReflection)
{
m->skyManager.RenderSky();
ogl_WarnIfError();
}
else
{
// Render terrain and models
RenderPatches(context, CULL_REFLECTIONS);
ogl_WarnIfError();
RenderModels(context, CULL_REFLECTIONS);
ogl_WarnIfError();
RenderTransparentModels(context, CULL_REFLECTIONS, TRANSPARENT, true);
ogl_WarnIfError();
}
glFrontFace(GL_CCW);
// Particles are always oriented to face the camera in the vertex shader,
@ -1234,13 +1236,13 @@ SScreenRect CRenderer::RenderReflections(const CShaderDefines& context, const CB
// rebind post-processing frambuffer.
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
return screenScissor;
return;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// RenderRefractions: render the water refractions to the refraction texture
SScreenRect CRenderer::RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned &scissor)
void CRenderer::RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned &scissor)
{
PROFILE3_GPU("water refractions");
@ -1255,6 +1257,9 @@ SScreenRect CRenderer::RenderRefractions(const CShaderDefines& context, const CB
ComputeRefractionCamera(m_ViewCamera, scissor);
CVector4D camPlane(0, -1, 0, wm.m_WaterHeight + 2.0f);
SetObliqueFrustumClipping(m_ViewCamera, camPlane);
m->SetOpenGLCamera(m_ViewCamera);
// Save the model-view-projection matrix so the shaders can use it for projective texturing
@ -1295,7 +1300,7 @@ SScreenRect CRenderer::RenderRefractions(const CShaderDefines& context, const CB
// rebind post-processing frambuffer.
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
return screenScissor;
return;
}
void CRenderer::RenderSilhouettes(const CShaderDefines& context)
@ -1486,25 +1491,10 @@ void CRenderer::RenderSubmissions(const CBoundingBoxAligned& waterScissor)
if (waterScissor.GetVolume() > 0 && m_WaterManager->WillRenderFancyWater())
{
PROFILE3_GPU("water scissor");
SScreenRect dirty = { INT_MAX, INT_MAX, INT_MIN, INT_MIN };
if (m_Options.m_WaterReflection)
{
SScreenRect reflectionScissor = RenderReflections(context, waterScissor);
dirty.x1 = std::min(dirty.x1, reflectionScissor.x1);
dirty.y1 = std::min(dirty.y1, reflectionScissor.y1);
dirty.x2 = std::max(dirty.x2, reflectionScissor.x2);
dirty.y2 = std::max(dirty.y2, reflectionScissor.y2);
}
RenderReflections(context, waterScissor);
if (m_Options.m_WaterRefraction)
{
SScreenRect refractionScissor = RenderRefractions(context, waterScissor);
dirty.x1 = std::min(dirty.x1, refractionScissor.x1);
dirty.y1 = std::min(dirty.y1, refractionScissor.y1);
dirty.x2 = std::max(dirty.x2, refractionScissor.x2);
dirty.y2 = std::max(dirty.y2, refractionScissor.y2);
}
RenderRefractions(context, waterScissor);
}
}
@ -1862,6 +1852,8 @@ void CRenderer::RenderScene(Scene& scene)
scene.EnumerateObjects(refractionCamera.GetFrustum(), this);
}
}
// Render the waves to the Fancy effects texture
m_WaterManager->RenderWaves(frustum);
}
m_CurrentCullGroup = -1;

View File

@ -353,6 +353,7 @@ protected:
friend class InstancingModelRenderer;
friend class ShaderInstancingModelRenderer;
friend class TerrainRenderer;
friend class WaterRenderer;
//BEGIN: Implementation of SceneCollector
void Submit(CPatch* patch);
@ -384,8 +385,8 @@ protected:
void RenderShadowMap(const CShaderDefines& context);
// render water reflection and refraction textures
SScreenRect RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor);
SScreenRect RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned& scissor);
void RenderReflections(const CShaderDefines& context, const CBoundingBoxAligned& scissor);
void RenderRefractions(const CShaderDefines& context, const CBoundingBoxAligned& scissor);
void ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const;
void ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const;

View File

@ -85,7 +85,6 @@ struct TerrainRendererInternals
/// Fancy water shader
CShaderProgramPtr fancyWaterShader;
CShaderProgramPtr fancyEffectsShader;
CSimulation2* simulation;
};
@ -645,14 +644,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
defines.Add(str_USE_REFLECTION, str_1);
if (shadow && WaterMgr->m_WaterShadows)
defines.Add(str_USE_SHADOWS_ON_WATER, str_1);
m->fancyEffectsShader = g_Renderer.GetShaderManager().LoadProgram("glsl/water_effects", defines);
if (!m->fancyEffectsShader)
{
LOGERROR(L"Failed to load Fancy effects shader. Deactivating fancy effects.\n");
g_Renderer.SetOptionBool(CRenderer::OPT_WATERFANCYEFFECTS, false);
defines.Add(str_USE_FANCY_EFFECTS, str_0);
}
// haven't updated the ARB shader yet so I'll always load the GLSL
/*if (!g_Renderer.m_Options.m_PreferGLSL && !superFancy)
@ -671,12 +662,12 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();
GLuint depthTex;
// creating the real depth texture using the depth buffer.
if (WaterMgr->m_WaterRealDepth)
{
if (WaterMgr->m_depthTT == 0)
{
GLuint depthTex;
glGenTextures(1, (GLuint*)&depthTex);
WaterMgr->m_depthTT = depthTex;
glBindTexture(GL_TEXTURE_2D, WaterMgr->m_depthTT);
@ -685,11 +676,12 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
}
else
{
glBindTexture(GL_TEXTURE_2D, WaterMgr->m_depthTT);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight(), 0);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
// Calculating the advanced informations about Foam and all if the quality calls for it.
@ -706,8 +698,6 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
float repeatPeriod = WaterMgr->m_RepeatPeriod;
GLuint FramebufferName = 0;
// Render normals and foam to a framebuffer if we're in fancy effects
if (WaterMgr->m_WaterFancyEffects)
{
@ -715,68 +705,30 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
GLint fbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo);
// Generate our framebuffer
pglGenFramebuffersEXT(1, &FramebufferName);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferName);
GLuint renderedTexture;
if (WaterMgr->m_FancyTexture == 0)
{
glGenTextures(1, &renderedTexture);
WaterMgr->m_FancyTexture = renderedTexture;
glBindTexture(GL_TEXTURE_2D, WaterMgr->m_FancyTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, WaterMgr->m_FancyEffectsFBO);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);
} else
glBindTexture(GL_TEXTURE_2D, WaterMgr->m_FancyTexture);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, WaterMgr->m_FancyTexture, 0);
// rendering
m->fancyEffectsShader->Bind();
m->fancyEffectsShader->BindTexture(str_normalMap, WaterMgr->m_NormalMap[curTex]);
m->fancyEffectsShader->BindTexture(str_normalMap2, WaterMgr->m_NormalMap[nexTex]);
m->fancyEffectsShader->Uniform(str_waviness, WaterMgr->m_Waviness);
m->fancyEffectsShader->Uniform(str_repeatScale, 1.0f / repeatPeriod);
m->fancyEffectsShader->Uniform(str_time, (float)time);
m->fancyEffectsShader->Uniform(str_windAngle, (float)WaterMgr->m_WindAngle);
m->fancyEffectsShader->Uniform(str_screenSize, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0.0f, 0.0f);
m->fancyEffectsShader->Uniform(str_mapSize, (float)(WaterMgr->m_MapSize));
if (WaterMgr->m_WaterType == L"clap")
{
m->fancyEffectsShader->Uniform(str_waveParams1, 30.0f,1.5f,20.0f,0.03f);
m->fancyEffectsShader->Uniform(str_waveParams2, 0.5f,0.0f,0.0f,0.0f);
}
else if (WaterMgr->m_WaterType == L"lake")
{
m->fancyEffectsShader->Uniform(str_waveParams1, 8.5f,1.5f,15.0f,0.03f);
m->fancyEffectsShader->Uniform(str_waveParams2, 0.2f,0.0f,0.0f,0.07f);
}
else
{
m->fancyEffectsShader->Uniform(str_waveParams1, 15.0f,0.8f,10.0f,0.1f);
m->fancyEffectsShader->Uniform(str_waveParams2, 0.3f,0.0f,0.1f,0.3f);
}
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<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
for (size_t i = 0; i < visiblePatches.size(); ++i)
{
CPatchRData* data = visiblePatches[i];
data->RenderWater(m->fancyEffectsShader);
data->RenderWater(dummyShader, true,true);
}
dummyShader->Unbind();
m->fancyEffectsShader->Unbind();
// rebind post-processing frambuffer.
glEnable(GL_CULL_FACE);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glBindTexture(GL_TEXTURE_2D, 0);
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
@ -791,23 +743,37 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
m->fancyWaterShader->BindTexture(str_normalMap2, WaterMgr->m_NormalMap[nexTex]);
if (WaterMgr->m_WaterFancyEffects)
m->fancyWaterShader->BindTexture(str_waterEffectsTex, WaterMgr->m_FancyTexture);
{
m->fancyWaterShader->BindTexture(str_waterEffectsTexNorm, WaterMgr->m_FancyTextureNormal);
m->fancyWaterShader->BindTexture(str_waterEffectsTexOther, WaterMgr->m_FancyTextureOther);
}
if (WaterMgr->m_WaterRealDepth)
m->fancyWaterShader->BindTexture(str_depthTex, WaterMgr->m_depthTT);
if (WaterMgr->m_WaterReflection)
m->fancyWaterShader->BindTexture(str_reflectionMap, WaterMgr->m_ReflectionTexture);
if (WaterMgr->m_WaterRefraction)
m->fancyWaterShader->BindTexture(str_refractionMap, WaterMgr->m_RefractionTexture);
if (WaterMgr->m_WaterReflection)
m->fancyWaterShader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube());
m->fancyWaterShader->BindTexture(str_reflectionMap, WaterMgr->m_ReflectionTexture);
m->fancyWaterShader->BindTexture(str_losMap, losTexture.GetTextureSmooth());
m->fancyWaterShader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube());
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
// TODO: only bind what's really needed for that.
m->fancyWaterShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
//TODO: bind only what's needed
if (WaterMgr->m_WaterReflection)
{
// TODO: check that this rotates in the right direction.
CMatrix3D skyBoxRotation;
skyBoxRotation.SetIdentity();
skyBoxRotation.RotateY(M_PI - 0.3f + lightEnv.GetRotation());
m->fancyWaterShader->Uniform(str_skyBoxRot, skyBoxRotation);
}
m->fancyWaterShader->Uniform(str_sunDir, lightEnv.GetSunDir());
m->fancyWaterShader->Uniform(str_sunColor, lightEnv.m_SunColor.X);
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);
@ -823,23 +789,20 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
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_WaterFancyEffects)
if (WaterMgr->m_WaterType == L"clap")
{
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);
}
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 && WaterMgr->m_WaterShadows)
@ -857,12 +820,9 @@ bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGr
CPatchRData* data = visiblePatches[i];
data->RenderWater(m->fancyWaterShader);
}
m->fancyWaterShader->Unbind();
pglActiveTextureARB(GL_TEXTURE0);
pglDeleteFramebuffersEXT(1, &FramebufferName);
glDepthFunc(GL_LEQUAL);
glDisable(GL_BLEND);
return true;
@ -941,7 +901,7 @@ void TerrainRenderer::RenderSimpleWater(int cullGroup)
for (size_t i = 0; i < visiblePatches.size(); ++i)
{
CPatchRData* data = visiblePatches[i];
data->RenderWater(dummyShader, true);
data->RenderWater(dummyShader, false, true);
}
glDisableClientState(GL_VERTEX_ARRAY);

View File

@ -23,6 +23,8 @@
#include "graphics/Terrain.h"
#include "graphics/TextureManager.h"
#include "graphics/ShaderManager.h"
#include "graphics/ShaderProgram.h"
#include "lib/bits.h"
#include "lib/timer.h"
@ -46,6 +48,32 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// WaterManager implementation
struct CoastalPoint
{
CoastalPoint(int idx, CVector2D pos) : index(idx), position(pos) {};
int index;
CVector2D position;
};
struct SWavesVertex {
// vertex position
CVector3D m_BasePosition;
CVector3D m_ApexPosition;
CVector3D m_SplashPosition;
CVector3D m_RetreatPosition;
CVector2D m_PerpVect;
u8 m_UV[3];
};
cassert(sizeof(SWavesVertex) == 60);
struct WaveObject
{
CVertexBuffer::VBChunk* m_VBvertices;
CBoundingBoxAligned m_AABB;
size_t m_Width;
float m_TimeDiff;
};
///////////////////////////////////////////////////////////////////
// Construction/Destruction
@ -64,6 +92,7 @@ WaterManager::WaterManager()
m_ReflectionFbo = 0;
m_RefractionFbo = 0;
m_FancyEffectsFBO = 0;
m_WaterTexTimer = 0.0;
@ -90,7 +119,9 @@ WaterManager::WaterManager()
m_NeedInfoUpdate = true;
m_depthTT = 0;
m_FancyTexture = 0;
m_FancyTextureNormal = 0;
m_FancyTextureOther = 0;
m_FancyTextureDepth = 0;
m_ReflFboDepthTexture = 0;
m_RefrFboDepthTexture = 0;
@ -107,14 +138,24 @@ WaterManager::~WaterManager()
// Cleanup if the caller messed up
UnloadWaterTextures();
// TODO: when c++11 is around, use lambdas or something because short Korea is best Korea.
for (size_t i = 0; i < m_ShoreWaves.size(); ++i)
delete m_ShoreWaves[i];
SAFE_ARRAY_DELETE(m_DistanceHeightmap);
SAFE_ARRAY_DELETE(m_BlurredNormalMap);
SAFE_ARRAY_DELETE(m_WindStrength);
glDeleteTextures(1, &m_depthTT);
glDeleteTextures(1, &m_FancyTexture);
glDeleteTextures(1, &m_FancyTextureNormal);
glDeleteTextures(1, &m_FancyTextureOther);
glDeleteTextures(1, &m_FancyTextureDepth);
glDeleteTextures(1, &m_ReflFboDepthTexture);
glDeleteTextures(1, &m_RefrFboDepthTexture);
pglDeleteFramebuffersEXT(1, &m_FancyEffectsFBO);
pglDeleteFramebuffersEXT(1, &m_RefractionFbo);
pglDeleteFramebuffersEXT(1, &m_ReflectionFbo);
}
@ -152,9 +193,27 @@ int WaterManager::LoadWaterTextures()
m_NormalMap[i] = texture;
}
// Load CoastalWaves
{
CTextureProperties textureProps(L"art/textures/terrain/types/water/coastalWave.png");
textureProps.SetWrap(GL_REPEAT);
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
texture->Prefetch();
m_WaveTex = texture;
}
// Load Foam
{
CTextureProperties textureProps(L"art/textures/terrain/types/water/foam.png");
textureProps.SetWrap(GL_REPEAT);
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
texture->Prefetch();
m_FoamTex = texture;
}
m_ReflectionTextureSize = g_Renderer.GetHeight() * 0.66; // Higher settings give a better result
m_RefractionTextureSize = g_Renderer.GetHeight() * 0.33; // Lower settings actually sorta look better since it blurs.
// Create reflection texture
glGenTextures(1, &m_ReflectionTexture);
glBindTexture(GL_TEXTURE_2D, m_ReflectionTexture);
@ -194,6 +253,31 @@ int WaterManager::LoadWaterTextures()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, (GLsizei)m_RefractionTextureSize, (GLsizei)m_RefractionTextureSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
// Create the Fancy Effects texture
glGenTextures(1, &m_FancyTextureNormal);
glBindTexture(GL_TEXTURE_2D, m_FancyTextureNormal);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)g_Renderer.GetWidth(), (GLsizei)g_Renderer.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL);
glGenTextures(1, &m_FancyTextureOther);
glBindTexture(GL_TEXTURE_2D, m_FancyTextureOther);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)g_Renderer.GetWidth(), (GLsizei)g_Renderer.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT, NULL);
glGenTextures(1, &m_FancyTextureDepth);
glBindTexture(GL_TEXTURE_2D, m_FancyTextureDepth);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, (GLsizei)g_Renderer.GetWidth(), (GLsizei)g_Renderer.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
// Create the water framebuffers
@ -231,6 +315,21 @@ int WaterManager::LoadWaterTextures()
g_Renderer.m_Options.m_WaterRefraction = false;
}
pglGenFramebuffersEXT(1, &m_FancyEffectsFBO);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_FancyTextureNormal, 0);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, m_FancyTextureOther, 0);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_FancyTextureDepth, 0);
ogl_WarnIfError();
status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
LOGWARNING(L"Fancy Effects framebuffer object incomplete: 0x%04X", status);
g_Renderer.m_Options.m_WaterRefraction = false;
}
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, currentFbo);
// Enable rendering, now that we've succeeded this far
@ -263,69 +362,542 @@ void WaterManager::UnloadWaterTextures()
// Calculate our binary heightmap from the terrain heightmap.
void WaterManager::RecomputeDistanceHeightmap()
{
size_t SideSize = m_MapSize*2;
if (m_DistanceHeightmap == NULL)
m_DistanceHeightmap = new u8[m_MapSize*m_MapSize];
// Custom copy the heightmap.
m_DistanceHeightmap = new float[SideSize*SideSize];
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
u16 waterLevel = m_WaterHeight/HEIGHT_SCALE;
u16* heightmap = terrain->GetHeightMap();
// Create a manhattan-distance heightmap.
// This is currently upsampled by a factor of 2 to get more precision
// This could be refined to only be done near the coast itself, but it's probably not necessary.
// We will "expand" the heightmap. That is we'll set each vertex on land as "3", and "bleed" that onto neighboring pixels.
// So 3 is "on land", 2 is "close", 1 "somewhat close" and 0 is "water".
// This gives a basic manhattan approximation of how close to the coast we are.
// I have a heathen fondness for ternary operators so there are some below.
u8 level = 0;
for (size_t z = 0; z < m_MapSize; ++z)
float level = SideSize;
for (size_t z = 0; z < SideSize; ++z)
{
level = 0;
for (size_t x = 0; x < m_MapSize; ++x)
m_DistanceHeightmap[z*m_MapSize + x] = heightmap[z*m_MapSize + x] >= waterLevel ? level = 3
: level > 0 ? --level : 0;
level = 0;
for (size_t x = m_MapSize-1; x != (size_t)-1; --x)
level = SideSize;
for (size_t x = 0; x < SideSize; ++x)
m_DistanceHeightmap[z*SideSize + x] = terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight ? level = 0.f : ++level;
level = SideSize;
for (size_t x = SideSize-1; x != (size_t)-1; --x)
{
if (heightmap[z*m_MapSize + x] >= waterLevel)
level = 3; // no need to set m_distanceHeightmap, it's already been done by the other loop.
if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight)
level = 0.f;
else
{
level > 0 ? --level : 0;
if (level > m_DistanceHeightmap[z*m_MapSize + x])
m_DistanceHeightmap[z*m_MapSize + x] = level;
++level;
if (level < m_DistanceHeightmap[z*SideSize + x])
m_DistanceHeightmap[z*SideSize + x] = level;
}
}
}
for (size_t x = 0; x < m_MapSize; ++x)
for (size_t x = 0; x < SideSize; ++x)
{
level = 0;
for (size_t z = 0; z < m_MapSize; ++z)
level = SideSize;
for (size_t z = 0; z < SideSize; ++z)
{
if (heightmap[z*m_MapSize + x] >= waterLevel)
level = 3;
if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight)
level = 0.f;
else if (level > m_DistanceHeightmap[z*SideSize + x])
level = m_DistanceHeightmap[z*SideSize + x];
else
{
level > 0 ? --level : 0;
if (level > m_DistanceHeightmap[z*m_MapSize + x])
m_DistanceHeightmap[z*m_MapSize + x] = level;
++level;
if (level < m_DistanceHeightmap[z*SideSize + x])
m_DistanceHeightmap[z*SideSize + x] = level;
}
}
level = 0;
for (size_t z = m_MapSize-1; z != (size_t)-1; --z)
level = SideSize;
for (size_t z = SideSize-1; z != (size_t)-1; --z)
{
if (heightmap[z*m_MapSize + x] >= waterLevel)
level = 3;
if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight)
level = 0.f;
else if (level > m_DistanceHeightmap[z*SideSize + x])
level = m_DistanceHeightmap[z*SideSize + x];
else
{
level > 0 ? --level : 0;
if (level > m_DistanceHeightmap[z*m_MapSize + x])
m_DistanceHeightmap[z*m_MapSize + x] = level;
++level;
if (level < m_DistanceHeightmap[z*SideSize + x])
m_DistanceHeightmap[z*SideSize + x] = level;
}
}
}
}
// This requires m_DistanceHeightmap to be defined properly.
void WaterManager::CreateWaveMeshes()
{
size_t SideSize = m_MapSize*2;
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
// TODO: when c++11 is around, use lambdas or something because short Korea is best Korea.
for (size_t i = 0; i < m_ShoreWaves.size(); ++i)
delete m_ShoreWaves[i];
m_ShoreWaves.clear();
if (m_Waviness < 5.0f && m_WaterType != L"ocean")
return;
// First step: get the points near the coast.
std::set<int> CoastalPointsSet;
for (size_t z = 0; z < SideSize; ++z)
for (size_t x = 0; x < SideSize; ++x)
if (abs(m_DistanceHeightmap[z*SideSize + x]-1.0f) < 0.2f)
CoastalPointsSet.insert(z*SideSize + x);
// Second step: create chains out of those coastal points.
static const int around[8][2] = { { -1,-1 }, { -1,0 }, { -1,1 }, { 0,1 }, { 1,1 }, { 1,0 }, { 1,-1 }, { 0,-1 } };
while (!CoastalPointsSet.empty())
{
int index = *(CoastalPointsSet.begin());
int x = index % SideSize;
int y = (index - x ) / SideSize;
std::deque<CoastalPoint> Chain;
Chain.push_front(CoastalPoint(index,CVector2D(x*2,y*2)));
// Erase us.
CoastalPointsSet.erase(CoastalPointsSet.begin());
// We're our starter points. At most we can have 2 points close to us.
// We'll pick the first one and look for its neighbors (he can only have one new)
// Up until we either reach the end of the chain, or ourselves.
// Then go down the other direction if there is any.
int neighbours[2] = { -1, -1 };
int nbNeighb = 0;
for (int i = 0; i < 8; ++i)
{
if (CoastalPointsSet.count(x + around[i][0] + (y + around[i][1])*SideSize))
{
if (nbNeighb < 2)
neighbours[nbNeighb] = x + around[i][0] + (y + around[i][1])*SideSize;
++nbNeighb;
}
}
if (nbNeighb > 2)
continue;
for (int i = 0; i < 2; ++i)
{
if (neighbours[i] == -1)
continue;
// Move to our neighboring point
int xx = neighbours[i] % SideSize;
int yy = (neighbours[i] - xx ) / SideSize;
int indexx = xx + yy*SideSize;
int endedChain = false;
if (i == 0)
Chain.push_back(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));
else
Chain.push_front(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));
// If there's a loop we'll be the "other" neighboring point already so check for that.
// We'll readd at the end/front the other one to have full squares.
if (CoastalPointsSet.count(indexx) == 0)
break;
CoastalPointsSet.erase(indexx);
// Start checking from there.
while(!endedChain)
{
bool found = false;
nbNeighb = 0;
for (int p = 0; p < 8; ++p)
{
if (CoastalPointsSet.count(xx+around[p][0] + (yy + around[p][1])*SideSize))
{
if (nbNeighb >= 2)
{
CoastalPointsSet.erase(xx + yy*SideSize);
continue;
}
++nbNeighb;
// We've found a new point around us.
// Move there
xx = xx + around[p][0];
yy = yy + around[p][1];
indexx = xx + yy*SideSize;
if (i == 0)
Chain.push_back(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));
else
Chain.push_front(CoastalPoint(indexx,CVector2D(xx*2,yy*2)));
CoastalPointsSet.erase(xx + yy*SideSize);
found = true;
break;
}
}
if (!found)
endedChain = true;
}
}
if (Chain.size() > 10)
CoastalPointsChains.push_back(Chain);
}
// (optional) third step: Smooth chains out.
// This is also really dumb.
for (size_t i = 0; i < CoastalPointsChains.size(); ++i)
{
// Bump 1 for smoother.
for (int p = 0; p < 3; ++p)
{
for (size_t j = 1; j < CoastalPointsChains[i].size()-1; ++j)
{
CVector2D realPos = CoastalPointsChains[i][j-1].position + CoastalPointsChains[i][j+1].position;
CoastalPointsChains[i][j].position = (CoastalPointsChains[i][j].position + realPos/2.0f)/2.0f;
}
}
}
// Fourth step: create waves themselves, using those chains. We basically create subchains.
size_t waveSizes = 14; // maximal size in width.
// Construct indices buffer (we can afford one for all of them)
std::vector<GLushort> water_indices;
for (size_t a = 0; a < waveSizes-1;++a)
{
for (size_t rect = 0; rect < 7; ++rect)
{
water_indices.push_back(a*9 + rect);
water_indices.push_back(a*9 + 9 + rect);
water_indices.push_back(a*9 + 1 + rect);
water_indices.push_back(a*9 + 9 + rect);
water_indices.push_back(a*9 + 10 + rect);
water_indices.push_back(a*9 + 1 + rect);
}
}
// Generic indexes, max-length
m_ShoreWaves_VBIndices = g_VBMan.Allocate(sizeof(GLushort), water_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER);
m_ShoreWaves_VBIndices->m_Owner->UpdateChunkVertices(m_ShoreWaves_VBIndices, &water_indices[0]);
float diff = (rand() % 50) / 5.0f;
for (size_t i = 0; i < CoastalPointsChains.size(); ++i)
{
for (size_t j = 0; j < CoastalPointsChains[i].size()-waveSizes; ++j)
{
if (CoastalPointsChains[i].size()- 1 - j < waveSizes)
break;
size_t width = waveSizes;
// First pass to get some parameters out.
float outmost = 0.0f; // how far to move on the shore.
float avgDepth = 0.0f;
int sign = 1;
CVector2D firstPerp, perp, lastPerp;
for (size_t a = 0; a < waveSizes;++a)
{
lastPerp = perp;
perp = CVector2D(0,0);
int nb = 0;
CVector2D pos = CoastalPointsChains[i][j+a].position;
CVector2D posPlus;
CVector2D posMinus;
if (a > 0)
{
++nb;
posMinus = CoastalPointsChains[i][j+a-1].position;
perp += pos-posMinus;
}
if (a < waveSizes-1)
{
++nb;
posPlus = CoastalPointsChains[i][j+a+1].position;
perp += posPlus-pos;
}
perp /= nb;
perp = CVector2D(-perp.Y,perp.X).Normalized();
if (a == 0)
firstPerp = perp;
if ( a > 1 && perp.Dot(lastPerp) < 0.90f && perp.Dot(firstPerp) < 0.70f)
{
width = a+1;
break;
}
if (m_BlurredNormalMap[ (int)(pos.X/4) + (int)(pos.Y/4)*m_MapSize].Y < 0.9)
{
width = a-1;
break;
}
if (terrain->GetExactGroundLevel(pos.X+perp.X*1.5f, pos.Y+perp.Y*1.5f) > m_WaterHeight)
sign = -1;
avgDepth += terrain->GetExactGroundLevel(pos.X+sign*perp.X*20.0f, pos.Y+sign*perp.Y*20.0f) - m_WaterHeight;
float localOutmost = -2.0f;
while (localOutmost < 0.0f)
{
float depth = terrain->GetExactGroundLevel(pos.X+sign*perp.X*localOutmost, pos.Y+sign*perp.Y*localOutmost) - m_WaterHeight;
if (depth < 0.0f || depth > 0.6f)
localOutmost += 0.2f;
else
break;
}
outmost += localOutmost;
}
if (width < 5)
{
j += 6;
continue;
}
outmost /= width;
if (outmost > -0.5f)
{
j += 3;
continue;
}
outmost = -0.5f + outmost * m_Waviness/10.0f;
avgDepth /= width;
if (avgDepth > -1.3f)
{
j += 3;
continue;
}
// we passed the checks, we can create a wave of size "width".
WaveObject* shoreWave = new WaveObject;
std::vector<SWavesVertex> vertices;
shoreWave->m_Width = width;
shoreWave->m_TimeDiff = diff;
diff += (rand() % 100) / 25.0f + 4.0f;
for (size_t a = 0; a < width;++a)
{
CVector2D perp = CVector2D(0,0);
int nb = 0;
CVector2D pos = CoastalPointsChains[i][j+a].position;
CVector2D posPlus;
CVector2D posMinus;
if (a > 0)
{
++nb;
posMinus = CoastalPointsChains[i][j+a-1].position;
perp += pos-posMinus;
}
if (a < waveSizes-1)
{
++nb;
posPlus = CoastalPointsChains[i][j+a+1].position;
perp += posPlus-pos;
}
perp /= nb;
perp = CVector2D(-perp.Y,perp.X).Normalized();
SWavesVertex point[9];
float baseHeight = 0.04f;
float halfWidth = (width-1.0f)/2.0f;
float sideNess = sqrtf(clamp( (halfWidth - fabsf(a-halfWidth))/3.0f, 0.0f,1.0f));
point[0].m_UV[0] = a; point[0].m_UV[1] = 8;
point[1].m_UV[0] = a; point[1].m_UV[1] = 7;
point[2].m_UV[0] = a; point[2].m_UV[1] = 6;
point[3].m_UV[0] = a; point[3].m_UV[1] = 5;
point[4].m_UV[0] = a; point[4].m_UV[1] = 4;
point[5].m_UV[0] = a; point[5].m_UV[1] = 3;
point[6].m_UV[0] = a; point[6].m_UV[1] = 2;
point[7].m_UV[0] = a; point[7].m_UV[1] = 1;
point[8].m_UV[0] = a; point[8].m_UV[1] = 0;
point[0].m_PerpVect = perp;
point[1].m_PerpVect = perp;
point[2].m_PerpVect = perp;
point[3].m_PerpVect = perp;
point[4].m_PerpVect = perp;
point[5].m_PerpVect = perp;
point[6].m_PerpVect = perp;
point[7].m_PerpVect = perp;
point[8].m_PerpVect = perp;
static const float perpT1[9] = { 6.0f, 6.05f, 6.1f, 6.2f, 6.3f, 6.4f, 6.5f, 6.6f, 9.7f };
static const float perpT2[9] = { 2.0f, 2.1f, 2.2f, 2.3f, 2.4f, 3.0f, 3.3f, 3.6f, 9.5f };
static const float perpT3[9] = { 1.1f, 0.7f, -0.2f, 0.0f, 0.6f, 1.3f, 2.2f, 3.6f, 9.0f };
static const float perpT4[9] = { 2.0f, 2.1f, 1.2f, 1.5f, 1.7f, 1.9f, 2.7f, 3.8f, 9.0f };
static const float heightT1[9] = { 0.0f, 0.2f, 0.5f, 0.8f, 0.9f, 0.85f, 0.6f, 0.2f, 0.0 };
static const float heightT2[9] = { -0.8f, -0.4f, 0.0f, 0.1f, 0.1f, 0.03f, 0.0f, 0.0f, 0.0 };
static const float heightT3[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0 };
for (size_t t = 0; t < 9; ++t)
{
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT1[t]+outmost),
pos.Y+sign*perp.Y*(perpT1[t]+outmost));
point[t].m_BasePosition = CVector3D(pos.X+sign*perp.X*(perpT1[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight),
pos.Y+sign*perp.Y*(perpT1[t]+outmost));
}
for (size_t t = 0; t < 9; ++t)
{
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT2[t]+outmost),
pos.Y+sign*perp.Y*(perpT2[t]+outmost));
point[t].m_ApexPosition = CVector3D(pos.X+sign*perp.X*(perpT2[t]+outmost), baseHeight + heightT1[t]*sideNess + std::max(m_WaterHeight,terrHeight),
pos.Y+sign*perp.Y*(perpT2[t]+outmost));
}
for (size_t t = 0; t < 9; ++t)
{
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess),
pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess));
point[t].m_SplashPosition = CVector3D(pos.X+sign*perp.X*(perpT3[t]+outmost*sideNess), baseHeight + heightT2[t]*sideNess + std::max(m_WaterHeight,terrHeight), pos.Y+sign*perp.Y*(perpT3[t]+outmost*sideNess));
}
for (size_t t = 0; t < 9; ++t)
{
float terrHeight = 0.05f + terrain->GetExactGroundLevel(pos.X+sign*perp.X*(perpT4[t]+outmost),
pos.Y+sign*perp.Y*(perpT4[t]+outmost));
point[t].m_RetreatPosition = CVector3D(pos.X+sign*perp.X*(perpT4[t]+outmost), baseHeight + heightT3[t]*sideNess + std::max(m_WaterHeight,terrHeight),
pos.Y+sign*perp.Y*(perpT4[t]+outmost));
}
vertices.push_back(point[8]);
vertices.push_back(point[7]);
vertices.push_back(point[6]);
vertices.push_back(point[5]);
vertices.push_back(point[4]);
vertices.push_back(point[3]);
vertices.push_back(point[2]);
vertices.push_back(point[1]);
vertices.push_back(point[0]);
shoreWave->m_AABB += point[8].m_SplashPosition;
shoreWave->m_AABB += point[8].m_BasePosition;
shoreWave->m_AABB += point[0].m_SplashPosition;
shoreWave->m_AABB += point[0].m_BasePosition;
shoreWave->m_AABB += point[4].m_ApexPosition;
}
if (sign == 1)
{
// Let's do some fancy reversing.
std::vector<SWavesVertex> reversed;
for (int a = width-1; a >= 0; --a)
{
for (size_t t = 0; t < 9; ++t)
reversed.push_back(vertices[a*9+t]);
}
vertices = reversed;
}
// very simple smoothing.
// Bump 1 for smoother.
/*for (int p = 0; p < 3; ++p)
{
for (size_t j = 1; j < waveSizes-1; ++j)
{
CVector3D realPos = (MeshPoints[j-1].m_BasePosition + MeshPoints[j+1].m_BasePosition)*0.5f;
MeshPoints[j].m_BasePosition = (MeshPoints[j].m_BasePosition + realPos)*0.5f;
realPos = (MeshPoints[j-1].m_ApexPosition + MeshPoints[j+1].m_ApexPosition)*0.5f;
MeshPoints[j].m_ApexPosition = (MeshPoints[j].m_ApexPosition + realPos)*0.5f;
realPos = (MeshPoints[j-1].m_SplashPosition + MeshPoints[j+1].m_SplashPosition)*0.5f;
MeshPoints[j].m_SplashPosition = (MeshPoints[j].m_SplashPosition + realPos)*0.5f;
realPos = (MeshPoints[j-1].m_RetreatPosition + MeshPoints[j+1].m_RetreatPosition)*0.5f;
MeshPoints[j].m_RetreatPosition = (MeshPoints[j].m_RetreatPosition + realPos)*0.5f;
}
}*/
j += width/2-1;
shoreWave->m_VBvertices = g_VBMan.Allocate(sizeof(SWavesVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER);
shoreWave->m_VBvertices->m_Owner->UpdateChunkVertices(shoreWave->m_VBvertices, &vertices[0]);
m_ShoreWaves.push_back(shoreWave);
}
}
}
void WaterManager::RenderWaves(const CFrustum& frustrum)
{
if (g_Renderer.m_SkipSubmit || !m_WaterFancyEffects)
return;
GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FancyEffectsFBO);
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
pglDrawBuffers(2, attachments);
glClearColor(0.0f,0.0f, 0.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
CShaderDefines none;
CShaderProgramPtr shad = g_Renderer.GetShaderManager().LoadProgram("glsl/waves", none);
shad->Bind();
shad->BindTexture(str_waveTex, m_WaveTex);
shad->BindTexture(str_foamTex, m_FoamTex);
shad->Uniform(str_time, (float)m_WaterTexTimer);
shad->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
for (size_t a = 0; a < m_ShoreWaves.size(); ++a)
{
if (!frustrum.IsBoxVisible(CVector3D(0,0,0), m_ShoreWaves[a]->m_AABB))
continue;
CVertexBuffer::VBChunk* VBchunk = m_ShoreWaves[a]->m_VBvertices;
SWavesVertex *base=(SWavesVertex *)VBchunk->m_Owner->Bind();
// setup data pointers
GLsizei stride = sizeof(SWavesVertex);
shad->VertexPointer(3, GL_FLOAT, stride, &base[VBchunk->m_Index].m_BasePosition);
shad->TexCoordPointer(GL_TEXTURE0, 2, GL_UNSIGNED_BYTE, stride, &base[VBchunk->m_Index].m_UV);
// NormalPointer(gl_FLOAT, stride, &base[m_VBWater->m_Index].m_UV)
pglVertexAttribPointerARB(2, 2, GL_FLOAT, GL_TRUE, stride, &base[VBchunk->m_Index].m_PerpVect); // replaces commented above because my normal is vec2
shad->VertexAttribPointer(str_a_apexPosition, 3, GL_FLOAT, false, stride, &base[VBchunk->m_Index].m_ApexPosition);
shad->VertexAttribPointer(str_a_splashPosition, 3, GL_FLOAT, false, stride, &base[VBchunk->m_Index].m_SplashPosition);
shad->VertexAttribPointer(str_a_retreatPosition, 3, GL_FLOAT, false, stride, &base[VBchunk->m_Index].m_RetreatPosition);
shad->AssertPointersBound();
shad->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff);
shad->Uniform(str_width, (int)m_ShoreWaves[a]->m_Width);
u8* indexBase = m_ShoreWaves_VBIndices->m_Owner->Bind();
glDrawElements(GL_TRIANGLES, (GLsizei) (m_ShoreWaves[a]->m_Width-1)*(7*6),
GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_ShoreWaves_VBIndices->m_Index));
shad->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff + 6.0f);
//glDrawElements(GL_TRIANGLES, (GLsizei) (m_ShoreWaves[a]->m_Width-1)*(7*6),
// GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(m_ShoreWaves_VBIndices->m_Index));
// bump stats
// TODO: figure out why this doesn't work.
//g_Renderer.m_Stats.m_DrawCalls++;
//g_Renderer.m_Stats.m_WaterTris += m_ShoreWaves_VBIndices->m_Count / 3;
CVertexBuffer::Unbind();
}
shad->Unbind();
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
glDisable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
}
///////////////////////////////////////////////////////////////////
// Calculate The blurred normal map to get an idea of where water ought to go.
void WaterManager::RecomputeBlurredNormalMap()

View File

@ -30,15 +30,10 @@
#include "renderer/VertexBufferManager.h"
class CSimulation2;
class CFrustum;
struct SWavesVertex {
// vertex position
CVector3D m_Position;
u8 m_UV[2];
};
cassert(sizeof(SWavesVertex) == 16);
struct CoastalPoint;
struct WaveObject;
/**
* Class WaterManager: Maintain rendering-related water settings and textures
@ -52,14 +47,26 @@ public:
CTexturePtr m_NormalMap[60];
float* m_WindStrength; // How strong the waves are at point X. % of waviness.
u8* m_DistanceHeightmap; // Returns how far from the shore a point is. 3-2-1-0 where 3 is "on land"
float* m_DistanceHeightmap; // How far from the shore a point is. Manhattan
CVector3D* m_BlurredNormalMap; // Cache a slightly blurred map of the normals of the terrain.
std::vector< std::deque<CoastalPoint> > CoastalPointsChains;
// Waves vertex buffers
std::vector< WaveObject* > m_ShoreWaves; // TODO: once we get C++11, remove pointer
// Waves indices buffer. Only one since All Wave Objects have the same.
CVertexBuffer::VBChunk* m_ShoreWaves_VBIndices;
size_t m_MapSize;
ssize_t m_TexSize;
CTexturePtr m_WaveTex;
CTexturePtr m_FoamTex;
GLuint m_depthTT;
GLuint m_FancyTexture;
GLuint m_FancyTextureNormal;
GLuint m_FancyTextureOther;
GLuint m_FancyTextureDepth;
GLuint m_ReflFboDepthTexture;
GLuint m_RefrFboDepthTexture;
@ -104,6 +111,7 @@ public:
// framebuffer objects
GLuint m_RefractionFbo;
GLuint m_ReflectionFbo;
GLuint m_FancyEffectsFBO;
// Model-view-projection matrices for reflected & refracted cameras
// (used to let the vertex shader do projective texturing)
@ -153,9 +161,9 @@ public:
void RecomputeBlurredNormalMap();
/**
* CreateSuperfancyInfo: creates textures and wave vertices for superfancy water
* CreateWaveMeshes: Creates the waves objects (and meshes).
*/
void CreateSuperfancyInfo(CSimulation2* simulation);
void CreateWaveMeshes();
/**
* Updates the map size. Will trigger a complete recalculation of fancy water information the next turn.
@ -172,6 +180,8 @@ public:
* and it hasn't been configured off)
*/
bool WillRenderFancyWater();
void RenderWaves(const CFrustum& frustrum);
};

View File

@ -138,9 +138,10 @@ public:
if (ReloadWater && CRenderer::IsInitialised())
{
g_Renderer.GetWaterManager()->SetMapSize(vertices);
g_Renderer.GetWaterManager()->RecomputeDistanceHeightmap();
g_Renderer.GetWaterManager()->RecomputeBlurredNormalMap();
g_Renderer.GetWaterManager()->RecomputeDistanceHeightmap();
g_Renderer.GetWaterManager()->RecomputeWindStrength();
g_Renderer.GetWaterManager()->CreateWaveMeshes();
}
MakeDirty(0, 0, tiles+1, tiles+1);
}

View File

@ -100,6 +100,7 @@ public:
g_Renderer.GetWaterManager()->RecomputeBlurredNormalMap();
g_Renderer.GetWaterManager()->RecomputeDistanceHeightmap();
g_Renderer.GetWaterManager()->RecomputeWindStrength();
g_Renderer.GetWaterManager()->CreateWaveMeshes();
}
// Tell the terrain it'll need to recompute its cached render data