Jump to content
  • Advertisement
Sign in to follow this  
Telanor

Need some tips on improving water shader

This topic is 2028 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm working on tweaking our water shader to get a nicer look out of it and there are a couple of issues I'm not sure how to solve. The main one is that the colorization, while nice during the day, makes the water look lit up at night and is very unnatural:

[attachment=15824:RuinValor 2013-05-19 20-57-37-99.png]

All I'm doing is lerping between the sampled refraction color and a water color parameter. How can I make it so it isn't "creating light"?

Another issue I'm having is the specular. Works during the day, creates black spots at night. Running through the shader debugger, I found it was returning QNANs, but I can't understand why, I have an if-statement that should return 0 specular for when the dot product returns a negative:

float specular = dot(normalize(reflectionVector), -eyeVector);
float3 specColor = 0;

if(specular > 0)
{
	specular = pow(specular, SpecPower) * 5;
	
	if(specular > 0) //This doesnt help either
		specColor = normalize(SpecColor.rgb) * specular;
}

 
One last issue I'm working on is making the water color strength vary based on the depth of the water. I haven't been able to find any documentation online about this so I've just sort of been making something up and playing around with it to see what works well. What I've done so far is read the terrain depth buffer sampled straight along the view ray, subtracted the depth from the camera to the surface, and then used that in an exponential fog equation. It works pretty well but seems a bit strange when shallow water becomes very foggy when viewed at a shallow angle. Any advice for this?

Share this post


Link to post
Share on other sites
Advertisement

All I'm doing is lerping between the sampled refraction color and a water color parameter. How can I make it so it isn't "creating light"?

 

What are you using to light your terrain for day vs night? Seems like, at least as a start, you should just be able to multiply your water value by the incident light on a flat surface - same as you would do for flat terrain.

 

Another issue I'm having is the specular. Works during the day, creates black spots at night. Running through the shader debugger, I found it was returning QNANs, but I can't understand why, I have an if-statement that should return 0 specular for when the dot product returns a negative:
float specular = dot(normalize(reflectionVector), -eyeVector);
float3 specColor = 0;

if(specular > 0)
{
specular = pow(specular, SpecPower) * 5;

if(specular > 0) //This doesnt help either
specColor = normalize(SpecColor.rgb) * specular;
}

 

Shaders generally execute all code paths, so that may be the source of your problem. An easy solution would be to get rid of your if statements and just use saturate to clamp the specular value between 0 and 1:

 

float specular = saturate(dot(normalize(reflectionVector), -eyeVector));

Share this post


Link to post
Share on other sites
Changing the if statement to a saturate made the water turn entirely black at night. I'll give the lighting thing a try and see how that works out.

Share this post


Link to post
Share on other sites
Ok, so a quick test of the lighting idea. I just multiplied the dot(normal, lightVector) with the final color. It works pretty well

[attachment=15825:RuinValor 2013-05-20 18-40-16-54.png]

It's a little too dark too soon though.

unbird: I am using fresnel. The reflections weren't working right before though, I've fixed them now and the shallow angle fog seems to be a lot less of a problem.

Share this post


Link to post
Share on other sites
Ok, two more issues. The lighting equation is causing the backside of waves to turn black:

[attachment=15828:RuinValor 2013-05-20 20-44-29-97.png]

Also, this is something that's been around for a while. One side of the wave (I'm guessing it's the back) is getting a strong reflection while the other side has a strong refraction. It's creating a kind of spotted/streak effect near the viewer where the water will be mostly transparent with spots of strong blue (from the sky) mixed in. This seems pretty unnatural to me. Any suggestions?

[attachment=15829:RuinValor-2013-05-20-20-45-20-21.jpg]

And again with the water set to an orange color (in this case there are also some strong orange spots):

[attachment=15830:RuinValor 2013-05-20 20-58-48-77.png]

Share this post


Link to post
Share on other sites

Any thoughts on this guys? This would be of great help if we could get this resolved. Thanks in advance!

Share this post


Link to post
Share on other sites

Firstly, on the subject of bright water:

 

Backing up a bit, I think it's helpful to understand where that 'water color' comes from. Physically, you're doing a very simple (but workable) approximation to multiple scattering-- basically light is entering the water all over the surface, bouncing around a little bit *inside* the water volume, then leaving towards the viewer... among other directions. You can get all crazy and simulate this numerically, but it turns out just having a single, flat color does a pretty good job of capturing the core 'light enters somewhere, leaves elsewhere' effect.

 

Intuitively, you just need to control that simulated incoming amount of light. Since we're throwing correctness out the window already, I'd suggest doing the simple, controllable thing and just have a sort of 'day water color' and 'night water color' and then blend between those (preferably on the CPU!) before handing it off to the shader. In order to save artist work, it seems like you could analytically figure out what the difference between night light and day light is and then just apply that directly to the 'day' color.

 

Re: streaking--

 

That's a problem with your eye vector resulting from your water surface approximation; (I'd bet good money you're just using a single flat plane + normal map for the water surface) it's entirely physically accurate. The issue arises because water (and surfaces in general) don't really change orientation without some intuitive change in 'position' (and hence eye vector) to go along. Ideally you'd do away with the normal map entirely and just have a nicely tessellated/displaced water volume, but if that's off the table then you may be able to fake a displacement in the eye vector by adding a small vector scaled by a height value in the normal map alpha or some other such unused channel.

Share this post


Link to post
Share on other sites
Ah, so the streaking can't be fixed without actually making the plane 3D. I managed to figure out the specular issue. The backsides of waves being black is about the only issue left now.

Share this post


Link to post
Share on other sites

The backsides of waves being black is about the only issue left now.

This is often an issue with screen normals pointing into the screen. The assumption, that all screen normals point outside the screen is just wrong, therefore you need to take special care of these normals.

 

One case would be, when using compression (xyz to 2 channel compression). E.g. the naive compression, when only saving the x and y coord of the normal and reconstructing z from them (z = -sqrt(x*x+y*y) ) will not work in this case. Although clamping could be a problem.

 

Therefore check your code for issues when your normals point into the screen.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!