1
0
forked from 0ad/0ad

Fix Atlas so that changing water type will actually change water type.

Fix the water shader so that object reflections are more visible. Looks
better.

This was SVN commit r16388.
This commit is contained in:
wraitii 2015-02-28 13:50:52 +00:00
parent b04761f1b8
commit 2d7d5b446d
4 changed files with 177 additions and 148 deletions

View File

@ -201,129 +201,131 @@ void main()
float ndotl = (dot(n, l) + 1.0)/2.0;
float depth;
#if USE_REAL_DEPTH
// Don't change these two. They should match the values in the config (TODO: dec uniforms).
float zNear = 2.0;
float zFar = 4096.0;
// Okay so here it's a tad complicated. I want to distort the depth buffer along the waves for a nice effect.
// However this causes a problem around underwater objects (think fishes): on some pixels, the depth will be seen as the same as the fishes'
// and the color will be grass ( cause I don't distort the refraction coord by exactly the same stuff)
// Also, things like towers with the feet in water would cause the buffer to see the depth as actually negative in some places.
// So what I do is first check the undistorted depth, then I compare with the distorted value and fix.
float water_b = gl_FragCoord.z;
float water_n = 2.0 * water_b - 1.0;
float waterDBuffer = 2.0 * zNear * zFar / (zFar + zNear - water_n * (zFar - zNear));
float undistortedBuffer = texture2D(depthTex, (gl_FragCoord.xy) / screenSize).x;
float undisto_z_b = texture2D(depthTex, (gl_FragCoord.xy) / screenSize).x;
float undisto_z_n = 2.0 * undisto_z_b - 1.0;
float waterDepth_undistorted = (2.0 * zNear * zFar / (zFar + zNear - undisto_z_n * (zFar - zNear)) - waterDBuffer);
vec2 depthCoord = clamp((gl_FragCoord.xy) / screenSize - n.xz*clamp( waterDepth_undistorted/400.0,0.0,0.05) , 0.001, 0.999);
float z_b = texture2D(depthTex, depthCoord).x;
if (z_b < undisto_z_b)
z_b = undisto_z_b;
float z_n = 2.0 * z_b - 1.0;
depth = (2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear)) - waterDBuffer);
#else
depth = waterDepth / (min(0.5,v.y)*1.5*min(0.5,v.y)*2.0);
#endif
#if USE_REAL_DEPTH
// Don't change these two. They should match the values in the config (TODO: dec uniforms).
float zNear = 2.0;
float zFar = 4096.0;
// Okay so here it's a tad complicated. I want to distort the depth buffer along the waves for a nice effect.
// However this causes a problem around underwater objects (think fishes): on some pixels, the depth will be seen as the same as the fishes'
// and the color will be grass ( cause I don't distort the refraction coord by exactly the same stuff)
// Also, things like towers with the feet in water would cause the buffer to see the depth as actually negative in some places.
// So what I do is first check the undistorted depth, then I compare with the distorted value and fix.
float water_b = gl_FragCoord.z;
float water_n = 2.0 * water_b - 1.0;
float waterDBuffer = 2.0 * zNear * zFar / (zFar + zNear - water_n * (zFar - zNear));
float undistortedBuffer = texture2D(depthTex, (gl_FragCoord.xy) / screenSize).x;
float undisto_z_b = texture2D(depthTex, (gl_FragCoord.xy) / screenSize).x;
float undisto_z_n = 2.0 * undisto_z_b - 1.0;
float waterDepth_undistorted = (2.0 * zNear * zFar / (zFar + zNear - undisto_z_n * (zFar - zNear)) - waterDBuffer);
vec2 depthCoord = clamp((gl_FragCoord.xy) / screenSize - n.xz*clamp( waterDepth_undistorted/400.0,0.0,0.05) , 0.001, 0.999);
float z_b = texture2D(depthTex, depthCoord).x;
if (z_b < undisto_z_b)
z_b = undisto_z_b;
float z_n = 2.0 * z_b - 1.0;
depth = (2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear)) - waterDBuffer);
#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
#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.
fresnel = clamp(pow(1.05 - ndotv, 1.3),0.0,0.8); // approximation. I'm using 1.05 and not 1.0 because it causes artifacts, see #1714
fresnel = clamp(pow(1.05 - ndotv, 1.1),0.0,0.8); // approximation. I'm using 1.05 and not 1.0 because it causes artifacts, see #1714
// 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 = clamp(fresnel*1.5,0.0,0.9);
fresnel *= min(1.0,log(1.0 + v.y*5.0));
fresnel = 0.1 + fresnel * 0.8;
//gl_FragColor = vec4(fresnel,fresnel,fresnel,1.0);
//return;
#if USE_SHADOWS_ON_WATER && USE_SHADOW
float shadow = get_shadow(vec4(v_shadow.xy, v_shadow.zw));
#endif
#if USE_SHADOWS_ON_WATER && USE_SHADOW
float shadow = get_shadow(vec4(v_shadow.xy, v_shadow.zw));
#endif
// for refraction, we want to adjust the value by v.y slightly otherwise it gets too different between "from above" and "from the sides".
// And it looks weird (again, we are not used to seeing water from above).
float fixedVy = max(v.y,0.1);
float distoFactor = clamp(depth/2.0,0.0,7.0);
float murky = mix(200.0,0.1,pow(murkiness,0.25));
#if USE_REFRACTION
refrCoords = clamp( (0.5*refractionCoords.xy - n.xz * distoFactor*7.0) / refractionCoords.z + 0.5,0.0,1.0); // Unbias texture coords
vec3 refColor = texture2D(refractionMap, refrCoords).rgb;
if (refColor.r > refColor.g + refColor.b + 0.25)
{
refrCoords = clamp( (0.5*refractionCoords.xy + n.xz) / refractionCoords.z + 0.5,0.0,1.0); // Unbias texture coords
refColor = texture2D(refractionMap, refrCoords).rgb;
}
// TODO: make murkiness (both types rematter on that.
// linearly extinct the water. This is how quickly we see nothing but the pure water color
float extFact = max(0.0,1.0 - (depth*fixedVy/murky));
// This is how tinted the water is, ie how quickly the refracted floor takes the tint of the water
float ColextFact = max(0.0,1.0 - (depth*fixedVy/murky));
vec3 colll = mix(refColor*tint,refColor,ColextFact);
#if USE_SHADOWS_ON_WATER && USE_SHADOW
// TODO:
refrColor = mix(color, colll, extFact);
#else
refrColor = mix(color, colll, extFact);
#endif
#else
// linearly extinct the water. This is how quickly we see nothing but the pure water color
float extFact = max(0.0,1.0 - (depth*fixedVy/20.0));
// using both those factors, get our transparency.
// This will be our base transparency on top.
float base = 0.4 + depth*fixedVy/15.0; // TODO: murkiness.
float alphaCoeff = mix(1.0, base, extFact);
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);
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*reflectionCoords.xy - waviness * mix(1.0, 4.0,waviness/10.0) * n.zx) / reflectionCoords.z + 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
// Temp fix for some ATI cards (see irc logs on th 1st of august betwee, fexor and wraitii)
//reflCoords = clamp( (0.5*reflectionCoords.xy - waviness * mix(1.0, 20.0,waviness/10.0) * n.zx) / reflectionCoords.z + 0.5,0.0,1.0); // Unbias texture coords
//vec3 refTex = texture2D(reflectionMap, reflCoords).rgb;
//reflColor = refTex.rgb;
reflColor = vec3(0.15, 0.7, 0.82);
#endif
#if USE_REFRACTION
refrCoords = clamp( (0.5*refractionCoords.xy - n.xz * distoFactor*7.0) / refractionCoords.z + 0.5,0.0,1.0); // Unbias texture coords
vec3 refColor = texture2D(refractionMap, refrCoords).rgb;
if (refColor.r > refColor.g + refColor.b + 0.25)
{
refrCoords = clamp( (0.5*refractionCoords.xy + n.xz) / refractionCoords.z + 0.5,0.0,1.0); // Unbias texture coords
refColor = texture2D(refractionMap, refrCoords).rgb;
}
// TODO: make murkiness (both types rematter on that.
// linearly extinct the water. This is how quickly we see nothing but the pure water color
float extFact = max(0.0,1.0 - (depth*fixedVy/murky));
// This is how tinted the water is, ie how quickly the refracted floor takes the tint of the water
float ColextFact = max(0.0,1.0 - (depth*fixedVy/murky));
vec3 colll = mix(refColor*tint,refColor,ColextFact);
#if USE_SHADOWS_ON_WATER && USE_SHADOW
// TODO:
refrColor = mix(color, colll, extFact);
#else
refrColor = mix(color, colll, extFact);
#endif
#else
// linearly extinct the water. This is how quickly we see nothing but the pure water color
float extFact = max(0.0,1.0 - (depth*fixedVy/20.0));
// using both those factors, get our transparency.
// This will be our base transparency on top.
float base = 0.4 + depth*fixedVy/15.0; // TODO: murkiness.
float alphaCoeff = mix(1.0, base, extFact);
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);
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*reflectionCoords.xy - 40.0 * n.zx) / reflectionCoords.z + 0.5,0.0,1.0); // Unbias texture coords
vec4 refTex = texture2D(reflectionMap, reflCoords);
fresnel = clamp(fresnel+refTex.a/3.0,0.0,1.0);
reflColor = refTex.rgb * refTex.a + reflColor*(1.0-refTex.a);
#else
// Temp fix for some ATI cards (see irc logs on th 1st of august betwee, fexor and wraitii)
//reflCoords = clamp( (0.5*reflectionCoords.xy - waviness * mix(1.0, 20.0,waviness/10.0) * n.zx) / reflectionCoords.z + 0.5,0.0,1.0); // Unbias texture coords
//vec3 refTex = texture2D(reflectionMap, reflCoords).rgb;
//reflColor = refTex.rgb;
reflColor = vec3(0.15, 0.7, 0.82);
#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)
// So tend towards a predefined color (per-map) which looks like what the skybox would look like if you really blurred it.
@ -336,61 +338,61 @@ void main()
// Specular.
specular = pow(ndoth, mix(5.0,2000.0, clamp(v.y*v.y*2.0,0.0,1.0)))*sunColor * 1.5;// * sunColor * 1.5 * ww.r;
losMod = texture2D(losMap, losCoords.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
#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);
colour = mix(refrColor, reflColor, fresShadow * wavesFresnel);
#else
colour = mix(refrColor, reflColor, fresnel * wavesFresnel);
#endif
#if USE_SHADOWS_ON_WATER && USE_SHADOW
float fresShadow = mix(fresnel, fresnel*shadow, 0.05 + murkiness*0.2);
colour = mix(refrColor, reflColor, fresShadow * wavesFresnel);
#else
colour = mix(refrColor, reflColor, fresnel * wavesFresnel);
#endif
#if USE_SHADOWS_ON_WATER && USE_SHADOW
colour += shadow*specular;
#else
colour += specular;
#endif
#if USE_SHADOWS_ON_WATER && USE_SHADOW
colour += shadow*specular;
#else
colour += specular;
#endif
#if USE_FANCY_EFFECTS
vec4 FoamEffects = texture2D(waterEffectsTexOther, gl_FragCoord.xy/screenSize);
vec3 foam1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).aaa;
vec3 foam2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).aaa;
vec3 foam3 = texture2D(normalMap, normalCoords.st/6.0 - normalCoords.zw * 0.02).aaa;
vec3 foam4 = texture2D(normalMap2, normalCoords.st/6.0 - normalCoords.zw * 0.02).aaa;
vec3 foaminterp = mix(foam1, foam2, moddedTime);
foaminterp *= mix(foam3, foam4, moddedTime);
foam1.x = 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;
#if USE_FANCY_EFFECTS
vec4 FoamEffects = texture2D(waterEffectsTexOther, gl_FragCoord.xy/screenSize);
gl_FragColor.rgb = get_fog(colour) * losMod + foam * losMod;// + fancyeffects.a * losMod;
#else
gl_FragColor.rgb = get_fog(colour) * losMod;
#endif
vec3 foam1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).aaa;
vec3 foam2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement*waviness/10.0) * (baseScale - waviness/wavyEffect)).aaa;
vec3 foam3 = texture2D(normalMap, normalCoords.st/6.0 - normalCoords.zw * 0.02).aaa;
vec3 foam4 = texture2D(normalMap2, normalCoords.st/6.0 - normalCoords.zw * 0.02).aaa;
vec3 foaminterp = mix(foam1, foam2, moddedTime);
foaminterp *= mix(foam3, foam4, moddedTime);
#if !USE_REFRACTION
gl_FragColor.a = clamp(depth*2.0,0.0,1.0) * alphaCoeff;
#else
gl_FragColor.a = clamp(depth*5.0,0.0,1.0);
#endif
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;
#if USE_FANCY_EFFECTS
if (fancyeffects.a < 0.05 && waterDepth < -1.0 )
gl_FragColor.a = 0.0;
#endif
gl_FragColor.rgb = get_fog(colour) * losMod + foam * losMod;// + fancyeffects.a * losMod;
#else
gl_FragColor.rgb = get_fog(colour) * losMod;
#endif
#if !USE_REFRACTION
gl_FragColor.a = clamp(depth*2.0,0.0,1.0) * alphaCoeff;
#else
gl_FragColor.a = clamp(depth*5.0,0.0,1.0);
#endif
#if USE_FANCY_EFFECTS
if (fancyeffects.a < 0.05 && waterDepth < -1.0 )
gl_FragColor.a = 0.0;
#endif
//gl_FragColor = vec4(sunColor,1.0);
}

