UNPKG

3d-tiles-renderer

Version:

https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification

216 lines (137 loc) 4.51 kB
import { Vector2 } from 'three'; import { TextureReadUtility } from '../utilities/TextureReadUtility.js'; import { getTexCoord, getTexelIndices, getTriangleVertexIndices } from '../utilities/TexCoordUtilities.js'; const _uv = /* @__PURE__ */ new Vector2(); const _pixel = /* @__PURE__ */ new Vector2(); const _dstPixel = /* @__PURE__ */ new Vector2(); // retrieve the appropriate UV attribute based on the tex coord index function getMaxBarycoordIndex( barycoord ) { if ( barycoord.x > barycoord.y && barycoord.x > barycoord.z ) { return 0; } else if ( barycoord.y > barycoord.z ) { return 1; } else { return 2; } } export class MeshFeatures { constructor( geometry, textures, data ) { this.geometry = geometry; this.textures = textures; this.data = data; this._asyncRead = false; // fill out feature id default values this.featureIds = data.featureIds.map( info => { const { texture, ...rest } = info; const result = { label: null, propertyTable: null, nullFeatureId: null, ...rest, }; if ( texture ) { result.texture = { texCoord: 0, channels: [ 0 ], ...texture, }; } return result; } ); } // returns list of textures getTextures() { return this.textures; } // returns a set of info for each feature getFeatureInfo() { return this.featureIds; } // performs texture data read back asynchronously getFeaturesAsync( ...args ) { this._asyncRead = true; const result = this.getFeatures( ...args ); this._asyncRead = false; return result; } // returns all features for the given point on the given triangle getFeatures( triangle, barycoord ) { const { geometry, textures, featureIds } = this; const result = new Array( featureIds.length ).fill( null ); // prep the canvas width const width = featureIds.length; TextureReadUtility.increaseSizeTo( width ); // get the attribute indices const indices = getTriangleVertexIndices( geometry, triangle ); const closestIndex = indices[ getMaxBarycoordIndex( barycoord ) ]; for ( let i = 0, l = featureIds.length; i < l; i ++ ) { // the feature id from the closest point is returned const featureId = featureIds[ i ]; const nullFeatureId = 'nullFeatureId' in featureId ? featureId.nullFeatureId : null; if ( 'texture' in featureId ) { const texture = textures[ featureId.texture.index ]; // get the attribute of the target tex coord and pixel getTexCoord( geometry, featureId.texture.texCoord, barycoord, indices, _uv ); getTexelIndices( _uv, texture.image.width, texture.image.height, _pixel ); _dstPixel.set( i, 0 ); // draw the image TextureReadUtility.renderPixelToTarget( textures[ featureId.texture.index ], _pixel, _dstPixel ); } else if ( 'attribute' in featureId ) { const attr = geometry.getAttribute( `_feature_id_${ featureId.attribute }` ); const value = attr.getX( closestIndex ); if ( value !== nullFeatureId ) { result[ i ] = value; } } else { // implicit id is based on vertex attributes, see 3d-tiles#763 const value = closestIndex; if ( value !== nullFeatureId ) { result[ i ] = value; } } } // read the buffer data const buffer = new Uint8Array( width * 4 ); if ( this._asyncRead ) { return TextureReadUtility .readDataAsync( buffer ) .then( () => { readTextureSampleResults(); return result; } ); } else { TextureReadUtility.readData( buffer ); readTextureSampleResults(); return result; } function readTextureSampleResults() { // get data based on the texture information const readBuffer = new Uint32Array( 1 ); for ( let i = 0, l = featureIds.length; i < l; i ++ ) { const featureId = featureIds[ i ]; const nullFeatureId = 'nullFeatureId' in featureId ? featureId.nullFeatureId : null; if ( 'texture' in featureId ) { // TODO: do we need to handle big-endian here? const { channels } = featureId.texture; const data = channels.map( c => buffer[ 4 * i + c ] ); new Uint8Array( readBuffer.buffer ).set( data ); const value = readBuffer[ 0 ]; if ( value !== nullFeatureId ) { result[ i ] = value; } } } } } // dispose all of the texture data used dispose() { this.textures.forEach( texture => { if ( texture ) { texture.dispose(); if ( texture.image instanceof ImageBitmap ) { texture.image.close(); } } } ); } }