@xeokit/xeokit-sdk 2.4.2-beta-14 → 2.4.2-beta-19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -352,6 +352,11 @@ class Scene extends Component {
352
352
  throw "Mandatory config expected: valid canvasId or canvasElement";
353
353
  }
354
354
 
355
+ /**
356
+ * @type {{[key: string]: {wrapperFunc: Function, tickSubId: string}}}
357
+ */
358
+ this._tickifiedFunctions = {};
359
+
355
360
  const transparent = (!!cfg.transparent);
356
361
  const alphaDepthMask = (!!cfg.alphaDepthMask);
357
362
 
@@ -2149,6 +2154,9 @@ class Scene extends Component {
2149
2154
  * @param {Number[]} [params.matrix] 4x4 transformation matrix to define the World-space ray origin and direction, as an alternative to ````origin```` and ````direction````.
2150
2155
  * @param {String[]} [params.includeEntities] IDs of {@link Entity}s to restrict picking to. When given, ignores {@link Entity}s whose IDs are not in this list.
2151
2156
  * @param {String[]} [params.excludeEntities] IDs of {@link Entity}s to ignore. When given, will pick *through* these {@link Entity}s, as if they were not there.
2157
+ * @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
2158
+ * @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
2159
+ * @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
2152
2160
  * @param {PickResult} [pickResult] Holds the results of the pick attempt. Will use the Scene's singleton PickResult if you don't supply your own.
2153
2161
  * @returns {PickResult} Holds results of the pick attempt, returned when an {@link Entity} is picked, else null. See method comments for description.
2154
2162
  */
@@ -2183,14 +2191,25 @@ class Scene extends Component {
2183
2191
  this._needRecompile = false;
2184
2192
  }
2185
2193
 
2186
- pickResult = this._renderer.pick(params, pickResult);
2194
+ if (params.snapToEdge || params.snapToVertex) {
2195
+ pickResult = this._renderer.snapPick(
2196
+ params.canvasPos,
2197
+ params.snapRadius || 30,
2198
+ params.snapToVertex,
2199
+ params.snapToEdge,
2200
+ pickResult
2201
+ );
2202
+ } else {
2203
+ pickResult = this._renderer.pick(params, pickResult);
2204
+ }
2187
2205
 
2188
2206
  if (pickResult) {
2189
2207
  if (pickResult.entity && pickResult.entity.fire) {
2190
- pickResult.entity.fire("picked", pickResult); // TODO: PerformanceModelNode doesn't fire events
2208
+ pickResult.entity.fire("picked", pickResult); // TODO: SceneModelEntity doesn't fire events
2191
2209
  }
2192
- return pickResult;
2193
2210
  }
2211
+
2212
+ return pickResult;
2194
2213
  }
2195
2214
 
2196
2215
  /**
@@ -2199,8 +2218,13 @@ class Scene extends Component {
2199
2218
  * @param {Number} [params.snapRadius=30] The snap radius, in canvas pixels
2200
2219
  * @param {boolean} [params.snapToVertex=true] Whether to snap to vertex.
2201
2220
  * @param {boolean} [params.snapToEdge=true] Whether to snap to edge.
2221
+ * @deprecated
2202
2222
  */
