Skip to content
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

Basic sky implementation #1713

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions build/generate-style-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ function propertyType(property) {
}
case 'light':
return 'LightSpecification';
case 'sky':
return 'SkySpecification';
case 'sources':
return '{[_: string]: SourceSpecification}';
case '*':
Expand Down Expand Up @@ -130,19 +132,19 @@ export type PromoteIdSpecification = {[_: string]: string} | string;

export type ExpressionInputType = string | number | boolean;

export type CollatorExpressionSpecification =
export type CollatorExpressionSpecification =
['collator', {
'case-sensitive'?: boolean | ExpressionSpecification,
'diacritic-sensitive'?: boolean | ExpressionSpecification,
'case-sensitive'?: boolean | ExpressionSpecification,
'diacritic-sensitive'?: boolean | ExpressionSpecification,
locale?: string | ExpressionSpecification}
]; // collator

export type InterpolationSpecification =
| ['linear']
| ['exponential', number | ExpressionSpecification]
| ['linear']
| ['exponential', number | ExpressionSpecification]
| ['cubic-bezier', number | ExpressionSpecification, number | ExpressionSpecification, number | ExpressionSpecification, number | ExpressionSpecification]

export type ExpressionSpecification =
export type ExpressionSpecification =
// types
| ['array', unknown | ExpressionSpecification] // array
| ['array', ExpressionInputType | ExpressionSpecification, unknown | ExpressionSpecification] // array
Expand Down Expand Up @@ -185,20 +187,20 @@ export type ExpressionSpecification =
| ['>=', ExpressionInputType | ExpressionSpecification, ExpressionInputType | ExpressionSpecification, CollatorExpressionSpecification?] // boolean
| ['all', ...(boolean | ExpressionSpecification)[]] // boolean
| ['any', ...(boolean | ExpressionSpecification)[]] // boolean
| ['case', boolean | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
| ['case', boolean | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
...(boolean | ExpressionInputType | ExpressionSpecification)[], ExpressionInputType | ExpressionSpecification]
| ['coalesce', ...(ExpressionInputType | ExpressionSpecification)[]] // at least two inputs required
| ['match', ExpressionInputType | ExpressionSpecification,
ExpressionInputType | ExpressionInputType[], ExpressionInputType | ExpressionSpecification,
| ['match', ExpressionInputType | ExpressionSpecification,
ExpressionInputType | ExpressionInputType[], ExpressionInputType | ExpressionSpecification,
...(ExpressionInputType | ExpressionInputType[] | ExpressionSpecification)[], // repeated as above
ExpressionInputType | ExpressionSpecification]
| ['within', unknown | ExpressionSpecification]
// Ramps, scales, curves
| ['interpolate', InterpolationSpecification, number | ExpressionSpecification,
| ['interpolate', InterpolationSpecification, number | ExpressionSpecification,
...(number | number[] | ColorSpecification)[]] // alternating number and number | number[] | ColorSpecification
| ['interpolate-hcl', InterpolationSpecification, number | ExpressionSpecification,
| ['interpolate-hcl', InterpolationSpecification, number | ExpressionSpecification,
...(number | ColorSpecification)[]] // alternating number and ColorSpecificaton
| ['interpolate-lab', InterpolationSpecification, number | ExpressionSpecification,
| ['interpolate-lab', InterpolationSpecification, number | ExpressionSpecification,
...(number | ColorSpecification)[]] // alternating number and ColorSpecification
| ['step', number | ExpressionSpecification, ExpressionInputType | ExpressionSpecification,
...(number | ExpressionInputType | ExpressionSpecification)[]] // alternating number and ExpressionInputType | ExpressionSpecification
Expand Down Expand Up @@ -308,6 +310,8 @@ ${objectDeclaration('StyleSpecification', spec.$root)}

${objectDeclaration('LightSpecification', spec.light)}

${objectDeclaration('SkySpecification', spec.sky)}

${objectDeclaration('TerrainSpecification', spec.terrain)}

${spec.source.map(key => objectDeclaration(sourceTypeName(key), spec[key])).join('\n\n')}
Expand Down
56 changes: 49 additions & 7 deletions src/geo/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Transform {
cameraToSeaLevelDistance: number;
mercatorMatrix: mat4;
projMatrix: mat4;
fogMatrix: mat4;
invProjMatrix: mat4;
alignedProjMatrix: mat4;
pixelMatrix: mat4;
Expand All @@ -59,6 +60,7 @@ class Transform {
_constraining: boolean;
_posMatrixCache: {[_: string]: mat4};
_alignedPosMatrixCache: {[_: string]: mat4};
_fogMatrixCache: {[_: string]: mat4};

constructor(minZoom?: number, maxZoom?: number, minPitch?: number, maxPitch?: number, renderWorldCopies?: boolean) {
this.tileSize = 512; // constant
Expand Down Expand Up @@ -86,6 +88,7 @@ class Transform {
this._edgeInsets = new EdgeInsets();
this._posMatrixCache = {};
this._alignedPosMatrixCache = {};
this._fogMatrixCache = {};
}

clone(): Transform {
Expand Down Expand Up @@ -712,6 +715,17 @@ 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} unwrappedTileID;
Expand All @@ -724,19 +738,32 @@ 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 @@ -905,6 +932,20 @@ 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 @@ -929,6 +970,7 @@ 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);
}
5 changes: 3 additions & 2 deletions src/render/draw_terrain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ 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);
}

}

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

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

Expand Down Expand Up @@ -446,6 +447,9 @@ 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};
26 changes: 22 additions & 4 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 All @@ -47,7 +54,11 @@ const terrainPreludeUniforms = (context: Context, locations: UniformLocations):
const terrainUniforms = (context: Context, locations: UniformLocations): TerrainUniformsType => ({
'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 +75,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';

const shaders = {
prelude: compile(preludeFrag, preludeVert),
Expand Down Expand Up @@ -86,8 +90,9 @@ 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)
};

export default shaders;
Expand Down
Loading