Skip to content

Commit

Permalink
Fix pixel projection in shaders (PR 1/2) (#2844)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress committed Mar 28, 2019
1 parent 58a5d2c commit 0ed3cbb
Show file tree
Hide file tree
Showing 32 changed files with 317 additions and 269 deletions.
8 changes: 3 additions & 5 deletions docs/developer-guide/coordinate-systems.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# Coordinate Systems

By default, deck.gl layers interprets positions in the [Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator) coordinate system, so when working with geospatial data (i.e with longitude and latitude encoded positions) deck.gl will automatically interpret any positions correctly.
By default, deck.gl layers interprets positions in the [Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator) coordinate system (i.e. `[longitude, latitude, altitude]`), so when working with geospatial data (i.e with longitude and latitude encoded positions) deck.gl will automatically interpret any positions correctly.

In addition, deck.gl layers can be configured to use "meter offset" based local coordinate systems, which can be quite convenient when modelling geographical data on small scales (e.g. city block level).
In addition, deck.gl layers can be configured to use a selection of alternative coordinate systems, supporting data from e.g. LIDAR sensors, and non-geospatial use cases.

Naturally, non-geospatial coordinates can also be used when working with non-geospatial data sets.

Of note is that each deck.gl layer can define its own coordinate system. Within the data supplied to a single layer, all positions must be specified in the coordinate system, however data supplied to other layers can be specified in other coordinate system.
Each deck.gl layer can define its own coordinate system. Within the data supplied to a single layer, all positions must be specified in the same coordinate system. Layers using different coordinate systems can be composed together, which is very useful when dealing with datasets from different sources.


## Supported Coordinate Systems
Expand Down
120 changes: 75 additions & 45 deletions docs/shader-modules/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

The `project` shader module is part of the core of deck.gl. It makes it easy to write shaders that support all of deck.gl's projection modes and it supports some advanced rendering techniques such as pixel space rendering etc.

Note that the `project` module has a `project64` counterpart that enables 64 bit projections, providing an increase in precision, at the cost of performance. Note that starting with deck.gl v6.1, the improved default 32 bit projection mode provides sufficient precision for most use cases.
The `project` module has two extensions:
- [project32](/docs/api-reference/shader-modules/project32.md) shorthand functions for projecting directly from worldspace to clipspace.
- [project64](/docs/api-reference/shader-modules/project64.md) counterpart of `project32` that enables 64 bit projections, providing an increase in precision, at the cost of performance.


## Usage
Expand All @@ -18,94 +20,122 @@ attribute float instanceSize;
void main(void) {
vec3 center = project_position(instanceCenter);
vec3 vertex = positions * project_scale(instanceSize);
gl_Position = project_to_clipspace(center + vertex);
vec3 vertex = positions * project_size(instanceSize);
gl_Position = project_common_position_to_clipspace(center + vertex);
}
```

## getUniforms

The JavaScript uniforms are extracted mainly from the viewport with a few additional parameters (which deck.gl supplies from `LayerManager` state or `Layer` props of course).

Provided by `LayerManager`:
The JavaScript uniforms are extracted from both contextual and per-layer props. The following information are used:

* `viewport`
* `devicePixelRatio`

Provided by `Layer` props:

* `coordinateSystem`
* `coordinateOrigin`
* `modelMatrix`


## GLSL Uniforms

Uniform names are not considered part of the official API of shader modules and can potentially change between minor releases, but are documented for applications that need this level of access. Use the module's public GLSL functions instead of directly accessing uniforms when possible.

| Uniform | Type | Description |
| --- | --- | --- |
| project_uModelMatrix | mat4 | model matrix (identity if not supplied) |
| project_uViewProjectionMatrix | mat4 | combined view projection matrix |
| project_uViewportSize | vec2 | size of viewport in pixels |
| project_uDevicePixelRatio | float | device pixel ratio of current viewport (value depends on `useDevicePixels` prop) |
| project_uFocalDistance | float | distance where "pixel sizes" are display in 1:1 ratio (modulo `devicePixelRatio`) |
| project_uCameraPosition | vec3 | position of camera in world space |
| project_uCoordinateSystem | float | COORDINATE_SYSTEM enum |
| project_uCenter | float | coordinate origin in world space |
| project_uScale | float | Web Mercator scale (2^zoom) |
| project_uPixelsPerMeter | vec3 | Web Mercator pixels per meter near the current viewport center |
| project_uPixelsPerDegree | vec3 | Web Mercator pixels per degree near the current viewport center |
Uniforms are considered private to each shader module. They may change in between patch releases. Always use documented functions instead of accessing module uniforms directly.

The uniforms of the `project` shader module are prefixed with `project_` in their names.

## GLSL Functions

The projection module makes it easy to write vertex shaders that follow deck.gl's projection methods, enabling your layer to accept coordinates in both [longitude,latitude,altitude] or [metersX,metersY,metersZ] format. To support the basic features expected of a deck.gl layer, such as various viewport types and coordinate systems, your own shaders should always use the built-in projection functions.

The functions converts positions/vectors between 4 coordinate spaces:

| Name | Short Name | Description |
|------|------|-------------|
| World space | `world` | The [coordinate system](/docs/developer-guide/coordinate-systems.md) defined by the layer, not necessarily linear or uniform. |
| Common space | `common` | A normalized intermediate 3D space that deck.gl uses for consistent processing of geometries, guaranteed to be linear and uniform. Therefore, it is safe to add/rotate/scale positions and vectors in this space. |
| Screen space | `pixel` | Top-left coordinate system runs from `[0, 0]` to `[viewportWidth, viewportHeight]` (see remarks below). |
| [Clip space](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_model_view_projection#Clip_space) | `clipspace` | Output of the vertex shader. |

The GLSL functions of the `project` shader module uses the following naming convention:

```
project_[<source_space>]_<object_type>_[to_<target_space>]
```

* `source_space`: the short name of the coordinate space of the input. If not specified, the input is always in the `world` space.
* `object_type`: one of the following
- `position`: absolute position of a point
- `offset`: the delta between two positions
- `normal`: the normal vector of a surface
- `size`: the measurement of a geometry. This is different from `offset` in that `size` is uniform on all axes (e.g. [x, y, z] in meters in `LNGLAT` world space) and `offset` may not be (e.g. [dLon, dLat, dAlt] in degrees, degrees, and meters respectively in `LNGLAT` world space).
* `target_space`: the short name of the coordinate space of the output. If not specified, the output is always in the `common` space.

### project_position

`vec2 project_position(vec2 position)`
`vec3 project_position(vec3 position)`
`vec4 project_position(vec4 position)`
```glsl
vec2 project_position(vec2 position)
vec3 project_position(vec3 position)
vec4 project_position(vec4 position)
```

Projects positions (coordinates) to worldspace coordinates. The coordinates are interpreted according to `coordinateSystem` and `modelMatrix` is applied.
Converts the coordinates of a point from the world space to the common space. The coordinates are interpreted according to `coordinateSystem` and `modelMatrix` is applied.


### project_scale
### project_size

`float project_scale(float meters)`
`vec2 project_scale(vec2 meters)`
`vec3 project_scale(vec3 meters)`
`vec4 project_scale(vec4 meters)`
```glsl
float project_size(float meters)
vec2 project_size(vec2 meters)
vec3 project_size(vec3 meters)
vec4 project_size(vec4 meters)
```

Projects sizes in meters to worldspace offsets. These offsets can be added directly to values returned by `project_position`.
Converts the size of a geometry from the world space (meters if geospatial, and absolute units otherwise) to the common space.

### project_size_to_pixel

### project_normal
```glsl
float project_size_to_pixel(float size)
```

`vec3 project_normal(vec3 vector)`
Converts the size of a geometry from the world space (meters if geospatial, and absolute units otherwise) to the common space. The result corresponds to the number of screen pixels when the given size is viewed with a top-down camera.

Projects position deltas in the current coordinate system to worldspace normals.
### project_pixel_size

```glsl
float project_pixel_size(float pixels)
```

### project_to_clipspace
Converts the size of a geometry from the screen space to the common space.

Projects world space coordinates to clipspace, which can be assigned to `gl_Position` as the "return value" from the vertex shader.
### project_pixel_size_to_clipspace

`vec4 project_to_clipspace(vec4 position)`
```glsl
vec2 project_pixel_size_to_clipspace(vec2 pixels)
```

Converts the size of a geometry from the screen space to the clip space.

### project_pixels_to_clipspace

Converts the given number of pixels to a clipspace offset that can be added to a clipspace position (typically added to values returned by `project_to_clipspace`).
### project_normal

`vec4 project_pixels_to_clipspace(vec2 pixels)`
```glsl
vec3 project_normal(vec3 vector)
```

Converts position deltas from the world space to normalized vector in the common space.


### project_common_position_to_clipspace

```glsl
vec4 project_common_position_to_clipspace(vec4 position)
```

* `pixels` (`vec2`) - adjustment in logical pixels. Returns values in clip space offsets that can be added directly to `gl_Position`
Converts the coordinates of a point from the common space to the clip space, which can be assigned to `gl_Position` as the "return value" from the vertex shader.


## Remarks

* For consistent results, pixels are logical pixels, not device pixels, i.e. this method multiplies `pixels` with `project_uDevicePixelRatio`.
* For consistent results, the screen space pixels are logical pixels, not device pixels, i.e. functions in the project module multiply `pixels` with `project_uDevicePixelRatio`.
* The pixels offsets will be divided by the `w` coordinate of `gl_Position`. This is simply the GPUs standard treatment of any coordinate. This means that there will be more pixels closer to the camera and less pixels further away from the camer. Setting the `focalDistance` uniform controls this.
* To avoid pixel sizes scaling with distance from camera, simply set `focalDistance` to 1 and multiply clipspace offset with `gl_Position.w`
13 changes: 7 additions & 6 deletions docs/shader-modules/project32.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
# project32 (Shader Module)

The `project32` shader module is an extension of the `project` shader module that adds some projection utilities.
The `project32` shader module is an extension of the [project](/docs/api-reference/shader-modules/project.md) shader module that adds some projection utilities.

## GLSL Functions

### project_position_to_clipspace

32 bit implementation of the `project_position_to_clipspace` interface.

`vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset)`

`vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset, out vec4 worldPosition)`
```glsl
vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset)
vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset, out vec4 commonPosition)
```

Parameters:

* `position` - vertex position in the layer's coordinate system.
* `position64xyLow` - always ignored
* `offset` - meter offset from the coordinate
* `worldPosition` - projected position in the world space
* `offset` - offset from the coordinate, in common space
* `commonPosition` - projected position in the common space

Returns:
Projected position in the clipspace.
35 changes: 18 additions & 17 deletions docs/shader-modules/project64.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# project64 (Shader Module)

The `project64` shader module is an extension of the `project` shader module that does projection using 64 bit floating point. This slows down the layer.
The `project64` shader module is an extension of the [project](/docs/api-reference/shader-modules/project.md) shader module that does projection using 64 bit floating point. It provides an increase in precision, at the cost of performance. Note that starting with deck.gl v6.1, the improved default 32 bit projection mode provides sufficient precision for most use cases.


## getUniforms
Expand All @@ -10,12 +10,9 @@ The uniforms needed by `project64` are extracted from the `project` module unifo

## GLSL Uniforms

Uniform names are not considered part of the official API of shader modules and can potentially change between minor releases, but are documented for applications that need this level of access. Use the module's public GLSL functions instead of directly accessing uniforms when possible.
Uniforms are considered private to each shader module. They may change in between patch releases. Always use documented functions instead of accessing module uniforms directly.

| Uniform | Type | Description |
| --- | --- | --- |
| project_uViewProjectionMatrixFP64 | uniform vec2[16] | 64-bit view projection matrix |
| project64_uScale | uniform vec2 | 64-bit Web Mercator scale |
The uniforms of the `project64` shader module are prefixed with `project64_` in their names.

## GLSL Functions

Expand All @@ -24,16 +21,17 @@ Uniform names are not considered part of the official API of shader modules and

64 bit implementation of the `project_position_to_clipspace` interface.

`vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset)`

`vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset, out vec4 worldPosition)`
```glsl
vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset)
vec4 project_position_to_clipspace(vec3 position, vec2 position64xyLow, vec3 offset, out vec4 commonPosition)
```

Parameters:

* `position` - vertex position in the layer's coordinate system.
* `position64xyLow` - low part of the vertex position's xy
* `offset` - meter offset from the coordinate
* `worldPosition` - projected position in the world space
* `offset` - offset from the coordinate, in common space
* `commonPosition` - projected position in the common space

Returns:
Projected position in the clipspace.
Expand All @@ -43,16 +41,19 @@ Projected position in the clipspace.

64 bit counterpart of the `project` modules `project_position`

`void project_position_fp64(vec4 position_fp64, out vec2 out_val[2])`

`void project_position_fp64(vec2 position, vec2 position64xyLow, out vec2 out_val[2])`
```glsl
void project_position_fp64(vec4 position_fp64, out vec2 out_val[2])
void project_position_fp64(vec2 position, vec2 position64xyLow, out vec2 out_val[2])
```


### project_to_clipspace_fp64
### project_common_position_to_clipspace_fp64

64 bit counterpart of the `project` modules `project_to_clipspace`
64 bit counterpart of the `project` modules `project_common_position_to_clipspace`

`vec4 project_to_clipspace_fp64(vec2 vertex_pos_modelspace[4])`
```glsl
vec4 project_to_clipspace_fp64(vec2 vertex_pos_modelspace[4])
```


## Remarks
Expand Down
9 changes: 9 additions & 0 deletions docs/upgrade-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@

The old experimental prop `lightSettings` in many 3D layers is no longer supported. The new and improved settings are split into two places: a [material](https://github.com/uber/luma.gl/tree/master/docs/api-reference/core/materials) prop for each 3D layer and a shared set of lights specified by [LightingEffect](/docs/effects/lighting-effect.md) with the [effects prop of Deck](/docs/api-reference/deck.md#effects).

#### project Shader Module

**Deprecations**

- `project_scale` -> `project_size`
- `project_to_clipspace` -> `project_common_position_to_clipspace`
- `project_to_clipspace_fp64` -> `project_common_position_to_clipspace_fp64`
- `project_pixel_to_clipspace` -> `project_pixel_size_to_clipspace`


## Upgrading from deck.gl v6.3 to v6.4

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void main(void) {
vec4 color = mix(minColor, maxColor, step) / 255.;
// TODO: discard when noRender is true
float finalCellSize = noRender ? 0.0 : project_scale(cellSize);
float finalCellSize = noRender ? 0.0 : project_size(cellSize);
float elevation = 0.0;
Expand Down Expand Up @@ -94,11 +94,11 @@ void main(void) {
1.0);
// extrude positions
vec4 position_worldspace;
gl_Position = project_position_to_clipspace(extrudedPosition, extrudedPosition64xyLow, offset, position_worldspace);
vec4 position_commonspace;
gl_Position = project_position_to_clipspace(extrudedPosition, extrudedPosition64xyLow, offset, position_commonspace);
if (extruded > 0.5) {
vec3 lightColor = lighting_getLightColor(color.rgb, project_uCameraPosition, position_worldspace.xyz, normals);
vec3 lightColor = lighting_getLightColor(color.rgb, project_uCameraPosition, position_commonspace.xyz, normals);
vColor = vec4(lightColor, color.a * opacity);
} else {
vColor = vec4(color.rgb, color.a * opacity);
Expand Down
1 change: 0 additions & 1 deletion modules/core/src/lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const COORDINATE_SYSTEM = {
// Positions are interpreted as [lng, lat, elevation]
// lng lat are degrees, elevation is meters. distances as meters.
LNGLAT: 1,
LNGLAT_EXPERIMENTAL: 1,
LNGLAT_DEPRECATED: 5,

// Positions are interpreted as meter offsets, distances as meters
Expand Down
Loading

0 comments on commit 0ed3cbb

Please sign in to comment.