2203
2223
  snapPick(params) {
2224
+ if (undefined === this._warnSnapPickDeprecated) {
2225
+ this._warnSnapPickDeprecated = true;
2226
+ this.warn("Scene.snapPick() is deprecated since v2.4.2 - use Scene.pick() instead")
2227
+ }
2204
2228
  return this._renderer.snapPick(
2205
2229
  params.canvasPos,
2206
2230
  params.snapRadius || 30,
@@ -2562,6 +2586,63 @@ class Scene extends Component {
2562
2586
  return changed;
2563
2587
  }
2564
2588
 
2589
+ /**
2590
+ * This method will "tickify" the provided `cb` function.
2591
+ *
2592
+ * This means, the function will be wrapped so:
2593
+ *
2594
+ * - it runs time-aligned to scene ticks
2595
+ * - it runs maximum once per scene-tick
2596
+ *
2597
+ * @param {Function} cb The function to tickify
2598
+ * @returns {Function)}
2599
+ */
2600
+ tickify(cb) {
2601
+ const cbString = cb.toString();
2602
+
2603
+ /**
2604
+ * Check if the function is already tickified, and if so return the cached one.
2605
+ */
2606
+ if (cbString in this._tickifiedFunctions) {
2607
+ return this._tickifiedFunctions[cbString].wrapperFunc;
2608
+ }
2609
+
2610
+ let alreadyRun = 0;
2611
+ let needToRun = 0;
2612
+
2613
+ let lastArgs;
2614
+
2615
+ /**
2616
+ * The provided `cb` function is replaced with a "set-dirty" function
2617
+ *
2618
+ * @type {Function}
2619
+ */
2620
+ const wrapperFunc = function (...args) {
2621
+ lastArgs = args;
2622
+ needToRun++;
2623
+ };
2624
+
2625
+ /**
2626
+ * An each scene tick, if the "dirty-flag" is set, run the `cb` function.
2627
+ *
2628
+ * This will make it run time-aligned to the scene tick.
2629
+ */
2630
+ const tickSubId = this.on("tick", () => {
2631
+ const tmp = needToRun;
2632
+ if (tmp > alreadyRun) {
2633
+ alreadyRun = tmp;
2634
+ cb(...lastArgs);
2635
+ }
2636
+ });
2637
+
2638
+ /**
2639
+ * And, store the list of subscribers.
2640
+ */
2641
+ this._tickifiedFunctions[cbString] = { tickSubId, wrapperFunc };
2642
+
2643
+ return wrapperFunc;
2644
+ }
2645
+
2565
2646
  /**
2566
2647
  * Destroys this Scene.
2567
2648
  */
@@ -60,13 +60,14 @@ class PickResult {
60
60
  */
61
61
  this.snappedToVertex = false;
62
62
 
63
- this._canvasPos = new Int16Array([0, 0]);
64
63
  this._origin = new Float64Array([0, 0, 0]);
65
64
  this._direction = new Float64Array([0, 0, 0]);
66
65
  this._indices = new Int32Array(3);
67
66
  this._localPos = new Float64Array([0, 0, 0]);
68
67
  this._worldPos = new Float64Array([0, 0, 0]);
69
68
  this._viewPos = new Float64Array([0, 0, 0]);
69
+ this._canvasPos = new Int16Array([0, 0]);
70
+ this._snappedCanvasPos = new Int16Array([0, 0]);
70
71
  this._bary = new Float64Array([0, 0, 0]);
71
72
  this._worldNormal = new Float64Array([0, 0, 0]);
72
73
  this._uv = new Float64Array([0, 0]);
@@ -75,7 +76,7 @@ class PickResult {
75
76
  }
76
77
 
77
78
  /**
78
- * Canvas coordinates when picking with a 2D pointer.
79
+ * Canvas pick coordinates.
79
80
  * @property canvasPos
80
81
  * @type {Number[]}
81
82
  */
@@ -193,6 +194,29 @@ class PickResult {
193
194
  }
194
195
  }
195
196
 
197
+ /**
198
+ * Canvas cursor coordinates, snapped when snap picking, otherwise same as {@link PickResult#pointerPos}.
199
+ * @property snappedCanvasPos
200
+ * @type {Number[]}
201
+ */
202
+ get snappedCanvasPos() {
203
+ return this._gotSnappedCanvasPos ? this._snappedCanvasPos : null;
204
+ }
205
+
206
+ /**
207
+ * @private
208
+ * @param value
209
+ */
210
+ set snappedCanvasPos(value) {
211
+ if (value) {
212
+ this._snappedCanvasPos[0] = value[0];
213
+ this._snappedCanvasPos[1] = value[1];
214
+ this._gotSnappedCanvasPos = true;
215
+ } else {
216
+ this._gotSnappedCanvasPos = false;
217
+ }
218
+ }
219
+
196
220
  /**
197
221
  * Picked World-space point.
198
222
  * @property worldPos
@@ -321,6 +345,7 @@ class PickResult {
321
345
  this.primitive = null;
322
346
  this.pickSurfacePrecision = false;
323
347
  this._gotCanvasPos = false;
348
+ this._gotSnappedCanvasPos = false;
324
349
  this._gotOrigin = false;
325
350
  this._gotDirection = false;
326
351
  this._gotIndices = false;
@@ -1283,255 +1283,260 @@ const Renderer = function (scene, options) {
1283
1283
  * @param {number} [snapRadiusInPixels=30]
1284
1284
  * @param {boolean} [snapToVertex=true]
1285
1285
  * @param {boolean} [snapToEdge=true]
1286
- *
1287
- * @returns {{worldPos:number[],snappedWorldPos:null|number[],snappedCanvasPos:null|number[], snapType:null|"vertex"|"edge"}}
1286
+ * @param pickResult
1287
+ * @returns {PickResult}
1288
1288
  */
1289
- this.snapPick = function (canvasPos, snapRadiusInPixels = 30, snapToVertex = true, snapToEdge = true) {
1290
-
1291
- if (!snapToVertex && !snapToEdge) {
1292
- return this.pick({canvasPos, pickSurface: true});
1293
- }
1289
+ this.snapPick = (function () {
1294
1290
 
1295
- const resolutionScale = scene.canvas.resolutionScale;
1296
-
1297
- frameCtx.reset();
1298
- frameCtx.backfaces = true;
1299
- frameCtx.frontface = true; // "ccw"
1300
- frameCtx.pickZNear = scene.camera.project.near;
1301
- frameCtx.pickZFar = scene.camera.project.far;
1302
-
1303
- const vertexPickBuffer = renderBufferManager.getRenderBuffer("uniquePickColors-aabs", {
1304
- depthTexture: true,
1305
- size: [
1306
- 2 * snapRadiusInPixels + 1,
1307
- 2 * snapRadiusInPixels + 1,
1308
- ]
1309
- });
1291
+ const _pickResult = new PickResult();
1310
1292
 
1311
- frameCtx.snapVectorA = [
1312
- getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
1313
- getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight),
1314
- ];
1293
+ return function (canvasPos, snapRadiusInPixels, snapToVertex, snapToEdge, pickResult = _pickResult) {
1315
1294
 
1316
- frameCtx.snapInvVectorAB = [
1317
- gl.drawingBufferWidth / (2 * snapRadiusInPixels),
1318
- gl.drawingBufferHeight / (2 * snapRadiusInPixels),
1319
- ];
1295
+ if (!snapToVertex && !snapToEdge) {
1296
+ return this.pick({canvasPos, pickSurface: true});
1297
+ }
1320
1298
 
1321
- // Bind and clear the snap render target
1299
+ const resolutionScale = scene.canvas.resolutionScale;
1322
1300
 
1323
- vertexPickBuffer.bind(gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI);
1324
- gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
1325
- gl.enable(gl.DEPTH_TEST);
1326
- gl.frontFace(gl.CCW);
1327
- gl.disable(gl.CULL_FACE);
1328
- gl.depthMask(true);
1329
- gl.disable(gl.BLEND);
1330
- gl.depthFunc(gl.LEQUAL);
1331
- gl.clear(gl.DEPTH_BUFFER_BIT);
1332
- gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
1333
- gl.clearBufferiv(gl.COLOR, 1, new Int32Array([0, 0, 0, 0]));
1334
- gl.clearBufferuiv(gl.COLOR, 2, new Uint32Array([0, 0, 0, 0]));
1301
+ frameCtx.reset();
1302
+ frameCtx.backfaces = true;
1303
+ frameCtx.frontface = true; // "ccw"
1304
+ frameCtx.pickZNear = scene.camera.project.near;
1305
+ frameCtx.pickZFar = scene.camera.project.far;
1335
1306
 
1336
- //////////////////////////////////
1337
- // Set view and proj mats for VBO renderers
1338
- ///////////////////////////////////////
1307
+ snapRadiusInPixels = snapRadiusInPixels || 30;
1339
1308
 
1340
- const pickViewMatrix = scene.camera.viewMatrix;
1341
- const pickProjMatrix = scene.camera.projMatrix;
1309
+ const vertexPickBuffer = renderBufferManager.getRenderBuffer("uniquePickColors-aabs", {
1310
+ depthTexture: true,
1311
+ size: [
1312
+ 2 * snapRadiusInPixels + 1,
1313
+ 2 * snapRadiusInPixels + 1,
1314
+ ]
1315
+ });
1342
1316
 
1343
- for (let type in drawableTypeInfo) {
1344
- if (drawableTypeInfo.hasOwnProperty(type)) {
1345
- const drawableList = drawableTypeInfo[type].drawableList;
1346
- for (let i = 0, len = drawableList.length; i < len; i++) {
1347
- const drawable = drawableList[i];
1348
- if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
1349
- drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
1350
- }
1351
- }
1352
- }
1353
- }
1317
+ frameCtx.snapVectorA = [
1318
+ getClipPosX(canvasPos[0] * resolutionScale, gl.drawingBufferWidth),
1319
+ getClipPosY(canvasPos[1] * resolutionScale, gl.drawingBufferHeight),
1320
+ ];
1354
1321
 
1355
- // a) init z-buffer
1356
- gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
1357
- const layerParamsSurface = snapInitDepthBuf(frameCtx);
1322
+ frameCtx.snapInvVectorAB = [
1323
+ gl.drawingBufferWidth / (2 * snapRadiusInPixels),
1324
+ gl.drawingBufferHeight / (2 * snapRadiusInPixels),
1325
+ ];
1358
1326
 
1359
- // b) snap-pick
1360
- const layerParamsSnap = []
1361
- frameCtx.snapPickLayerParams = layerParamsSnap;
1327
+ // Bind and clear the snap render target
1362
1328
 
1363
- gl.depthMask(false);
1364
- gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
1329
+ vertexPickBuffer.bind(gl.RGBA32I, gl.RGBA32I, gl.RGBA8UI);
1330
+ gl.viewport(0, 0, vertexPickBuffer.size[0], vertexPickBuffer.size[1]);
1331
+ gl.enable(gl.DEPTH_TEST);
1332
+ gl.frontFace(gl.CCW);
1333
+ gl.disable(gl.CULL_FACE);
1334
+ gl.depthMask(true);
1335
+ gl.disable(gl.BLEND);
1336
+ gl.depthFunc(gl.LEQUAL);
1337
+ gl.clear(gl.DEPTH_BUFFER_BIT);
1338
+ gl.clearBufferiv(gl.COLOR, 0, new Int32Array([0, 0, 0, 0]));
1339
+ gl.clearBufferiv(gl.COLOR, 1, new Int32Array([0, 0, 0, 0]));
1340
+ gl.clearBufferuiv(gl.COLOR, 2, new Uint32Array([0, 0, 0, 0]));
1365
1341
 
1366
- if (snapToVertex && snapToEdge) {
1367
- frameCtx.snapMode = "edge";
1368
- snapPickDrawSnapDepths(frameCtx);
1342
+ //////////////////////////////////
1343
+ // Set view and proj mats for VBO renderers
1344
+ ///////////////////////////////////////
1369
1345
 
1370
- frameCtx.snapMode = "vertex";
1371
- frameCtx.snapPickLayerNumber++;
1346
+ const pickViewMatrix = scene.camera.viewMatrix;
1347
+ const pickProjMatrix = scene.camera.projMatrix;
1372
1348
 
1373
- snapPickDrawSnapDepths(frameCtx);
1374
- } else {
1375
- frameCtx.snapMode = snapToVertex ? "vertex" : "edge";
1376
-
1377
- snapPickDrawSnapDepths(frameCtx);
1378
- }
1349
+ for (let type in drawableTypeInfo) {
1350
+ if (drawableTypeInfo.hasOwnProperty(type)) {
1351
+ const drawableList = drawableTypeInfo[type].drawableList;
1352
+ for (let i = 0, len = drawableList.length; i < len; i++) {
1353
+ const drawable = drawableList[i];
1354
+ if (drawable.setPickMatrices) { // Eg. SceneModel, which needs pre-loading into texture
1355
+ drawable.setPickMatrices(pickViewMatrix, pickProjMatrix);
1356
+ }
1357
+ }
1358
+ }
1359
+ }
1379
1360
 
1380
- gl.depthMask(true);
1361
+ // a) init z-buffer
1362
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2]);
1363
+ const layerParamsSurface = snapInitDepthBuf(frameCtx);
1381
1364
 
1382
- // Read and decode the snapped coordinates
1365
+ // b) snap-pick
1366
+ const layerParamsSnap = []
1367
+ frameCtx.snapPickLayerParams = layerParamsSnap;
1383
1368
 
1384
- const snapPickResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
1385
- const snapPickNormalResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4, 1);
1386
- const snapPickIdResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.UNSIGNED_INT, Uint32Array, 4, 2);
1369
+ gl.depthMask(false);
1370
+ gl.drawBuffers([gl.COLOR_ATTACHMENT0]);
1387
1371
 
