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:
parent
91ead32b1a
commit
9ce51f4357
BIN
binaries/data/mods/public/art/textures/terrain/types/water/coastalWave.png
(Stored with Git LFS)
Normal file
BIN
binaries/data/mods/public/art/textures/terrain/types/water/coastalWave.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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>
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
43
binaries/data/mods/public/shaders/glsl/waves.fs
Normal file
43
binaries/data/mods/public/shaders/glsl/waves.fs
Normal 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;
|
||||
}
|
34
binaries/data/mods/public/shaders/glsl/waves.vs
Normal file
34
binaries/data/mods/public/shaders/glsl/waves.vs
Normal 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);
|
||||
}
|
17
binaries/data/mods/public/shaders/glsl/waves.xml
Normal file
17
binaries/data/mods/public/shaders/glsl/waves.xml
Normal 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>
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user