tangrams / tangram

WebGL map rendering engine for creative cartography
https://tangram.city
MIT License
2.22k stars 290 forks source link

Specular lighting not working as expected #680

Closed rwrx closed 6 years ago

rwrx commented 6 years ago

I am trying to create hillshading like is in OpenTopoMap - https://www.opentopomap.org in hypsometric mode (it is used only up to zoom 8). As you can see it has some slight specular, I am trying to create this effect in Tangram style, but unfortunately without a success. Here are lights I have in style:

specular_light:
    type: directional
    direction: [-1.0, 1.0, -1.0]
    diffuse: 0.0
    ambient: 0.0
    specular: 1.0
ambient_light:
    direction: [1, -1, -.01]
    type: directional
    diffuse: 1.0
    ambient: 1.0

and here is material for style:

material:
    diffuse: 0.5
    ambient: 0.5
    specular: 1.0
    shininess: 0.5

unfortunately it results only half of the screen to be actually affected by specular. I have tried several numbers to set in camera's direction, but without a luck. Here is an image of the result:

specular

Could I ask you for help, or some hints of what I am doing wrong? Thank you a lot.

rwrx commented 6 years ago

Hello, will someone look into this? Because I am not sure if I am doing something wrong or if this is an actual bug. Thank you.

bcamper commented 6 years ago

@meetar @matteblair? This may actually be correct based on the relationship of positions/surface normals from the camera to the terrain? Because specular is dependent on both the angle from light to surface and also the angle from camera eye to surface. I am just guessing / hand-waving here without looking more closely though :)

matteblair commented 6 years ago

@rwrx Do you have a scene file you can share?

I suspect you don't actually want "specular" lighting - hillshading is typically achieved with just "diffuse" lighting.

rwrx commented 6 years ago

@bcamper @matteblair thank you for your response. Actually I need to achieve similar "plasticity" for hillshading as is in OpenTopoMap and this plasticity can be achieved by specular lighting. I assume that OpenTopoMap is achieving this "plasticity" also by specular lighting as to me it seems that way. I have packed whole style into zip file, you can download it from here: https://www.dropbox.com/s/wnj5vuqm3tji0k1/basic-work-specular.zip?dl=0 . But it is heavily work in progress and also testing style to try out different things so there is a bit mess and not much optimized styling and code.

In my very old project when I did some normal mapping in 3D OpenGL scene I have one point light (not and directional light as I have set up in this scene) and when normal mapping disabled I get this:

normal_off

When I have enabled normal mapping, I get this:

normal_on

It's been years for me so I forgot most things about lighting and rendering, but I think that for the directional lighting specular lighting should be on the whole surface not depending on position of pixel in camera. I could be horribly wrong, but I just need to achieve that "plasticity" effect for hillshading as is in OpenTopoMap.

matteblair commented 6 years ago

@rwrx In every model of specular lighting that I know of, the intensity of the specular highlight at a point depends on both the incoming direction of the light from the point and the direction of the viewer from the point. This is how it the effect is calculated in Tangram's lighting model.

The desired result you're describing sounds more like a lighting-like effect and not an actual lighting model. You'll probably be better off modifying the shaders to approximate this "plastic" effect.

meetar commented 6 years ago

@rwrx I know what you're talking about and have tried to get this look before. I think the catch here is that the standard directional light model is effectively a point light an infinite distance away, so its position winds up being poorly defined for use in the specular calculation – and something about the implementation here is leading to the artifacts we're seeing. So what you want is a diffuse term with a shininess coefficient!

The way I worked around this problem in this example (code here) was to artificially limit the range of angles that the directional light's diffuse term was able to illuminate, by giving it a very shallow angle – basically using it as a rim light. This way I could crank up the diffuse value without blowing out the whole image – just a narrow range of normals.

But without a custom shader (or by changing the way diffuse specular works, which I'm not against!) you won't be able to use this trick with less shallow angles.

rwrx commented 6 years ago

@matteblair @meetar Thank you a lot for your comments. @meetar with your example code and fiddling with it I was able to achieve this:

topo

It is not exactly as in OpenTopoMap, but at least some "plasticity" is achieved. I will close this issue.

nvkelso commented 6 years ago

@rwrx that looks rad!

rwrx commented 6 years ago

@nvkelso thank you, but basically I have just put together multiple existing things :slightly_smiling_face:

meetar commented 6 years ago

basically I have just put together multiple existing things

@rwrx That's the same method I use! :D