-
-
Notifications
You must be signed in to change notification settings - Fork 640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add an Atmosphere layer for Globe (#3888) #4020
base: globe
Are you sure you want to change the base?
Conversation
Can you please add some render tests (and maybe unit test) and resolve conflict before I review this thoroughly? |
I resolve conflict. I will add some tests. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## globe #4020 +/- ##
===========================================
- Coverage 87.92% 64.62% -23.30%
===========================================
Files 250 254 +4
Lines 34910 35178 +268
Branches 2262 1503 -759
===========================================
- Hits 30694 22735 -7959
- Misses 3211 11599 +8388
+ Partials 1005 844 -161 ☔ View full report in Codecov by Sentry. |
private _globePosition: vec3 = [0, 0, 0]; | ||
private _globeRadiusPixels: number = 0.0; | ||
|
||
private _projMatrix: mat4 = mat4.create(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the atmosphere math can be done with matrices that were already present.
The _globeProjMatrix
matrix assumes the globe is a unit sphere located at (0,0,0), unrotated (so the null island is always at the unit sphere's +Z (0,0,1), see _angularCoordinatesToVector
) and projects it to screen. The already present cameraPosition
property is the camera position relative to the unit-sphere globe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The atmosphere math are performed into camera frame. I need the real globe position into the camera frame and to project each pixel as a ray into this frame also.
This is why I extract the projection matrix and compute the globe position.
The previously computed cameraPosition
do not give me the expected value. I will try to reuse some other value to avoid a new computation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try to view if I could use cameraPosition
directly, but this position include the projection effect. I need the globe position in the camera frame without the projection effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this shader could be helpful: https://github.com/maplibre/maplibre-gl-js/blob/globe/src/shaders/fill_extrusion.fragment.glsl
It computes ray-globe intersection for large fill-extrusions, which is very close to what atmopshere needs. The only part the linked shader doesn't do is getting the ray from a pixel, but your approach with the inverse matrix should work fine.
(The varying v_sphere_pos
contains the current pixel's position on the globe, relative to the unit sphere, so a point on the surface would have distance 1 from 0,0,0, a point higher up would have greater distance. See the matching vertex shader for more details.)
|
||
export type ProjectionPreludeUniformsType = { | ||
'u_projection_matrix': UniformMatrix4f; | ||
'u_projection_tile_mercator_coords': Uniform4f; | ||
'u_projection_clipping_plane': Uniform4f; | ||
'u_projection_transition': Uniform1f; | ||
'u_projection_fallback_matrix': UniformMatrix4f; | ||
'u_globe_position': Uniform3f; | ||
'u_globe_radius': Uniform1f; | ||
'u_inv_proj_matrix': UniformMatrix4f; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these new uniforms would be better suited for atmosphereUniformsType
. ProjectionData and ProjectionPreludeUniformsType
is passed to every single shader, but the uniforms added here are only used by atmosphere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will do like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
To be clean, it could be better to centralize all the projection code from transform.ts
into mercator.ts
.
But I propose to not do that in the frame of this PR and do this into a refactoring PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also like to do that, I already started looking at adapting interactions (map panning, etc.) and animations (easeTo, etc.) for globe, changing the transform and refactoring this will definitely be required. As for controls, I would like to have a "globe" and "flat" control scheme (as opposed to "mercator"), since the flat controls would likely get used by all projections except globe. As suggested at the end of this comment: maplibre/maplibre-style-spec#568 (comment)
… inv projection matrix.
I propose to wait the dicussion on maplibre/maplibre-style-spec#163 before adding some render test with the proposed style. |
Sure, that's a good idea. |
I finally had the time to play with the example. It looks amazing! I'm worried about performance though, I also tried to run it on my phone (Snapdragon 636, 1080x2280 pixel screen) and got framerate in the single digits, and the sunlight was missing for some reason. Edit: also runs at low framerate on Intel HD 630. |
Thank you :) |
Can this PR be updated? |
Based on the updated atmosphere style spec, sure ! |
@HarelM I update with the new style definition and I use the sky/atmosphere-blend parameter to decide if the atmosphere should be visible or not. The default value of 0.8 add an atmosphere to any project even if not required. Do you think a default value of 0.0 could be used to ensure no atmosphere is displayed until required ? |
Yes, the default should be 0 to keep rendering backward compatible. |
Unless you are talking about the default when globe is "on", which is not the default. |
The default value of 0.8 is define directly into the style spec. Could you made the change please ? |
No, I render the atmosphere only when a globe projection is selected. |
I see, if we only render the atmosphere when globe projection is selected then there's no problem, and I think atmosphere should be on by default so that it will look good when someone uses a globe (using globe is not the default). |
Ok, sounds like a good plan. |
@HarelM I update this PR with new style spec definition for sky and use the light position definition. I also add some tests. I think you could review it now. |
test/examples/globe-atmosphere.html
Outdated
} | ||
}, | ||
atmosphere: true, | ||
atmosphereOptions: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still relevant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Effectively, I forget to remove this elements.
test/examples/globe-atmosphere.html
Outdated
<html lang="en"> | ||
<head> | ||
<title>Display a globe with a satellite map</title> | ||
<meta property="og:description" content="Display a globe with a satellite raster baselayer." /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a word about the atmosphere here?
src/ui/map.ts
Outdated
@@ -443,6 +445,7 @@ export class Map extends Camera { | |||
painter: Painter; | |||
handlers: HandlerManager; | |||
projection: Projection; | |||
atmosphere: Atmosphere; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be part of the sky object too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the moment, Sky class contains just the style definition, not render elements as mesh that need a Context from the painter.
The Atmosphere class contains the render stuffs.
What is your proposition ? merge the two classes ? instantiate the atmosphere class into sky class ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out the sky PR, I don't see any addition to the map object besides the sky specification API.
I'm not sure what is the correct solution here though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will use the same approach.
I know this is a bit out of scope, but can we incorporate the sky implementation as part of this PR? |
src/geo/projection/projection.ts
Outdated
* @param lngLat - The longitude and latitude coordinate to transform. | ||
* @param elev - The elevation coordinate to transform. | ||
*/ | ||
transformPosition(lngLat: LngLat, elev: number): vec3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use elevation
instead of elev
.
src/geo/projection/projection.ts
Outdated
/** | ||
* Globe position in camera frame. | ||
*/ | ||
get globePosition(): vec3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are not great as this is an interface for all the projections, some of them are not globe.
Can you think of a better way to solve this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I propose to use worldCenterPosition
and worldSize
as more general properties. So, now, the information is available for any projection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my previous comment, no new projection properties should be needed for atmosphere, except maybe inverse projection matrix. Lighting can be done in world space instead of camera space, it is common practice in games. In world space, the globe is always a unit sphere placed at 0,0,0. I can suggest the code changes for this if you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I change the parameter to be more generic.
I do not understand what it is so important to do the render in world space instead of camera space.
What improvement could be expected ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, the benefits aren't very significant. It would make the code a bit smaller and maybe help with maintainability, since computing lighting is usually done in world space (or at least I have the impression that is the case).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. In fact, the shader computes atmospheric transmittance. Many implementations do it in camera space. If it is for you, I propose to let the shader like that.
src/render/atmosphere.ts
Outdated
import {Projection} from '../geo/projection/projection'; | ||
import {LngLat} from '../geo/lng_lat'; | ||
|
||
export class Atmosphere { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class needs more tests to cover its logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I simplify this class to remove the Sun position computation from the current time as with the style default value, this code could not be used. I also remove this class to split the code between Sky ans Light Style classes and draw_atmosphere method.
I look at the Sky PR during the implementation of this PR. It could propably be merged after this one also. |
I've also tried how well atmosphere runs with the reduced sample counts back when the PR was first opened, and it doesn't help all that much with performance on integrated gpus. I'm not sure such a performance-heavy feature should be on by default. Sorry for mentioning this after you already did the style spec. |
@HarelM I add some Unit Tests to improve the coverage. I hope its better now. I have some problem to test the |
Launch Checklist
This PR add a realistic atmosphere layer to the Earth when using a globe projection.
Some options allows to change the zoom level to fade in and out the atmosphere.
By default, the sun position is computed based on current time.
An optionnal date and time allows to set the sun to any position.
CHANGELOG.md
under the## main
section.