Skip to content

Commit 77db1fe

Browse files
astojiljgithub-actions[bot]
authored andcommitted
Properly position 3D models in roads underpass areas (internal-9229)
GitOrigin-RevId: ca150daa42638aff883d83c899a2b6c297f30dee
1 parent 16d8482 commit 77db1fe

7 files changed

Lines changed: 4898 additions & 3 deletions

File tree

3d-style/data/bucket/model_bucket.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {LayerTypeMask} from '../../../3d-style/util/conflation';
1515
import {isValidUrl} from '../../../src/style-spec/validate/validate_model';
1616
import {type FeatureState, type GlobalProperties} from '../../../src/style-spec/expression/index';
1717
import Point from '@mapbox/point-geometry';
18+
import {ElevationFeatures, type ElevationFeature} from '../../elevation/elevation_feature';
1819

1920
import type ModelStyleLayer from '../../style/style_layer/model_style_layer';
2021
import type {ReplacementSource, Region} from '../../../3d-style/source/replacement_source';
@@ -64,6 +65,7 @@ class PerModelAttributes {
6465
instancedDataArray: InstanceVertexArray;
6566
instancedDataBuffer: VertexBuffer;
6667
instancesEvaluatedElevation: Array<number>; // Gets added to DEM elevation of the instance to produce value in instancedDataArray.
68+
instancesRoadElevation: Array<number> | undefined;
6769

6870
features: Array<ModelFeature>;
6971
idToFeaturesIndex: Partial<Record<string | number, number>>; // via this.features, enable lookup instancedDataArray based on feature ID.
@@ -230,6 +232,10 @@ class ModelBucket implements Bucket {
230232
const needGeometry = this.layers[0]._featureFilter.needGeometry;
231233
this.lookup = new Uint8Array(this.lookupDim * this.lookupDim);
232234

235+
// Only use elevation features when model-elevation-reference is set to hd-road-markup
236+
const usesHdRoadMarkupElevation = this.layers[0].paint.get('model-elevation-reference') === 'hd-road-markup';
237+
const elevationFeatures = usesHdRoadMarkupElevation ? options.elevationFeatures : undefined;
238+
233239
for (const {feature, id, index, sourceLayerIndex} of features) {
234240
// use non numeric id, if in properties, too.
235241
const featureId = (id != null) ? id :
@@ -249,7 +255,7 @@ class ModelBucket implements Bucket {
249255
patterns: {}
250256
};
251257

252-
const modelId = this.addFeature(bucketFeature, bucketFeature.geometry, evaluationFeature);
258+
const modelId = this.addFeature(bucketFeature, bucketFeature.geometry, evaluationFeature, elevationFeatures, canonical);
253259

254260
if (modelId) {
255261
// Since 3D model geometry extends over footprint or point geometry, it is important
@@ -442,6 +448,8 @@ class ModelBucket implements Bucket {
442448
feature: BucketFeature,
443449
geometry: Array<Array<Point>>,
444450
evaluationFeature: EvaluationFeature,
451+
elevationFeatures?: ElevationFeature[],
452+
canonical?: CanonicalTileID
445453
): string {
446454
const layer = this.layers[0];
447455
const modelIdProperty = layer.layout.get('model-id');
@@ -474,6 +482,13 @@ class ModelBucket implements Bucket {
474482
const instancedDataArray = perModelVertexArray.instancedDataArray;
475483

476484
const modelFeature = new ModelFeature(evaluationFeature, instancedDataArray.length);
485+
486+
// Query elevation feature once per feature
487+
let tiledElevation: ElevationFeature | undefined;
488+
if (elevationFeatures) {
489+
tiledElevation = ElevationFeatures.getElevationFeature(feature, elevationFeatures);
490+
}
491+
477492
for (const geometries of geometry) {
478493
for (const point of geometries) {
479494
if (point.x < 0 || point.x >= EXTENT || point.y < 0 || point.y >= EXTENT) {
@@ -493,6 +508,14 @@ class ModelBucket implements Bucket {
493508
this.instanceCount++;
494509
const i = instancedDataArray.length;
495510
instancedDataArray.resize(i + 1);
511+
512+
if (elevationFeatures) {
513+
if (!perModelVertexArray.instancesRoadElevation) {
514+
perModelVertexArray.instancesRoadElevation = [];
515+
}
516+
const roadElevation = tiledElevation ? tiledElevation.pointElevation(new Point(point.x, point.y)) : 0;
517+
perModelVertexArray.instancesRoadElevation.push(roadElevation);
518+
}
496519
perModelVertexArray.instancesEvaluatedElevation.push(0);
497520
instancedDataArray.float32[i * 16] = point.x;
498521
instancedDataArray.float32[i * 16 + 1] = point.y;
@@ -575,7 +598,8 @@ class ModelBucket implements Bucket {
575598
// Elements [4..6]: translation evaluated for the feature.
576599
va[offset + 4] = translation[0];
577600
va[offset + 5] = translation[1];
578-
va[offset + 6] = translation[2] + terrainElevationContribution;
601+
const roadElevationContribution = perModelVertexArray.instancesRoadElevation ? perModelVertexArray.instancesRoadElevation[instanceOffset] : 0;
602+
va[offset + 6] = translation[2] + roadElevationContribution + terrainElevationContribution;
579603
// Elements [7..16] Instance modelMatrix holds combined rotation and scale 3x3,
580604
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
581605
va[offset + 7] = rotationScaleYZFlip[0];

src/style-spec/reference/v8.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11429,7 +11429,7 @@
1142911429
},
1143011430
"model-elevation-reference": {
1143111431
"type": "enum",
11432-
"doc": "Selects the base of the model. Some modes might require precomputed elevation data in the tileset.",
11432+
"doc": "Selects the base of the model. Some modes might require precomputed elevation data in the tileset. When using vector tiled source as the model layer source and hd-road-markup elevation reference, this property acts as layout property and elevation is evaluated only in tile loading time.",
1143311433
"values": {
1143411434
"sea": {
1143511435
"doc": "Elevated rendering is enabled. Use this mode to elevate models relative to the sea level."
87.5 KB
Loading

0 commit comments

Comments
 (0)