1388
- vertexPickBuffer.unbind();
1372
+ if (snapToVertex && snapToEdge) {
1373
+ frameCtx.snapMode = "edge";
1374
+ snapPickDrawSnapDepths(frameCtx);
1389
1375
 
1390
- // result 1) regular hi-precision world position
1376
+ frameCtx.snapMode = "vertex";
1377
+ frameCtx.snapPickLayerNumber++;
1391
1378
 
1392
- let worldPos = null;
1393
- let worldNormal = null;
1394
- let pickable = null;
1379
+ snapPickDrawSnapDepths(frameCtx);
1380
+ } else {
1381
+ frameCtx.snapMode = snapToVertex ? "vertex" : "edge";
1395
1382
 
1396
- const middleX = snapRadiusInPixels;
1397
- const middleY = snapRadiusInPixels;
1398
- const middleIndex = (middleX * 4) + (middleY * vertexPickBuffer.size[0] * 4);
1399
- const pickResultMiddleXY = snapPickResultArray.slice(middleIndex, middleIndex + 4);
1400
- const pickNormalResultMiddleXY = snapPickNormalResultArray.slice(middleIndex, middleIndex + 4);
1401
- const pickPickableResultMiddleXY = snapPickIdResultArray.slice(middleIndex, middleIndex + 4);
1383
+ snapPickDrawSnapDepths(frameCtx);
1384
+ }
1402
1385
 
