diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 48747ddf04..0ae8f04212 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -13,6 +13,7 @@ The following people have contributed to iTowns. * [Madec Germerie-Guizouarn](https://github.com/mgermerie) * [Mathieu Brédif](https://github.com/mbredif) * [Aymeric Dutremble](https://github.com/a-dutremble) + * [Raphaël Duhen](https://github.com/HoloTheDrunk) * [CIRIL Group](https://www.cirilgroup.com/en/): * [Vincent Jaillot](https://github.com/jailln) diff --git a/src/Core/Picking.js b/src/Core/Picking.js index 117d31098f..a5ed180ee8 100644 --- a/src/Core/Picking.js +++ b/src/Core/Picking.js @@ -148,11 +148,11 @@ export default { traversePickingCircle(radius, (x, y) => { const idx = (y * 2 * radius + x) * 4; - const data = buffer.slice(idx, idx + 4); + const data = buffer.slice(idx, idx + 3); // see PotreeProvider and the construction of unique_id - const objId = (data[0] << 8) | data[1]; - const index = (data[2] << 8) | data[3]; + const objId = data[0]; + const index = (data[1] << 16) | data[2]; const r = { objId, index }; diff --git a/src/Provider/PointCloudProvider.js b/src/Provider/PointCloudProvider.js index 57e24bcbf5..40d0dae4b6 100644 --- a/src/Provider/PointCloudProvider.js +++ b/src/Provider/PointCloudProvider.js @@ -1,28 +1,52 @@ import * as THREE from 'three'; import Extent from 'Core/Geographic/Extent'; +const CLOUD_ID_WORD_COUNT = 1; +const MAX_CLOUDS = 2 ** (CLOUD_ID_WORD_COUNT * 16); + +const POINT_ID_WORD_COUNT = 2; +const MAX_POINTS_PER_CLOUD = 2 ** (POINT_ID_WORD_COUNT * 16); + +const ID_WORD_COUNT = POINT_ID_WORD_COUNT + CLOUD_ID_WORD_COUNT; + let nextuuid = 1; +/** + * Generate a unique ID for every point in a cloud. + * @param {THREE.Points} points - The point cloud to add IDs to. + * @returns {THREE.Points} The resulting point cloud. + */ function addPickingAttribute(points) { - // generate unique id for picking const numPoints = points.geometry.attributes.position.count; - const ids = new Uint8Array(4 * numPoints); - const baseId = nextuuid++; - if (numPoints > 0xffff || baseId > 0xffff) { - // TODO: fixme - console.warn('Currently picking is limited to Points with less than 65535 elements and less than 65535 Points instances'); + const cloudId = nextuuid++; + + if ( + numPoints >= MAX_POINTS_PER_CLOUD || + cloudId > MAX_CLOUDS + ) { + console.warn( + `Too many points or clouds: ${numPoints} points and ${cloudId} clouds.\n` + + `Picking is currently limited to Points with less than ${MAX_POINTS_PER_CLOUD} elements and less than ${MAX_CLOUDS} Points instances`, + ); return points; } - for (let i = 0; i < numPoints; i++) { - // todo numpoints > 16bits - const v = (baseId << 16) | i; - ids[4 * i + 0] = (v & 0xff000000) >> 24; - ids[4 * i + 1] = (v & 0x00ff0000) >> 16; - ids[4 * i + 2] = (v & 0x0000ff00) >> 8; - ids[4 * i + 3] = (v & 0x000000ff) >> 0; + + // Generate and store an ID for every single point + const ids = new Uint16Array(ID_WORD_COUNT * numPoints); + for (let pointId = 0; pointId < numPoints; pointId++) { + // Full ID: + // word word word + // \__/ \_______/ + // cloudId pointId + ids[ID_WORD_COUNT * pointId + 2] = pointId & 0x0000_ffff; + ids[ID_WORD_COUNT * pointId + 1] = (pointId & 0xffff_0000) >> 16; + ids[ID_WORD_COUNT * pointId] = cloudId; } - points.baseId = baseId; - points.geometry.setAttribute('unique_id', new THREE.BufferAttribute(ids, 4, true)); + points.baseId = cloudId; + points.geometry.setAttribute( + 'unique_id', + new THREE.BufferAttribute(ids, 3, true), + ); return points; } @@ -41,7 +65,10 @@ export default { points.updateMatrix(); points.tightbbox = geometry.boundingBox.applyMatrix4(points.matrix); points.layer = layer; - points.extent = Extent.fromBox3(command.view.referenceCrs, node.bbox); + points.extent = Extent.fromBox3( + command.view.referenceCrs, + node.bbox, + ); points.userData.node = node; return points; }); diff --git a/src/Renderer/Shader/PointsVS.glsl b/src/Renderer/Shader/PointsVS.glsl index 498a60cf3d..ae604639b2 100644 --- a/src/Renderer/Shader/PointsVS.glsl +++ b/src/Renderer/Shader/PointsVS.glsl @@ -32,7 +32,7 @@ uniform float maxAttenuatedSize; attribute vec3 color; attribute vec2 range; -attribute vec4 unique_id; +attribute vec3 unique_id; attribute float intensity; attribute float classification; attribute float pointSourceID; @@ -95,7 +95,7 @@ void main() { #endif if (picking) { - vColor = unique_id; + vColor = vec4(unique_id, 1.0); } else { vColor.a = opacity; if (applyOpacityClassication || mode == PNTS_MODE_CLASSIFICATION) {