Skip to content

Commit 196775b

Browse files
lasselammigithub-actions[bot]
authored andcommitted
Add line-elevation-ground-scale property to scale elevated lines with terrain exaggeration (internal-9440)
GitOrigin-RevId: 5513c0747c841d28a588be8c8441d9fa0339f1fd
1 parent bfb565f commit 196775b

16 files changed

Lines changed: 1237 additions & 19 deletions

File tree

build/generate-struct-arrays.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ createStructArrayType('raster_bounds', boundsAttributes);
145145

146146
import {circleAttributes, circleAttributesExt, circleGlobeAttributesExt} from '../src/data/bucket/circle_attributes';
147147
import {fillLayoutAttributes, fillLayoutAttributesExt, intersectionsAttributes, intersectionNormalAttributes as intersectionsNormalAttributes} from '../src/data/bucket/fill_attributes';
148-
import {lineLayoutAttributes, lineZOffsetAttributes} from '../src/data/bucket/line_attributes';
148+
import {lineLayoutAttributes, lineZOffsetAttributes, lineElevationGroundScaleAttributes} from '../src/data/bucket/line_attributes';
149149
import lineAttributesExt from '../src/data/bucket/line_attributes_ext';
150150
import lineAttributesPattern from '../src/data/bucket/line_attributes_pattern';
151151
import {patternAttributes} from '../src/data/bucket/pattern_attributes';
@@ -283,6 +283,9 @@ createStructArrayType('line_strip_index', createLayout([
283283
// line z offset extension
284284
createStructArrayType('line_z_offset_ext', lineZOffsetAttributes);
285285

286+
// line elevation ground scale
287+
createStructArrayType('line_elevation_ground_scale', lineElevationGroundScaleAttributes);
288+
286289
// skybox vertex array
287290
createStructArrayType(`skybox_vertex`, skyboxAttributes);
288291

src/data/array_types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,7 @@ export {
17121712
StructArrayLayout2ui4 as LineIndexArray,
17131713
StructArrayLayout1ui2 as LineStripIndexArray,
17141714
StructArrayLayout3f12 as LineZOffsetExtArray,
1715+
StructArrayLayout1f4 as LineElevationGroundScaleArray,
17151716
StructArrayLayout3f12 as SkyboxVertexArray,
17161717
StructArrayLayout4i8 as TileBoundsArray,
17171718
StructArrayLayout3f12 as ModelLayoutArray,

src/data/bucket/line_attributes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ export const lineZOffsetAttributes: StructArrayLayout = createLayout([
1212
{name: 'a_z_offset_width', components: 3, type: 'Float32'}
1313
], 4);
1414

15+
export const lineElevationGroundScaleAttributes: StructArrayLayout = createLayout([
16+
{name: 'a_elevation_ground_scale', components: 1, type: 'Float32'}
17+
], 4);
18+
1519
export const {members, size, alignment} = lineLayoutAttributes;

src/data/bucket/line_bucket.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import {
33
LineExtLayoutArray,
44
LinePatternLayoutArray,
55
LineZOffsetExtArray,
6+
LineElevationGroundScaleArray,
67
} from '../array_types';
7-
import {members as layoutAttributes, lineZOffsetAttributes} from './line_attributes';
8+
import {members as layoutAttributes, lineZOffsetAttributes, lineElevationGroundScaleAttributes} from './line_attributes';
89
import {members as layoutAttributesExt} from './line_attributes_ext';
910
import {members as layoutAttributesPattern} from './line_attributes_pattern';
1011
import SegmentVector from '../segment';
@@ -99,6 +100,7 @@ type GradientTexture = {
99100
type LineProgressFeatures = {
100101
zOffset: number;
101102
variableWidth: number;
103+
elevationGroundScale: number;
102104
};
103105

104106
interface Subsegment {
@@ -121,6 +123,7 @@ class LineBucket implements Bucket {
121123
lineClips: LineClips | null | undefined;
122124
zOffsetValue: PossiblyEvaluatedValue<number>;
123125
variableWidthValue: PossiblyEvaluatedValue<number>;
126+
elevationGroundScaleValue: PossiblyEvaluatedValue<number>;
124127
lineFeature: BucketFeature;
125128

126129
e1: number;
@@ -155,6 +158,9 @@ class LineBucket implements Bucket {
155158
zOffsetVertexArray: LineZOffsetExtArray;
156159
zOffsetVertexBuffer: VertexBuffer;
157160

161+
elevationGroundScaleVertexArray: LineElevationGroundScaleArray;
162+
elevationGroundScaleVertexBuffer: VertexBuffer;
163+
158164
indexArray: TriangleIndexArray;
159165
indexBuffer: IndexBuffer;
160166

@@ -172,6 +178,7 @@ class LineBucket implements Bucket {
172178
evaluationGlobals = {'zoom': 0, 'lineProgress': undefined};
173179

174180
elevationType: ElevationType = 'none';
181+
isSeaLevelReference: boolean = false;
175182
heightRange: Range | undefined;
176183

177184
worldview: string;
@@ -203,6 +210,7 @@ class LineBucket implements Bucket {
203210
this.segments = new SegmentVector();
204211
this.maxLineLength = 0;
205212
this.zOffsetVertexArray = new LineZOffsetExtArray();
213+
this.elevationGroundScaleVertexArray = new LineElevationGroundScaleArray();
206214
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);
207215
// A vector tile is usually rendered over 128x128 terrain grid. Half of that frequency (step is EXTENT / 64)
208216
// should be enough since line elevation over terrain samples neighboring points.
@@ -238,6 +246,7 @@ class LineBucket implements Bucket {
238246
if (this.elevationType === 'offset' && elevationReference === 'none') {
239247
warnOnce(`line-elevation-reference: ground is used for the layer ${this.layerIds[0]} because non-zero line-z-offset value was found.`);
240248
}
249+
this.isSeaLevelReference = elevationReference === 'sea';
241250
}
242251

243252
const crossSlope = this.layers[0].layout.get('line-cross-slope');
@@ -397,6 +406,10 @@ class LineBucket implements Bucket {
397406
this.zOffsetVertexBuffer = context.createVertexBuffer(this.zOffsetVertexArray, lineZOffsetAttributes.members, true);
398407
}
399408

409+
if (!this.elevationGroundScaleVertexBuffer && this.elevationGroundScaleVertexArray.length > 0) {
410+
this.elevationGroundScaleVertexBuffer = context.createVertexBuffer(this.elevationGroundScaleVertexArray, lineElevationGroundScaleAttributes.members, true);
411+
}
412+
400413
this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, layoutAttributes);
401414
this.indexBuffer = context.createIndexBuffer(this.indexArray);
402415
}
@@ -409,6 +422,9 @@ class LineBucket implements Bucket {
409422
if (this.zOffsetVertexBuffer) {
410423
this.zOffsetVertexBuffer.destroy();
411424
}
425+
if (this.elevationGroundScaleVertexBuffer) {
426+
this.elevationGroundScaleVertexBuffer.destroy();
427+
}
412428
this.layoutVertexBuffer.destroy();
413429
this.indexBuffer.destroy();
414430
this.programConfigurations.destroy();
@@ -455,6 +471,14 @@ class LineBucket implements Bucket {
455471
this.variableWidthValue = lineWidth;
456472
}
457473

474+
// Only set elevationGroundScaleValue for sea level reference lines with non-default value
475+
if (this.isSeaLevelReference) {
476+
const elevationGroundScaleExpr = layout.get('line-elevation-ground-scale').value;
477+
if (elevationGroundScaleExpr.kind !== 'constant' || elevationGroundScaleExpr.value !== 0) {
478+
this.elevationGroundScaleValue = elevationGroundScaleExpr;
479+
}
480+
}
481+
458482
if (this.elevationType === 'road') {
459483
const vertexOffset = this.layoutVertexArray.length;
460484
const added = this.addElevatedRoadFeature(feature, geometry, canonical, elevationFeatures, join, cap, miterLimit, roundLimit);
@@ -1032,14 +1056,25 @@ class LineBucket implements Bucket {
10321056
if (this.variableWidthValue && this.variableWidthValue.kind !== 'constant') {
10331057
variableWidth = this.variableWidthValue.evaluate(this.evaluationGlobals, this.lineFeature) || 0.0;
10341058
}
1059+
const elevationGroundScale = this.evaluateElevationGroundScale();
10351060
if (this.elevationType !== 'offset') {
1036-
return {zOffset: 0.0, variableWidth};
1061+
return {zOffset: 0.0, variableWidth, elevationGroundScale};
10371062
}
10381063
if (this.zOffsetValue.kind === 'constant') {
1039-
return {zOffset: this.zOffsetValue.value, variableWidth};
1064+
return {zOffset: this.zOffsetValue.value, variableWidth, elevationGroundScale};
10401065
}
10411066
const zOffset: number = this.zOffsetValue.evaluate(this.evaluationGlobals, this.lineFeature) || 0.0;
1042-
return {zOffset, variableWidth};
1067+
return {zOffset, variableWidth, elevationGroundScale};
1068+
}
1069+
1070+
evaluateElevationGroundScale(): number {
1071+
if (!this.elevationGroundScaleValue) {
1072+
return 0.0;
1073+
}
1074+
if (this.elevationGroundScaleValue.kind === 'constant') {
1075+
return this.elevationGroundScaleValue.value;
1076+
}
1077+
return this.elevationGroundScaleValue.evaluate(this.evaluationGlobals, this.lineFeature) || 0.0;
10431078
}
10441079

10451080
/**
@@ -1184,6 +1219,11 @@ class LineBucket implements Bucket {
11841219
lineProgressFeatures.variableWidth
11851220
);
11861221
}
1222+
// Populate elevationGroundScaleVertexArray only when the property is used
1223+
if (this.elevationGroundScaleValue) {
1224+
const elevationGroundScale = lineProgressFeatures ? lineProgressFeatures.elevationGroundScale : this.evaluateElevationGroundScale();
1225+
this.elevationGroundScaleVertexArray.emplaceBack(elevationGroundScale);
1226+
}
11871227
assert(this.zOffsetVertexArray.length === this.layoutVertexArray.length || this.elevationType !== 'offset');
11881228
}
11891229

src/render/draw_line.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
274274
programConfiguration.updatePaintBuffers();
275275
}
276276

277-
if (elevated && !elevationFromSea) {
277+
if (elevated) {
278278
assert(painter.terrain);
279279
painter.terrain.setupElevationDraw(tile, program);
280280
}
@@ -287,7 +287,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
287287
program.draw(painter, gl.TRIANGLES, depthMode,
288288
stencilMode, colorMode, CullFaceMode.disabled, uniformValues,
289289
layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer, bucket.segments,
290-
layer.paint, painter.transform.zoom, programConfiguration, [bucket.layoutVertexBuffer2, bucket.patternVertexBuffer, bucket.zOffsetVertexBuffer]);
290+
layer.paint, painter.transform.zoom, programConfiguration, [bucket.layoutVertexBuffer2, bucket.patternVertexBuffer, bucket.zOffsetVertexBuffer, bucket.elevationGroundScaleVertexBuffer]);
291291
if (lineOpacityForOcclusion != null) {
292292
lineOpacityForOcclusion.value = lineOpacity; //restore
293293
}

src/render/program.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class Program<Us extends UniformBindings> {
197197

198198
// Symbol and circle layer are depth (terrain + 3d layers) occluded
199199
// For the sake of native compatibility depth occlusion goes via terrain uniforms block
200-
if (fixedDefines.includes('TERRAIN') || name.includes('symbol') || name.includes('circle')) {
200+
if (fixedDefines.includes('TERRAIN') || fixedDefines.includes('ELEVATED') || name.includes('symbol') || name.includes('circle')) {
201201
this.terrainUniforms = terrainUniforms(context);
202202
}
203203
if (fixedDefines.includes('GLOBE')) {

src/shaders/line.vertex.glsl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ in vec4 a_data;
1515
#if defined(ELEVATED) || defined(ELEVATED_ROADS) || defined(VARIABLE_LINE_WIDTH)
1616
in vec3 a_z_offset_width;
1717
#endif
18+
#ifdef ELEVATED
19+
in float a_elevation_ground_scale;
20+
#endif
1821

1922
// Includes in order: a_uv_x, a_split_index, a_line_progress
2023
// to reduce attribute count on older devices.
@@ -264,11 +267,12 @@ void main() {
264267
vec2 offsetTile = offset2 * u_pixels_to_tile_units;
265268
vec2 offset_pos = pos + offsetTile;
266269
float ele = 0.0;
270+
float scaled_z_offset = a_z_offset * mix(1.0, u_exaggeration, a_elevation_ground_scale);
267271
#ifdef CROSS_SLOPE_VERTICAL
268272
// Vertical line
269273
// The least significant bit of a_pos_normal.y hold 1 if it's on top, 0 for bottom
270274
float top = a_pos_normal.y - 2.0 * floor(a_pos_normal.y * 0.5);
271-
float line_height = 2.0 * u_tile_to_meter * outset * top * u_pixels_to_tile_units[1][1] + a_z_offset;
275+
float line_height = 2.0 * u_tile_to_meter * outset * top * u_pixels_to_tile_units[1][1] + scaled_z_offset;
272276
ele = sample_elevation(offset_pos) + line_height;
273277
// Ignore projected extrude for vertical lines
274278
projected_extrude = vec4(0);
@@ -279,14 +283,14 @@ void main() {
279283
float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
280284
float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
281285
float ele_max = max(ele0, max(ele1, ele2));
282-
ele = ele_max + a_z_offset;
286+
ele = ele_max + scaled_z_offset;
283287
#else // CROSS_SLOPE_HORIZONTAL
284288
// Line follows terrain slope
285289
float ele0 = sample_elevation(offset_pos);
286290
float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
287291
float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
288292
float ele_max = max(ele0, 0.5 * (ele1 + ele2));
289-
ele = ele_max - ele0 + ele1 + a_z_offset;
293+
ele = ele_max - ele0 + ele1 + scaled_z_offset;
290294
#endif // CROSS_SLOPE_HORIZONTAL
291295
#endif // CROSS_SLOPE_VERTICAL
292296
gl_Position = u_matrix * vec4(offset_pos, ele, 1.0) + projected_extrude;

src/shaders/line_pattern.vertex.glsl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ in vec4 a_data;
1515
#if defined(ELEVATED) || defined(ELEVATED_ROADS)
1616
in vec3 a_z_offset_width;
1717
#endif
18+
#ifdef ELEVATED
19+
in float a_elevation_ground_scale;
20+
#endif
1821
// Includes in order: a_uv_x, a_split_index, a_line_progress
1922
// to reduce attribute count on older devices.
2023
// Only line-trim-offset will requires a_packed info.
@@ -155,11 +158,12 @@ void main() {
155158
vec2 offsetTile = offset2 * u_pixels_to_tile_units;
156159
vec2 offset_pos = pos + offsetTile;
157160
float ele = 0.0;
161+
float scaled_z_offset = a_z_offset * mix(1.0, u_exaggeration, a_elevation_ground_scale);
158162
#ifdef CROSS_SLOPE_VERTICAL
159163
// Vertical line
160164
// The least significant bit of a_pos_normal.y hold 1 if it's on top, 0 for bottom
161165
float top = a_pos_normal.y - 2.0 * floor(a_pos_normal.y * 0.5);
162-
float line_height = 2.0 * u_tile_to_meter * outset * top * u_pixels_to_tile_units[1][1] + a_z_offset;
166+
float line_height = 2.0 * u_tile_to_meter * outset * top * u_pixels_to_tile_units[1][1] + scaled_z_offset;
163167
ele = sample_elevation(offset_pos) + line_height;
164168
// Ignore projected extrude for vertical lines
165169
projected_extrude = vec4(0);
@@ -170,14 +174,14 @@ void main() {
170174
float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
171175
float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
172176
float ele_max = max(ele0, max(ele1, ele2));
173-
ele = ele_max + a_z_offset;
177+
ele = ele_max + scaled_z_offset;
174178
#else // CROSS_SLOPE_HORIZONTAL
175179
// Line follows terrain slope
176180
float ele0 = sample_elevation(offset_pos);
177181
float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
178182
float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
179183
float ele_max = max(ele0, 0.5 * (ele1 + ele2));
180-
ele = ele_max - ele0 + ele1 + a_z_offset;
184+
ele = ele_max - ele0 + ele1 + scaled_z_offset;
181185
#endif // CROSS_SLOPE_HORIZONTAL
182186
#endif // CROSS_SLOPE_VERTICAL
183187
gl_Position = u_matrix * vec4(offset_pos, ele, 1.0) + projected_extrude;

src/style-spec/reference/v8.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2838,6 +2838,38 @@
28382838
]
28392839
},
28402840
"property-type": "data-constant"
2841+
},
2842+
"line-elevation-ground-scale": {
2843+
"type": "number",
2844+
"default": 0,
2845+
"minimum": 0,
2846+
"maximum": 1,
2847+
"doc": "Controls how much the elevation of lines with `line-elevation-reference` set to `sea` scales with terrain exaggeration. A value of 0 keeps the line at a fixed altitude above sea level. A value of 1 scales the elevation proportionally with terrain exaggeration.",
2848+
"sdk-support": {
2849+
"basic functionality": {
2850+
"js": "3.19.0",
2851+
"android": "11.19.0",
2852+
"ios": "11.19.0"
2853+
},
2854+
"data-driven styling": {
2855+
"js": "3.19.0",
2856+
"android": "11.19.0",
2857+
"ios": "11.19.0"
2858+
}
2859+
},
2860+
"expression": {
2861+
"interpolated": true,
2862+
"parameters": [
2863+
"zoom",
2864+
"feature",
2865+
"line-progress"
2866+
]
2867+
},
2868+
"requires": [
2869+
"line-z-offset"
2870+
],
2871+
"transition": true,
2872+
"property-type": "data-driven"
28412873
}
28422874
},
28432875
"layout_symbol": {

src/style-spec/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,9 @@ export type LineLayerSpecification = {
716716
/**
717717
* @experimental This property is experimental and subject to change in future versions.
718718
*/
719-
"line-width-unit"?: PropertyValueSpecification<"pixels" | "meters">
719+
"line-width-unit"?: PropertyValueSpecification<"pixels" | "meters">,
720+
"line-elevation-ground-scale"?: DataDrivenPropertyValueSpecification<number>,
721+
"line-elevation-ground-scale-transition"?: TransitionSpecification
720722
},
721723
"paint"?: {
722724
"line-opacity"?: DataDrivenPropertyValueSpecification<number>,

0 commit comments

Comments
 (0)