• Create Account

## Specular highlights on water

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

12 replies to this topic

### #1Hiyar  Members

Posted 08 November 2011 - 11:30 AM

Hi,
I am using animated normalmaps and usual specular calculation result looks not that good,
Is there a way to make specular highlights on water look better and natural?

Thanks

### #2Kryzon  Prime Members

Posted 08 November 2011 - 12:43 PM

I take it you already tried doing it the "right" way, so if you're interested in other approaches...

Super Mario Sunshine's Water Effect
Super Mario Sunshine uses strongly-colored ocean floors and a waving water mesh with a special noise texture. This texture is used in combination with a shader calculation to define where the shines on this water mesh will happen. An analytical view of this texture:

Notice it is mip-mapped, which means that under distance it will look different based on which pair of stages are being interpolated. The second stage is the brightest, so areas at a medium distance will be stronger than closer or really far away ones. Also note that the texture itself is completely blank, so there's no way the water will shine near the camera; only where the mip levels are used.
Anyway, SMS uses a single instance of that texture tiled over the entire water mesh (just one texture unit), but this texture is sampled twice, with two different UV values; these UV values should be scrolled in different directions and at different speeds in your game code, so that when they sample the same texture they can be added together and give an entirely unique, composited value. The water mesh also performs a waving animation with its vertices.
The shader then compares this unique color value (you can use any of the RGB channels, since the texture is grayscale) against a constant threshold\cutoff value - if the composited value is whiter\stronger than the cutoff value, it's discarded or rendered as transparent. Optionally, you can also set a lower cutoff value as the code below exemplifies:

float4 PS(
float4 Diff : COLOR0,
float4 Spec : COLOR1,
float4 Vert : TEXCOORD0,
float2 Tex1 : TEXCOORD1,
float2 Tex2 : TEXCOORD2 ) : COLOR
{
float4 waterTex0 = tex2D(baseSampler,Tex1); // The same texture, sampled twice to simulate...
float4 waterTex1 = tex2D(baseSampler,Tex2); // ...two scrolling textures without using 2 texture units.

float water = ((waterTex0.r + waterTex1.r) * Vert.r); // Composited value from the two samples.

if((water >= cutoff_bottom && water <= cutoff_top))

return float4(water,water,water,1.0f);
}

The resulting fragment will be blended with the ocean floor, thus acquiring that water-like color while giving the impression of a shine. If it fails the cutoff values, you just get the ocean floor's color. You can see this in that screenshot at the top of the post. The water mesh doesn't cover all of the visible ocean, just an area around the player - most likely to increase the performance of this effect on the GameCube. You can shape this technique to achieve whatever result you want: adding different parameters, using a 1D texture instead of that "IF" shader instruction (might be faster) etc.

I wouldn't know all this if it weren't for the ingeniousness of Arthur Carvalho (nicked "Yoasakura") of the Dolphin-Emulator forums, so big thanks to him.

Bye.

Edited by Kryzon, 21 November 2013 - 10:05 PM.

### #3Hiyar  Members

Posted 08 November 2011 - 02:08 PM

thanks for sharing this

### #4Kryzon  Prime Members

Posted 08 November 2011 - 02:50 PM

No problem.

Forgot to say; you can use the Photoshop NVIDIA DDS plugin to draw custom data on the mip-levels: http://www.modwiki.n...diting_MIP_Maps

Alternatively you can use the GIMP plugin: http://code.google.c...p-dds/

### #5Hodgman  Moderators

Posted 08 November 2011 - 05:36 PM

I am using animated normalmaps and usual specular calculation result looks not that good,
Is there a way to make specular highlights on water look better and natural?

That depends on what is not good-looking about it... Can you post a picture?

If the problem is specular aliasing, then mipmapping your normal maps with a toksvig factor, or using LEAN mapping, will help.

### #6Hiyar  Members

Posted 09 November 2011 - 12:17 PM

I am just trying to create sparkles, little specular highlights on water surface, what I am having looks more like a flat disc with little distortion.
I am using fresnel term to blend refraction and reflection maps, should I use this for specular heighlights too?

### #7Kryzon  Prime Members

Posted 09 November 2011 - 04:25 PM

I second Hodgman's question - please post a picture. It'll be loads easier to tell what's wrong.

### #8Hiyar  Members

Posted 10 November 2011 - 04:25 AM

### #9Kryzon  Prime Members

Posted 10 November 2011 - 07:18 PM

Hi Hiyar, I can see now what needs improvement. You said you wanted more noise, that it's looking "flat" the way it is. What you're missing right now is one major coloring factor: the lighting. All the noise you need is stored in those animated normal-maps; you just need something to compare them with.

There is a quick and easy way to implement something in this style. I'd like you to do the following:

• Define the sun's vector. This is a constant Float3 value, with a negative Y axis since it's pointing down. Prefer a vector that points in the same direction as the sun in your environment.

• Choose a deep-water color. This is a constant Float4 value. I suggest something in the lines of RGBA (0.0, 0.23, 0.31, 1.0).

• Compute the Dot product of the sun's vector with the current fragment's normal (taken from the animated normal-map), but transfer the result to the '1.0 ~ 0.0' range:
float lighting = (dot(sunVector, normalSample.rgb) + 1.0) * 0.5 // Transfer the dot result from '1.0 ~ -1.0' to the '1.0 ~ 0.0' range.

• Add a small offset to the lighting factor so the water doesn't perfectly reflect the environment - so it doesn't look like a flawless mirror:
lighting = max(lighting - 0.1, 0.0)

• Use that computed lighting factor to Lerp between 'deep-water color' and 'reflection map':
return lerp(deepWaterColor, reflectionSample, lighting)

• Consider that Lerp as your final fragment color.

This doesn't represent what goes on in reality, but it's a good substitute. If this doesn't look good I'll suggest you another method.
If you can, please post a picture of above in action so we can see if it's working.

### #10Hiyar  Members

Posted 11 November 2011 - 01:49 AM

I am not sure if I understand you correctly.
What exactly do you mean by deepwater color? I am using height based fog for underwater and I am using refraction map too.
You can not see this in the picture maybe
See this

for the lerp blending I am using fresnel term.
I think I am just going to experiment with different normal maps, should I use fresnel for this additional specular highlights too?

Posted 11 November 2011 - 02:02 AM

To me it looks fine. It looks like weak waves in a pond. Do you want more ocean shiny specular? You could scale your UV to tile over the water more then to get more detailed specular.

### #12Kryzon  Prime Members

Posted 11 November 2011 - 12:43 PM

Ok, since you have refraction and an ocean floor neatly set up I see why you're preferring to use fresnel. I suggest making the ocean floor very dark, so you have enough contrast against the lighter parts of the water or else it'll keep flat the way it is - so far the only part where we see the normal-map noise is at the reflected sun; you need a darker ocean floor so the other parts are visible as well.

You should also make it greener:

- Look at the first screenshot you posted.
- Then look at this one from real life: http://i39.tinypic.com/348hjs7.jpg. Your ocean floor should look as dark as the part that's shadowed by that boat. Notice how the back of every wavelet is colored by that.

### #13Hiyar  Members

Posted 11 November 2011 - 03:15 PM

My real-life reference is a lagoon-like environment click
But yes I could indeed try to use better colors.
thanks

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.