1403
- if (pickResultMiddleXY[3] !== 0) {
1404
- const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
1405
- const origin = pickedLayerParmasSurface.origin;
1406
- const scale = pickedLayerParmasSurface.coordinateScale;
1407
- worldPos = [
1408
- pickResultMiddleXY[0] * scale[0] + origin[0],
1409
- pickResultMiddleXY[1] * scale[1] + origin[1],
1410
- pickResultMiddleXY[2] * scale[2] + origin[2],
1411
- ];
1412
- worldNormal = math.normalizeVec3([
1413
- pickNormalResultMiddleXY[0] / math.MAX_INT,
1414
- pickNormalResultMiddleXY[1] / math.MAX_INT,
1415
- pickNormalResultMiddleXY[2] / math.MAX_INT,
1416
- ]);
1417
-
1418
- const pickID =
1419
- pickPickableResultMiddleXY[0]
1420
- + (pickPickableResultMiddleXY[1] << 8)
1421
- + (pickPickableResultMiddleXY[2] << 16)
1422
- + (pickPickableResultMiddleXY[3] << 24);
1423
-
1424
- pickable = pickIDs.items[pickID];
1425
- }
1386
+ gl.depthMask(true);
1426
1387
 
1427
- // result 2) hi-precision snapped (to vertex/edge) world position
1428
-
1429
- let snapPickResult = [];
1430
-
1431
- for (let i = 0; i < snapPickResultArray.length; i += 4) {
1432
- if (snapPickResultArray[i + 3] > 0) {
1433
- const pixelNumber = Math.floor(i / 4);
1434
- const w = vertexPickBuffer.size[0];
1435
- const x = pixelNumber % w - Math.floor(w / 2);
1436
- const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
1437
- const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
1438
- snapPickResult.push({
1439
- x,
1440
- y,
1441
- dist,
1442
- isVertex: snapToVertex && snapToEdge ? snapPickResultArray[i + 3] > layerParamsSnap.length / 2 : snapToVertex,
1443
- result: [
1444
- snapPickResultArray[i + 0],
1445
- snapPickResultArray[i + 1],
1446
- snapPickResultArray[i + 2],
1447
- snapPickResultArray[i + 3],
1448
- ],
1449
- normal: [
1450
- snapPickNormalResultArray[i + 0],
1451
- snapPickNormalResultArray[i + 1],
1452
- snapPickNormalResultArray[i + 2],
1453
- snapPickNormalResultArray[i + 3],
1454
- ],
1455
- id: [
1456
- snapPickIdResultArray[i + 0],
1457
- snapPickIdResultArray[i + 1],
1458
- snapPickIdResultArray[i + 2],
1459
- snapPickIdResultArray[i + 3],
1460
- ]
1461
- });
1388
+ // Read and decode the snapped coordinates
1389
+
1390
+ const snapPickResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4);
1391
+ const snapPickNormalResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.INT, Int32Array, 4, 1);
1392
+ const snapPickIdResultArray = vertexPickBuffer.readArray(gl.RGBA_INTEGER, gl.UNSIGNED_INT, Uint32Array, 4, 2);
1393
+
1394
+ vertexPickBuffer.unbind();
1395
+
1396
+ // result 1) regular hi-precision world position
1397
+
1398
+ let worldPos = null;
1399
+ let worldNormal = null;
1400
+ let pickable = null;
1401
+
1402
+ const middleX = snapRadiusInPixels;
1403
+ const middleY = snapRadiusInPixels;
1404
+ const middleIndex = (middleX * 4) + (middleY * vertexPickBuffer.size[0] * 4);
1405
+ const pickResultMiddleXY = snapPickResultArray.slice(middleIndex, middleIndex + 4);
1406
+ const pickNormalResultMiddleXY = snapPickNormalResultArray.slice(middleIndex, middleIndex + 4);
1407
+ const pickPickableResultMiddleXY = snapPickIdResultArray.slice(middleIndex, middleIndex + 4);
1408
+
1409
+ if (pickResultMiddleXY[3] !== 0) {
1410
+ const pickedLayerParmasSurface = layerParamsSurface[Math.abs(pickResultMiddleXY[3]) % layerParamsSurface.length];
1411
+ const origin = pickedLayerParmasSurface.origin;
1412
+ const scale = pickedLayerParmasSurface.coordinateScale;
1413
+ worldPos = [
1414
+ pickResultMiddleXY[0] * scale[0] + origin[0],
1415
+ pickResultMiddleXY[1] * scale[1] + origin[1],
1416
+ pickResultMiddleXY[2] * scale[2] + origin[2],
1417
+ ];
1418
+ worldNormal = math.normalizeVec3([
1419
+ pickNormalResultMiddleXY[0] / math.MAX_INT,
1420
+ pickNormalResultMiddleXY[1] / math.MAX_INT,
1421
+ pickNormalResultMiddleXY[2] / math.MAX_INT,
1422
+ ]);
1423
+
1424
+ const pickID =
1425
+ pickPickableResultMiddleXY[0]
1426
+ + (pickPickableResultMiddleXY[1] << 8)
1427
+ + (pickPickableResultMiddleXY[2] << 16)
1428
+ + (pickPickableResultMiddleXY[3] << 24);
1429
+
1430
+ pickable = pickIDs.items[pickID];
1462
1431
  }