View File

@ -387,6 +387,23 @@ void WaterManager::Resize()
glBindTexture(GL_TEXTURE_2D, 0);
}
# This is for Atlas. TODO: this copies code from init, should reuse it.
void WaterManager::ReloadWaterNormalTextures()
{
wchar_t pathname[PATH_MAX];
// Load normalmaps (for fancy water)
for (size_t i = 0; i < ARRAY_SIZE(m_NormalMap); ++i)
{
swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/%ls/normal00%02d.png", m_WaterType.c_str(), (int)i+1);
CTextureProperties textureProps(pathname);
textureProps.SetWrap(GL_REPEAT);
textureProps.SetMaxAnisotropy(4);
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
texture->Prefetch();
m_NormalMap[i] = texture;
}
}
///////////////////////////////////////////////////////////////////
// Unload water textures

View File

@ -143,6 +143,12 @@ public:
*/
void Resize();
/**
* ReloadWaterNormalTextures: Reload the normal textures so that changing
* water type in Atlas will actually do the right thing.
*/
void ReloadWaterNormalTextures();
/**
* UnloadWaterTextures: Free any loaded water textures and reset the internal state
* so that another call to LoadWaterTextures will begin progressive loading.

View File

@ -103,7 +103,11 @@ void SetSettings(const sEnvironmentSettings& s)
wm->m_Waviness = s.waterwaviness;
wm->m_Murkiness = s.watermurkiness;
wm->m_WindAngle = s.windangle;
wm->m_WaterType = *s.watertype;
if (wm->m_WaterType != *s.watertype)
{
wm->m_WaterType = *s.watertype;
wm->ReloadWaterNormalTextures();
}
#define COLOUR(A, B) B = CColor(A->r/255.f, A->g/255.f, A->b/255.f, 1.f)
COLOUR(s.watercolour, wm->m_WaterColor);