Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 031f93e

Browse files
committed
feat(3d-tiles): support picking of metadata
1 parent 8b22591 commit 031f93e

File tree

2 files changed

+117
-2
lines changed

2 files changed

+117
-2
lines changed

examples/jsm/OGC3DTilesHelper.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ export function fillHTMLWithPickingInfo(event, pickingArg) {
3333
// eslint-disable-next-line
3434
htmlDiv.appendChild(createHTMLListFromObject(closestC3DTileFeature));
3535
}
36+
37+
layer.getMetadataFromIntersections(intersects).then((metadata) => {
38+
// eslint-disable-next-line
39+
metadata?.forEach(m => htmlDiv.appendChild(createHTMLListFromObject(m)));
40+
});
3641
}
3742

3843
function zoomToSphere(view, tile, sphere) {

src/Layer/OGC3DTilesLayer.js

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,90 @@ export function enableMeshoptDecoder(MeshOptDecoder) {
144144
itownsGLTFLoader.setMeshoptDecoder(MeshOptDecoder);
145145
}
146146

147+
async function getMeshFeatures(meshFeatures, options) {
148+
const { faceIndex, barycoord } = options;
149+
150+
const features = await meshFeatures.getFeaturesAsync(faceIndex, barycoord);
151+
return {
152+
features,
153+
featureIds: meshFeatures.getFeatureInfo(),
154+
};
155+
}
156+
157+
function getStructuralMetadata(structuralMetadata, options) {
158+
const { index, faceIndex, barycoord, tableIndices, features } = options;
159+
160+
const tableData = [];
161+
if (tableIndices !== undefined && features !== undefined) {
162+
structuralMetadata.getPropertyTableData(
163+
tableIndices,
164+
features,
165+
tableData,
166+
);
167+
}
168+
169+
const attributeData = [];
170+
if (index !== undefined) {
171+
structuralMetadata.getPropertyAttributeData(index, attributeData);
172+
}
173+
174+
const textureData = [];
175+
if (faceIndex !== undefined) {
176+
structuralMetadata.getPropertyTextureData(
177+
faceIndex,
178+
barycoord,
179+
textureData,
180+
);
181+
}
182+
183+
const metadata = [
184+
...tableData,
185+
...textureData,
186+
...attributeData,
187+
];
188+
189+
return metadata;
190+
}
191+
192+
async function getMetadataFromIntersection(intersection) {
193+
const { point, object, face, faceIndex } = intersection;
194+
const { meshFeatures, structuralMetadata } = object.userData;
195+
196+
const barycoord = new THREE.Vector3();
197+
if (face) {
198+
const position = object.geometry.getAttribute('position');
199+
const triangle = new THREE.Triangle().setFromAttributeAndIndices(
200+
position,
201+
face.a,
202+
face.b,
203+
face.c,
204+
);
205+
triangle.a.applyMatrix4(object.matrixWorld);
206+
triangle.b.applyMatrix4(object.matrixWorld);
207+
triangle.c.applyMatrix4(object.matrixWorld);
208+
triangle.getBarycoord(point, barycoord);
209+
} else {
210+
barycoord.set(0, 0, 0);
211+
}
212+
213+
// EXT_mesh_features
214+
const { features, featureIds } = meshFeatures ? await getMeshFeatures(meshFeatures, {
215+
faceIndex,
216+
barycoord,
217+
}) : {};
218+
const tableIndices = featureIds?.map(p => p.propertyTable);
219+
220+
// EXT_structural_metadata
221+
const metadata = structuralMetadata ? getStructuralMetadata(structuralMetadata, {
222+
...intersection,
223+
barycoord,
224+
tableIndices,
225+
features,
226+
}) : [];
227+
228+
return metadata;
229+
}
230+
147231
class OGC3DTilesLayer extends GeometryLayer {
148232
/**
149233
* Layer for [3D Tiles](https://www.ogc.org/standard/3dtiles/) datasets.
@@ -285,7 +369,8 @@ class OGC3DTilesLayer extends GeometryLayer {
285369
this._res();
286370
}
287371
});
288-
this.tilesRenderer.addEventListener('load-model', ({ scene }) => {
372+
this.tilesRenderer.addEventListener('load-model', (e) => {
373+
const { scene } = e;
289374
scene.traverse((obj) => {
290375
this._assignFinalMaterial(obj);
291376
this._assignFinalAttributes(obj);
@@ -369,10 +454,35 @@ class OGC3DTilesLayer extends GeometryLayer {
369454
this.tilesRenderer.dispose();
370455
}
371456

457+
/**
458+
* Get the [metadata](https://github.com/CesiumGS/3d-tiles/tree/main/specification/Metadata)
459+
* of the closest intersected object from a list of intersections.
460+
*
461+
* This method retrieves structured metadata stored in GLTF 2.0 assets using
462+
* the [`EXT_structural_metadata`](https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata)
463+
* extension.
464+
*
465+
* Internally, it uses the closest intersected point to index metadata
466+
* stored in property attributes and textures.
467+
*
468+
* If present in GLTF 2.0 assets, this method leverages the
469+
* [`EXT_mesh_features`](`https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_mesh_features)
470+
* extension and the returned featured to index metadata stored in property tables.
471+
*
472+
* @param {Array<THREE.Intersection>} intersections
473+
* @returns {Promise<Object | null>} - the intersected object's metadata
474+
*/
475+
async getMetadataFromIntersections(intersections) {
476+
if (!intersections.length) { return null; }
477+
478+
const metadata = await getMetadataFromIntersection(intersections[0]);
479+
return metadata;
480+
}
481+
372482
/**
373483
* Get the attributes for the closest intersection from a list of
374484
* intersects.
375-
* @param {Array} intersects - An array containing all
485+
* @param {Array<THREE.Intersection>} intersects - An array containing all
376486
* objects picked under mouse coordinates computed with view.pickObjectsAt(..).
377487
* @returns {Object | null} - An object containing
378488
*/

0 commit comments

Comments
 (0)