Jump to content
  • Advertisement
Sign in to follow this  
kosmon_x

High contrast terrain shading

This topic is 4768 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

Hey, I've implemented some terrain shading by computing quad normals, then averaging the surrounding 4 normals to get vertex normals. To compute the shade, I do cosine = DotProduct( VertNormal, DirToLight ) and clamp negative values to 0. Then, I multiply the RGB color 1.0, 1.0, 1.0 by the cosine to get the diffuse color for that vertex. So, if the vertex normal is facing directly at the light, it will have a diffuse of pure white (no shading at all) and if its completely away it will have a diffuse of pure black. This works, but the results aren't nice since the polys are rarely facing directly at or away from the light source. What I end up with is a muddy looking terrain with little definition, since all of the polygons are somewhat shaded. An example can be seen here: What I want is higher contrast between the shaded and light regions. If I clamp the diffuse so that it's pure white if the cosine is > 0.5f and only shaded if its <= 0.5f, I get something like this: Obviously much higher contrast, which is what I want. Unfortunately since I'm throwing out all values > 0.5f, there are sharp ugly transitions. What I need is some way to modify the cosine function resulting from the dot product to get a steeper slope between 0 and 1 (larger range of values closer 0 and 1). This is beyond me -- has anyone done anything like this? [Edited by - kosmon_x on July 26, 2005 5:37:09 PM]

Share this post


Link to post
Share on other sites
Advertisement
Are you scaling the cosine to 0...1 like "cos = (cos+1)/2" or clamping by setting any negative values to zero? The latter is more correct, as direct light cannot reach a surface that's facing more than 90 degrees away from it. The "back" side of the mountain should be black in the absence of ambient lighting. (The ambient can be either a constant added on top of the direct lighting value, or calculated in some way based on the terrain)

Share this post


Link to post
Share on other sites
I'm clamping by setting any negative values to 0.. I'll edit my original post as that part is unclear ;)

Do you have any idea how I can change the dot product function to give a slope that looks more like cos(x^2)? (Atleast I think this is what I need to do?)

edit: maybe I should post that question in the Math forum? :P

Share this post


Link to post
Share on other sites
I tried this (with the help of ra in #gamedev): t = acos( DotProd(N, V) ); t = cosine( t * t ) to give a curve like cos(x^2). It gives much higher contrast shadows, however the light areas are still the same muddled grey:



Now I just need to change the function to give higher contrast lit areas as well... hmmm

Share this post


Link to post
Share on other sites
It looks like you have some abient lighting in your scene? If not, then the terrain lighting should not look that dramatic for what seems to be a mostly-overhead light. If it isnt mostly overhead, then there should be spots that are black just because they are facing >90 degrees from the light vector.

First, Try setting your clamping value to higher than 0.5, like 0.75. And it also looks like You should try just scaling your final cosine value to make an artificial "exposure". Try cos = (cos*2)-0.5. Clamp the new cos between 0 and 1. That will take your light values under 0.25 and make them black and anything 0.75 or over will be white. Unlike yours, the change is fully linear, so a value of 0.74 will be nearly white, whereas a value of 0.49 with your clamping would have been grey. Give it a try.. hope it's what you want.

Ideally, you would do something like i suggested, then apply some kind of "glow" filter to the pixels over 1 in brightness. That would give the the illusion of high-contrast, bright terrain. Without doing that, so just know... your scene will never be brighter than your texture without this, which is probably less than ideal.

Share this post


Link to post
Share on other sites
Hey thanks for the response / ideas. I tried your linear scaling of (cos*2)-0.5 (and similar values) and it works very well. The results are almost identical to cos(x^2) in the shade, but look much better in bright areas as well. I combined this with modulate2x to give brighter-than-normal areas, and here is the (preliminary) result:



Looks much, much better than the original! (First image in my original post). I'll have to tweak the scaling some more to get just the right amount of exposure :)

edit: just noticed some artifacts in the shading.. it's not quite as smooth, there are more rigid lines for some reason... even so, I'd say the sacrifice is worth it :)

Share this post


Link to post
Share on other sites
the rigid lines are because of shading. In phong shading, lighting is done per pixel. In your app, I would assume you are using gouraud shading doing vertex lighting . It's hard to explain and I couldn't find a link (sorry), but even with shared normals and normals, you still have linear interpolation between vertices. this has a picture about 1/3 down that shows a gouraud sphere in the middle. You can see in the phong image to the right that the shading between vertices isn't linear sometimes.

With high contrast and your current polygonal detail, its not going to disappear unless you write shaders for per-pixel lighting... or if you are doing this at load time and are willing to sacrifice a little accuracy, smooth out the map of lighting coefficients.

Share this post


Link to post
Share on other sites
Something must be wrong with your lighting, or you left something out of your description. If your terrain is lit the way you describe it, then the polys facing away from the light should be solid black -- but they aren't.

You say you "average" the 4 normals. How do you do that? Hopefully not (v0+v1+v2+v3)/4.

Share this post


Link to post
Share on other sites
Quote:
Original post by kosmon_x
I tried this (with the help of ra in #gamedev): t = acos( DotProd(N, V) ); t = cosine( t * t ) to give a curve like cos(x^2). It gives much higher contrast shadows, however the light areas are still the same muddled grey:


cos(x2)? That's pretty strange. Don't you mean cos(x)2?

cos(x):

cos(x2):

cos(x)2:

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
Something must be wrong with your lighting, or you left something out of your description. If your terrain is lit the way you describe it, then the polys facing away from the light should be solid black -- but they aren't.

You say you "average" the 4 normals. How do you do that? Hopefully not (v0+v1+v2+v3)/4.


I do (v0 + v1 + v2 + v3) and then normalize that, where v0-v3 are all unit vectors. Is this correct? What's the right way to do it?

EDIT: You were absolutely right.. there was a flaw in my lighting calculation. I was not taking into account vertical scaling, so when I increased the cellsize it kept the cellheight the same (effectively flattening everything out).

[Edited by - kosmon_x on July 27, 2005 4:22:33 AM]

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!