Skip to content

Commit

Permalink
copy over maplibre changes from maplibre#1713
Browse files Browse the repository at this point in the history
  • Loading branch information
acalcutt committed Aug 13, 2023
1 parent 4619234 commit b4900c8
Show file tree
Hide file tree
Showing 19 changed files with 362 additions and 24 deletions.
56 changes: 49 additions & 7 deletions src/geo/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class Transform {
cameraToCenterDistance: number;
mercatorMatrix: mat4;
projMatrix: mat4;
fogMatrix: mat4;
invProjMatrix: mat4;
alignedProjMatrix: mat4;
pixelMatrix: mat4;
Expand All @@ -56,6 +57,7 @@ export class Transform {
_constraining: boolean;
_posMatrixCache: {[_: string]: mat4};
_alignedPosMatrixCache: {[_: string]: mat4};
_fogMatrixCache: {[_: string]: mat4};
_minEleveationForCurrentTile: number;

constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean) {
Expand Down Expand Up @@ -83,6 +85,7 @@ export class Transform {
this._edgeInsets = new EdgeInsets();
this._posMatrixCache = {};
this._alignedPosMatrixCache = {};
this._fogMatrixCache = {};
this._minEleveationForCurrentTile = 0;
}

Expand Down Expand Up @@ -673,6 +676,17 @@ export class Transform {
}
}

calculateTileMatrix(unwrappedTileID: UnwrappedTileID): mat4 {
const canonical = unwrappedTileID.canonical;
const scale = this.worldSize / this.zoomScale(canonical.z);
const unwrappedX = canonical.x + Math.pow(2, canonical.z) * unwrappedTileID.wrap;

const worldMatrix = mat4.identity(new Float64Array(16) as any);
mat4.translate(worldMatrix, worldMatrix, [unwrappedX * scale, canonical.y * scale, 0]);
mat4.scale(worldMatrix, worldMatrix, [scale / EXTENT, scale / EXTENT, 1]);
return worldMatrix;
}

/**
* Calculate the posMatrix that, given a tile coordinate, would be used to display the tile on a map.
* @param unwrappedTileID - the tile ID
Expand All @@ -684,19 +698,32 @@ export class Transform {
return cache[posMatrixKey];
}

const canonical = unwrappedTileID.canonical;
const scale = this.worldSize / this.zoomScale(canonical.z);
const unwrappedX = canonical.x + Math.pow(2, canonical.z) * unwrappedTileID.wrap;

const posMatrix = mat4.identity(new Float64Array(16) as any);
mat4.translate(posMatrix, posMatrix, [unwrappedX * scale, canonical.y * scale, 0]);
mat4.scale(posMatrix, posMatrix, [scale / EXTENT, scale / EXTENT, 1]);
const posMatrix = this.calculateTileMatrix(unwrappedTileID);
mat4.multiply(posMatrix, aligned ? this.alignedProjMatrix : this.projMatrix, posMatrix);

cache[posMatrixKey] = new Float32Array(posMatrix);
return cache[posMatrixKey];
}

/**
* Calculate the fogMatrix that, given a tile coordinate, would be used to calculate fog on the map.
* @param {UnwrappedTileID} unwrappedTileID;
* @private
*/
calculateFogMatrix(unwrappedTileID: UnwrappedTileID): mat4 {
const posMatrixKey = unwrappedTileID.key;
const cache = this._fogMatrixCache;
if (cache[posMatrixKey]) {
return cache[posMatrixKey];
}

const fogMatrix = this.calculateTileMatrix(unwrappedTileID);
mat4.multiply(fogMatrix, this.fogMatrix, fogMatrix);

cache[posMatrixKey] = new Float32Array(fogMatrix);
return cache[posMatrixKey];
}

customLayerMatrix(): mat4 {
return this.mercatorMatrix.slice() as any;
}
Expand Down Expand Up @@ -867,6 +894,20 @@ export class Transform {
this.projMatrix = m;
this.invProjMatrix = mat4.invert([] as any, m);

// create a fog matrix, same es proj-matrix but with near clipping-plane in mapcenter
// needed to calculate a correct z-value for fog calculation, because projMatrix z value is not
this.fogMatrix = new Float64Array(16) as any;
mat4.perspective(this.fogMatrix, this._fov, this.width / this.height, this.cameraToSeaLevelDistance, farZ);
this.fogMatrix[8] = -offset.x * 2 / this.width;
this.fogMatrix[9] = offset.y * 2 / this.height;
mat4.scale(this.fogMatrix, this.fogMatrix, [1, -1, 1]);
mat4.translate(this.fogMatrix, this.fogMatrix, [0, 0, -this.cameraToCenterDistance]);
mat4.rotateX(this.fogMatrix, this.fogMatrix, this._pitch);
mat4.rotateZ(this.fogMatrix, this.fogMatrix, this.angle);
mat4.translate(this.fogMatrix, this.fogMatrix, [-x, -y, 0]);
mat4.scale(this.fogMatrix, this.fogMatrix, [1, 1, this._pixelPerMeter]);
mat4.translate(this.fogMatrix, this.fogMatrix, [0, 0, -this.elevation]); // elevate camera over terrain

// matrix for conversion from location to screen coordinates in 2D
this.pixelMatrix3D = mat4.multiply(new Float64Array(16) as any, this.labelPlaneMatrix, m);

Expand All @@ -891,6 +932,7 @@ export class Transform {

this._posMatrixCache = {};
this._alignedPosMatrixCache = {};
this._fogMatrixCache = {};
}

maxPitchScaleFactor() {
Expand Down
24 changes: 24 additions & 0 deletions src/render/draw_sky.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import StencilMode from '../gl/stencil_mode';
import DepthMode from '../gl/depth_mode';
import CullFaceMode from '../gl/cull_face_mode';
import {skyUniformValues} from './program/sky_program';
import type Painter from './painter';
import Sky from '../style/sky';

export default drawSky;

function drawSky(painter: Painter, sky: Sky) {
const context = painter.context;
const gl = context.gl;

const skyUniforms = skyUniformValues(sky, painter.style.map.transform, painter.pixelRatio);

const depthMode = new DepthMode(gl.LEQUAL, DepthMode.ReadWrite, [0, 1]);
const stencilMode = StencilMode.disabled;
const colorMode = painter.colorModeForRenderPass();
const program = painter.useProgram('sky');

program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode,
CullFaceMode.disabled, skyUniforms, undefined, 'sky', sky.vertexBuffer,
sky.indexBuffer, sky.segments);
}
4 changes: 3 additions & 1 deletion src/render/draw_terrain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ function drawTerrain(painter: Painter, terrain: Terrain, tiles: Array<Tile>) {
const terrainData = terrain.getTerrainData(tile.tileID);
context.activeTexture.set(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture.texture);
const eleDelta = terrain.getMeshFrameDelta(painter.transform.zoom);
const fogMatrix = painter.transform.calculateFogMatrix(tile.tileID.toUnwrapped());
const posMatrix = painter.transform.calculatePosMatrix(tile.tileID.toUnwrapped());
const uniformValues = terrainUniformValues(posMatrix, terrain.getMeshFrameDelta(painter.transform.zoom));
const uniformValues = terrainUniformValues(posMatrix, eleDelta, fogMatrix, painter.style.sky, painter.transform.pitch);
program.draw(context, gl.TRIANGLES, depthMode, StencilMode.disabled, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, 'terrain', mesh.vertexBuffer, mesh.indexBuffer, mesh.segments);
}

Expand Down
4 changes: 4 additions & 0 deletions src/render/painter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import type {IndexBuffer} from '../gl/index_buffer';
import type {DepthRangeType, DepthMaskType, DepthFuncType} from '../gl/types';
import type {ResolvedImage} from '@maplibre/maplibre-gl-style-spec';
import {RenderToTexture} from './render_to_texture';
import {drawSky} from './draw_sky';

export type RenderPass = 'offscreen' | 'opaque' | 'translucent';

Expand Down Expand Up @@ -415,6 +416,9 @@ export class Painter {
this.context.clear({color: options.showOverdrawInspector ? Color.black : Color.transparent, depth: 1});
this.clearStencil();

// draw sky first to not overwrite symbols
if (this.style.sky) drawSky(this, this.style.sky);

this._showOverdrawInspector = options.showOverdrawInspector;
this.depthRangeFor3D = [0, 1 - ((style._order.length + 2) * this.numSublayers * this.depthEpsilon)];

Expand Down
4 changes: 3 additions & 1 deletion src/render/program/program_uniforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {rasterUniforms} from './raster_program';
import {symbolIconUniforms, symbolSDFUniforms, symbolTextAndIconUniforms} from './symbol_program';
import {backgroundUniforms, backgroundPatternUniforms} from './background_program';
import {terrainUniforms, terrainDepthUniforms, terrainCoordsUniforms} from './terrain_program';
import {skyUniforms} from './sky_program';

export const programUniforms = {
fillExtrusion: fillExtrusionUniforms,
Expand Down Expand Up @@ -40,5 +41,6 @@ export const programUniforms = {
backgroundPattern: backgroundPatternUniforms,
terrain: terrainUniforms,
terrainDepth: terrainDepthUniforms,
terrainCoords: terrainCoordsUniforms
terrainCoords: terrainCoordsUniforms,
sky: skyUniforms
};
28 changes: 28 additions & 0 deletions src/render/program/sky_program.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {UniformColor, Uniform1f} from '../uniform_binding';
import type Context from '../../gl/context';
import type {UniformValues, UniformLocations} from '../uniform_binding';
import Transform from '../../geo/transform';
import Sky from '../../style/sky';

export type SkyUniformsType = {
'u_sky_color': UniformColor;
'u_fog_color': UniformColor;
'u_horizon': Uniform1f;
'u_horizon_blend': Uniform1f;
};

const skyUniforms = (context: Context, locations: UniformLocations): SkyUniformsType => ({
'u_sky_color': new UniformColor(context, locations.u_sky_color),
'u_fog_color': new UniformColor(context, locations.u_fog_color),
'u_horizon': new Uniform1f(context, locations.u_horizon),
'u_horizon_blend': new Uniform1f(context, locations.u_horizon_blend)
});

const skyUniformValues = (sky: Sky, transform: Transform, pixelRatio: number): UniformValues<SkyUniformsType> => ({
'u_sky_color': sky.properties.get('sky-color'),
'u_fog_color': sky.properties.get('fog-color'),
'u_horizon': (transform.height / 2 + transform.getHorizon()) * pixelRatio,
'u_horizon_blend': (sky.properties.get('horizon-blend') * transform.height / 2) * pixelRatio
});

export {skyUniforms, skyUniformValues};
25 changes: 22 additions & 3 deletions src/render/program/terrain_program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import {
Uniform1i,
Uniform1f,
Uniform4f,
UniformMatrix4f
UniformMatrix4f,
UniformColor
} from '../uniform_binding';
import type {Context} from '../../gl/context';
import type {UniformValues, UniformLocations} from '../../render/uniform_binding';
import {mat4} from 'gl-matrix';
import Sky from '../../style/sky';
import Color from '../../style-spec/util/color';

export type TerrainPreludeUniformsType = {
'u_depth': Uniform1i;
Expand All @@ -21,6 +24,10 @@ export type TerrainUniformsType = {
'u_matrix': UniformMatrix4f;
'u_texture': Uniform1i;
'u_ele_delta': Uniform1f;
'u_fog_matrix': UniformMatrix4f;
'u_fog_color': UniformColor;
'u_fog_blend': Uniform1f;
'u_fog_blend_opacity': Uniform1f;
};

export type TerrainDepthUniformsType = {
Expand Down Expand Up @@ -48,6 +55,11 @@ const terrainUniforms = (context: Context, locations: UniformLocations): Terrain
'u_matrix': new UniformMatrix4f(context, locations.u_matrix),
'u_texture': new Uniform1i(context, locations.u_texture),
'u_ele_delta': new Uniform1f(context, locations.u_ele_delta)
'u_ele_delta': new Uniform1f(context, locations.u_ele_delta),
'u_fog_matrix': new UniformMatrix4f(context, locations.u_fog_matrix),
'u_fog_color': new UniformColor(context, locations.u_fog_color),
'u_fog_blend': new Uniform1f(context, locations.u_fog_blend),
'u_fog_blend_opacity': new Uniform1f(context, locations.u_fog_blend_opacity)
});

const terrainDepthUniforms = (context: Context, locations: UniformLocations): TerrainDepthUniformsType => ({
Expand All @@ -64,11 +76,18 @@ const terrainCoordsUniforms = (context: Context, locations: UniformLocations): T

const terrainUniformValues = (
matrix: mat4,
eleDelta: number
eleDelta: number,
fogMatrix: mat4,
sky: Sky,
pitch: number
): UniformValues<TerrainUniformsType> => ({
'u_matrix': matrix,
'u_texture': 0,
'u_ele_delta': eleDelta
'u_ele_delta': eleDelta,
'u_fog_matrix': fogMatrix,
'u_fog_color': sky ? sky.properties.get('fog-color') : Color.white,
'u_fog_blend': sky ? sky.properties.get('fog-blend') : 1,
'u_fog_blend_opacity': sky ? sky.calculateFogBlendOpacity(pitch) : 0
});

const terrainDepthUniformValues = (
Expand Down
6 changes: 3 additions & 3 deletions src/shaders/_prelude.vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ uniform highp sampler2D u_depth;

// methods for pack/unpack depth value to texture rgba
// https://stackoverflow.com/questions/34963366/encode-floating-point-data-in-a-rgba-texture
const highp vec4 bitSh = vec4(256. * 256. * 256., 256. * 256., 256., 1.);
const highp vec4 bitShifts = vec4(1.) / bitSh;
const highp vec4 bitSh = vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0);
const highp vec4 bitShifts = vec4(1.0) / bitSh;

highp float unpack(highp vec4 color) {
return dot(color , bitShifts);
return dot(color, bitShifts);
}

// calculate the opacity behind terrain, returns a value between 0 and 1.
Expand Down
9 changes: 7 additions & 2 deletions src/shaders/shaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ import symbolTextAndIconVert from './symbol_text_and_icon.vertex.glsl.g';
import terrainDepthFrag from './terrain_depth.fragment.glsl.g';
import terrainCoordsFrag from './terrain_coords.fragment.glsl.g';
import terrainFrag from './terrain.fragment.glsl.g';
import terrainDepthVert from './terrain_depth.vertex.glsl.g';
import terrainCoordsVert from './terrain_coords.vertex.glsl.g';
import terrainVert from './terrain.vertex.glsl.g';
import skyFrag from './sky.fragment.glsl.g';
import skyVert from './sky.vertex.glsl.g';

export const shaders = {
prelude: compile(preludeFrag, preludeVert),
Expand Down Expand Up @@ -86,8 +90,9 @@ export const shaders = {
symbolSDF: compile(symbolSDFFrag, symbolSDFVert),
symbolTextAndIcon: compile(symbolTextAndIconFrag, symbolTextAndIconVert),
terrain: compile(terrainFrag, terrainVert),
terrainDepth: compile(terrainDepthFrag, terrainVert),
terrainCoords: compile(terrainCoordsFrag, terrainVert)
terrainDepth: compile(terrainDepthFrag, terrainDepthVert),
terrainCoords: compile(terrainCoordsFrag, terrainCoordsVert),
sky: compile(skyFrag, skyVert)
};

// Expand #pragmas to #ifdefs.
Expand Down
18 changes: 18 additions & 0 deletions src/shaders/sky.fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
uniform vec4 u_sky_color;
uniform vec4 u_fog_color;
uniform float u_horizon;
uniform float u_horizon_blend;

void main() {
float y = gl_FragCoord.y;
if (y > u_horizon) {
float blend = y - u_horizon;
if (blend < u_horizon_blend) {
gl_FragColor = mix(u_sky_color, u_fog_color, pow(1.0 - blend / u_horizon_blend, 2.0));
} else {
gl_FragColor = u_sky_color;
}
} else {
gl_FragColor = u_fog_color;
}
}
5 changes: 5 additions & 0 deletions src/shaders/sky.vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
attribute vec2 a_pos;

void main() {
gl_Position = vec4(a_pos, 1.0, 1.0);
}
8 changes: 8 additions & 0 deletions src/shaders/terrain.fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
uniform sampler2D u_texture;
uniform vec4 u_fog_color;
uniform float u_fog_blend;
uniform float u_fog_blend_opacity;

in vec2 v_texture_pos;
in float v_fog_depth;

void main() {
fragColor = texture(u_texture, v_texture_pos);
if (v_fog_depth > u_fog_blend) {
float a = (v_fog_depth - u_fog_blend) / (1.0 - u_fog_blend);
fragColor = mix(fragColor, u_fog_color, pow(a * u_fog_blend_opacity, 2.0));
}
}
10 changes: 8 additions & 2 deletions src/shaders/terrain.vertex.glsl
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
in vec3 a_pos3d;

uniform mat4 u_matrix;
uniform mat4 u_fog_matrix;
uniform float u_ele_delta;

out vec2 v_texture_pos;
out float v_depth;
out float v_fog_depth;

void main() {
float ele = get_elevation(a_pos3d.xy);
float extent = 8192.0; // 8192.0 is the hardcoded vector-tiles coordinates resolution
float ele_delta = a_pos3d.z == 1.0 ? u_ele_delta : 0.0;
v_texture_pos = a_pos3d.xy / extent;
gl_Position = u_matrix * vec4(a_pos3d.xy, get_elevation(a_pos3d.xy) - ele_delta, 1.0);
v_depth = gl_Position.z / gl_Position.w;
gl_Position = u_matrix * vec4(a_pos3d.xy, ele - ele_delta, 1.0);
v_depth = gl_Position.z / gl_Position.w;
vec4 pos = u_fog_matrix * vec4(a_pos3d.xy, ele, 1.0);
v_fog_depth = pos.z / pos.w * 0.5 + 0.5;

}
13 changes: 13 additions & 0 deletions src/shaders/terrain_coords.vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
attribute vec3 a_pos3d;

uniform mat4 u_matrix;
uniform float u_ele_delta;

varying vec2 v_texture_pos;

void main() {
float ele = get_elevation(a_pos3d.xy);
float ele_delta = a_pos3d.z == 1.0 ? u_ele_delta : 0.0;
v_texture_pos = a_pos3d.xy / 8192.0;
gl_Position = u_matrix * vec4(a_pos3d.xy, ele - ele_delta, 1.0);
}
Loading

0 comments on commit b4900c8

Please sign in to comment.