1463
- }
1464
-
1465
- let snappedWorldPos = null;
1466
- let snappedWorldNormal = null;
1467
- let snappedPickable = null;
1468
- let snapType = null;
1469
1432
 
1470
- if (snapPickResult.length > 0) {
1471
- // vertex snap first, then edge snap
1472
- snapPickResult.sort((a, b) => {
1473
- if (a.isVertex !== b.isVertex) {
1474
- return a.isVertex ? -1 : 1;
1475
- } else {
1476
- return a.dist - b.dist;
1433
+ // result 2) hi-precision snapped (to vertex/edge) world position
1434
+
1435
+ let snapPickResult = [];
1436
+
1437
+ for (let i = 0; i < snapPickResultArray.length; i += 4) {
1438
+ if (snapPickResultArray[i + 3] > 0) {
1439
+ const pixelNumber = Math.floor(i / 4);
1440
+ const w = vertexPickBuffer.size[0];
1441
+ const x = pixelNumber % w - Math.floor(w / 2);
1442
+ const y = Math.floor(pixelNumber / w) - Math.floor(w / 2);
1443
+ const dist = (Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
1444
+ snapPickResult.push({
1445
+ x,
1446
+ y,
1447
+ dist,
1448
+ isVertex: snapToVertex && snapToEdge ? snapPickResultArray[i + 3] > layerParamsSnap.length / 2 : snapToVertex,
1449
+ result: [
1450
+ snapPickResultArray[i + 0],
1451
+ snapPickResultArray[i + 1],
1452
+ snapPickResultArray[i + 2],
1453
+ snapPickResultArray[i + 3],
1454
+ ],
1455
+ normal: [
1456
+ snapPickNormalResultArray[i + 0],
1457
+ snapPickNormalResultArray[i + 1],
1458
+ snapPickNormalResultArray[i + 2],
1459
+ snapPickNormalResultArray[i + 3],
1460
+ ],
1461
+ id: [
1462
+ snapPickIdResultArray[i + 0],
1463
+ snapPickIdResultArray[i + 1],
1464
+ snapPickIdResultArray[i + 2],
1465
+ snapPickIdResultArray[i + 3],
1466
+ ]
1467
+ });
1477
1468
  }
1478
- });
1469
+ }
1479
1470
 
1480
- snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
1481
- const snapPick = snapPickResult[0].result;
1482
- const snapPickNormal = snapPickResult[0].normal;
1483
- const snapPickId = snapPickResult[0].id;
1471
+ let snappedWorldPos = null;
1472
+ let snappedWorldNormal = null;
1473
+ let snappedPickable = null;
1474
+ let snapType = null;
1475
+
1476
+ if (snapPickResult.length > 0) {
1477
+ // vertex snap first, then edge snap
1478
+ snapPickResult.sort((a, b) => {
1479
+ if (a.isVertex !== b.isVertex) {
1480
+ return a.isVertex ? -1 : 1;
1481
+ } else {
1482
+ return a.dist - b.dist;
1483
+ }
1484
+ });
1484
1485
 
1485
- const pickedLayerParmas = layerParamsSnap[snapPick[3]];
1486
+ snapType = snapPickResult[0].isVertex ? "vertex" : "edge";
1487
+ const snapPick = snapPickResult[0].result;
1488
+ const snapPickNormal = snapPickResult[0].normal;
1489
+ const snapPickId = snapPickResult[0].id;
1486
1490
 
1487
- const origin = pickedLayerParmas.origin;
1488
- const scale = pickedLayerParmas.coordinateScale;
1491
+ const pickedLayerParmas = layerParamsSnap[snapPick[3]];
1489
1492
 
1490
- snappedWorldNormal = math.normalizeVec3([
1491
- snapPickNormal[0] / math.MAX_INT,
1492
- snapPickNormal[1] / math.MAX_INT,
1493
- snapPickNormal[2] / math.MAX_INT,
1494
- ]);
1493
+ const origin = pickedLayerParmas.origin;
1494
+ const scale = pickedLayerParmas.coordinateScale;
1495
1495
 
1496
- snappedWorldPos = [
1497
- snapPick[0] * scale[0] + origin[0],
1498
- snapPick[1] * scale[1] + origin[1],
1499
- snapPick[2] * scale[2] + origin[2],
1500
- ];
1496
+ snappedWorldNormal = math.normalizeVec3([
1497
+ snapPickNormal[0] / math.MAX_INT,
1498
+ snapPickNormal[1] / math.MAX_INT,
1499
+ snapPickNormal[2] / math.MAX_INT,
1500
+ ]);
1501
1501
 
1502
- snappedPickable = pickIDs.items[
1502
+ snappedWorldPos = [
1503
+ snapPick[0] * scale[0] + origin[0],
1504
+ snapPick[1] * scale[1] + origin[1],
1505
+ snapPick[2] * scale[2] + origin[2],
1506
+ ];
1507
+
1508
+ snappedPickable = pickIDs.items[
1503
1509
  snapPickId[0]
1504
1510
  + (snapPickId[1] << 8)
1505
1511
  + (snapPickId[2] << 16)
1506
1512
  + (snapPickId[3] << 24)
1507
- ];
1508
- }
1513
+ ];
1514
+ }
1509
1515
 
1510
- if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
1511
- return null;
1512
- }
1516
+ if (null === worldPos && null == snappedWorldPos) { // If neither regular pick or snap pick, return null
1517
+ return null;
1518
+ }
1513
1519
 
1514
- let snappedCanvasPos = null;
1520
+ let snappedCanvasPos = null;
1515
1521
 
1516
- if (null !== snappedWorldPos) {
1517
- snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
1518
- }
1522
+ if (null !== snappedWorldPos) {
1523
+ snappedCanvasPos = scene.camera.projectWorldPos(snappedWorldPos);
1524
+ }
1525
+
1526
+ const snappedEntity = (snappedPickable && snappedPickable.delegatePickedEntity) ? snappedPickable.delegatePickedEntity() : snappedPickable;
1519
1527
 
1520
- const snappedEntity = (snappedPickable && snappedPickable.delegatePickedEntity) ? snappedPickable.delegatePickedEntity() : snappedPickable;
1521
-
1522
- return {
1523
- snapType,
1524
- snappedToVertex: snapType === "vertex",
1525
- snappedToEdge: snapType === "edge",
1526
- worldPos,
1527
- worldNormal,
1528
- snappedWorldPos,
1529
- snappedWorldNormal,
1530
- snappedCanvasPos,
1531
- snappedEntity,
1532
- entity: snappedEntity
1528
+ pickResult.reset();
1529
+ pickResult.snappedToEdge = (snapType === "edge");
1530
+ pickResult.snappedToVertex = (snapType === "vertex");
1531
+ pickResult.worldPos = snappedWorldPos;
1532
+ pickResult.worldNormal = snappedWorldNormal;
1533
+ pickResult.entity = snappedEntity;
1534
+ pickResult.canvasPos = canvasPos;
1535
+ pickResult.snappedCanvasPos = snappedCanvasPos || canvasPos;
1536
+
1537
+ return pickResult;
1533
1538
  };
1534
- };
1539
+ })();
1535
1540
 
1536
1541
  function unpackDepth(depthZ) {
1537
1542
  const vec = [depthZ[0] / 256.0, depthZ[1] / 256.0, depthZ[2] / 256.0, depthZ[3] / 256.0];