itowns 2.44.3-next.21 → 2.44.3-next.23

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.
Files changed (55) hide show
  1. package/dist/debug.js +1 -1
  2. package/dist/debug.js.map +1 -1
  3. package/dist/itowns.js +1 -1
  4. package/dist/itowns.js.map +1 -1
  5. package/examples/layers/JSONLayers/GeoidMNT.json +3 -1
  6. package/examples/source_file_geojson_3d.html +0 -1
  7. package/examples/source_stream_wfs_raster.html +0 -7
  8. package/lib/Converter/Feature2Mesh.js +1 -2
  9. package/lib/Converter/Feature2Texture.js +3 -1
  10. package/lib/Converter/convertToTile.js +3 -3
  11. package/lib/Converter/textureConverter.js +1 -2
  12. package/lib/Core/Feature.js +1 -2
  13. package/lib/Core/Geographic/Coordinates.js +1 -1
  14. package/lib/Core/Geographic/Crs.js +114 -144
  15. package/lib/Core/Geographic/Extent.js +2 -5
  16. package/lib/Core/Geographic/GeoidGrid.js +1 -1
  17. package/lib/Core/Prefab/Globe/Atmosphere.js +4 -2
  18. package/lib/Core/Prefab/Globe/GlobeLayer.js +21 -14
  19. package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +111 -0
  20. package/lib/Core/Prefab/GlobeView.js +2 -3
  21. package/lib/Core/Prefab/Planar/PlanarLayer.js +16 -10
  22. package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +43 -43
  23. package/lib/Core/Prefab/TileBuilder.js +27 -32
  24. package/lib/Core/Prefab/computeBufferTileGeometry.js +189 -130
  25. package/lib/Core/Tile/Tile.js +4 -4
  26. package/lib/Core/Tile/TileGrid.js +7 -10
  27. package/lib/Core/TileGeometry.js +112 -28
  28. package/lib/Core/TileMesh.js +1 -2
  29. package/lib/Core/View.js +2 -2
  30. package/lib/Layer/C3DTilesLayer.js +7 -4
  31. package/lib/Layer/ColorLayer.js +35 -9
  32. package/lib/Layer/CopcLayer.js +5 -0
  33. package/lib/Layer/ElevationLayer.js +39 -7
  34. package/lib/Layer/EntwinePointTileLayer.js +12 -5
  35. package/lib/Layer/FeatureGeometryLayer.js +20 -6
  36. package/lib/Layer/GeometryLayer.js +42 -11
  37. package/lib/Layer/LabelLayer.js +11 -5
  38. package/lib/Layer/Layer.js +83 -57
  39. package/lib/Layer/OGC3DTilesLayer.js +3 -2
  40. package/lib/Layer/OrientedImageLayer.js +12 -4
  41. package/lib/Layer/PointCloudLayer.js +69 -23
  42. package/lib/Layer/Potree2Layer.js +7 -2
  43. package/lib/Layer/PotreeLayer.js +8 -3
  44. package/lib/Layer/RasterLayer.js +12 -2
  45. package/lib/Layer/TiledGeometryLayer.js +69 -13
  46. package/lib/Main.js +1 -1
  47. package/lib/Provider/Fetcher.js +5 -1
  48. package/lib/Renderer/OBB.js +11 -13
  49. package/lib/Renderer/RasterTile.js +1 -2
  50. package/lib/Source/FileSource.js +1 -2
  51. package/lib/Source/Source.js +1 -1
  52. package/lib/Source/TMSSource.js +2 -3
  53. package/lib/Source/WFSSource.js +1 -2
  54. package/package.json +3 -3
  55. package/lib/Core/Prefab/Globe/BuilderEllipsoidTile.js +0 -110
@@ -5,7 +5,6 @@ import Coordinates from "../Geographic/Coordinates.js";
5
5
  import GlobeLayer from "./Globe/GlobeLayer.js";
6
6
  import Atmosphere from "./Globe/Atmosphere.js";
7
7
  import CameraUtils from "../../Utils/CameraUtils.js";
8
- import CRS from "../Geographic/Crs.js";
9
8
  import { ellipsoidSizes } from "../Math/Ellipsoid.js";
10
9
 
11
10
  /**
@@ -129,11 +128,11 @@ class GlobeView extends View {
129
128
  return Promise.reject(new Error('Add Layer type object'));
130
129
  }
131
130
  if (layer.isColorLayer) {
132
- if (!this.tileLayer.tileMatrixSets.includes(CRS.formatToTms(layer.source.crs))) {
131
+ if (!this.tileLayer.tileMatrixSets.includes(layer.source.crs)) {
133
132
  return layer._reject(`Only ${this.tileLayer.tileMatrixSets} tileMatrixSet are currently supported for color layers`);
134
133
  }
135
134
  } else if (layer.isElevationLayer) {
136
- if (CRS.formatToTms(layer.source.crs) !== this.tileLayer.tileMatrixSets[0]) {
135
+ if (layer.source.crs !== this.tileLayer.tileMatrixSets[0]) {
137
136
  return layer._reject(`Only ${this.tileLayer.tileMatrixSets[0]} tileMatrixSet is currently supported for elevation layers`);
138
137
  }
139
138
  }
@@ -1,21 +1,19 @@
1
1
  import * as THREE from 'three';
2
2
  import TiledGeometryLayer from "../../../Layer/TiledGeometryLayer.js";
3
3
  import { globalExtentTMS } from "../../Tile/TileGrid.js";
4
- import CRS from "../../Geographic/Crs.js";
5
- import PlanarTileBuilder from "./PlanarTileBuilder.js";
4
+ import { PlanarTileBuilder } from "./PlanarTileBuilder.js";
6
5
 
7
6
  /**
8
7
  * @property {boolean} isPlanarLayer - Used to checkout whether this layer is a
9
8
  * PlanarLayer. Default is true. You should not change this, as it is used
10
9
  * internally for optimisation.
10
+ * @extends TiledGeometryLayer
11
11
  */
12
12
  class PlanarLayer extends TiledGeometryLayer {
13
13
  /**
14
14
  * A {@link TiledGeometryLayer} to use with a {@link PlanarView}. It has
15
15
  * specific method for updating and subdivising its grid.
16
16
  *
17
- * @extends TiledGeometryLayer
18
- *
19
17
  * @param {string} id - The id of the layer, that should be unique. It is
20
18
  * not mandatory, but an error will be emitted if this layer is added a
21
19
  * {@link View} that already has a layer going by that id.
@@ -35,19 +33,27 @@ class PlanarLayer extends TiledGeometryLayer {
35
33
  */
36
34
  constructor(id, extent, object3d) {
37
35
  let config = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
38
- const tms = CRS.formatToTms(extent.crs);
36
+ const {
37
+ minSubdivisionLevel = 0,
38
+ maxSubdivisionLevel = 5,
39
+ ...tiledConfig
40
+ } = config;
41
+ const tileMatrixSets = [extent.crs];
39
42
  if (!globalExtentTMS.get(extent.crs)) {
40
43
  // Add new global extent for this new crs projection.
41
44
  globalExtentTMS.set(extent.crs, extent);
42
45
  }
43
- config.tileMatrixSets = [tms];
44
- super(id, object3d || new THREE.Group(), [extent], new PlanarTileBuilder({
46
+ const builder = new PlanarTileBuilder({
45
47
  crs: extent.crs
46
- }), config);
48
+ });
49
+ super(id, object3d || new THREE.Group(), [extent], builder, {
50
+ tileMatrixSets,
51
+ ...tiledConfig
52
+ });
47
53
  this.isPlanarLayer = true;
48
54
  this.extent = extent;
49
- this.minSubdivisionLevel = this.minSubdivisionLevel == undefined ? 0 : this.minSubdivisionLevel;
50
- this.maxSubdivisionLevel = this.maxSubdivisionLevel == undefined ? 5 : this.maxSubdivisionLevel;
55
+ this.minSubdivisionLevel = minSubdivisionLevel;
56
+ this.maxSubdivisionLevel = maxSubdivisionLevel;
51
57
  }
52
58
  }
53
59
  export default PlanarLayer;
@@ -3,70 +3,70 @@ import Coordinates from "../../Geographic/Coordinates.js";
3
3
  import Extent from "../../Geographic/Extent.js";
4
4
  const quaternion = new THREE.Quaternion();
5
5
  const center = new THREE.Vector3();
6
- class PlanarTileBuilder {
7
- constructor() {
8
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
9
- /* istanbul ignore next */
6
+
7
+ /** Specialized parameters for the [PlanarTileBuilder]. */
8
+
9
+ /**
10
+ * TileBuilder implementation for the purpose of generating planar
11
+ * tile arrangements.
12
+ */
13
+ export class PlanarTileBuilder {
14
+ constructor(options) {
10
15
  if (options.projection) {
11
- console.warn('PlanarTileBuilder projection parameter is deprecated, use crs instead.');
12
- options.crs = options.crs || options.projection;
13
- }
14
- if (options.crs) {
15
- this.crs = options.crs;
16
- } else {
17
- throw new Error('options.crs is mandatory for PlanarTileBuilder');
16
+ console.warn('PlanarTileBuilder projection parameter is deprecated,' + ' use crs instead.');
17
+ options.crs ??= options.projection;
18
18
  }
19
- this.tmp = {
19
+ this._crs = options.crs;
20
+ this._transform = {
20
21
  coords: new Coordinates('EPSG:4326', 0, 0),
21
22
  position: new THREE.Vector3(),
22
23
  normal: new THREE.Vector3(0, 0, 1)
23
24
  };
24
- this.uvCount = options.uvCount || 1;
25
+ this._uvCount = options.uvCount ?? 1;
26
+ }
27
+ get uvCount() {
28
+ return this._uvCount;
29
+ }
30
+ get crs() {
31
+ return this._crs;
25
32
  }
26
- // prepare params
27
- // init projected object -> params.projected
28
33
  prepare(params) {
29
- params.nbRow = 2 ** (params.zoom + 1.0);
30
- params.projected = new THREE.Vector3();
34
+ const newParams = params;
35
+ newParams.nbRow = 2 ** (params.level + 1.0);
36
+ newParams.coordinates = new Coordinates(this.crs);
37
+ return newParams;
31
38
  }
32
-
33
- // get center tile in cartesian 3D
34
39
  center(extent) {
35
- extent.center(this.tmp.coords);
36
- center.set(this.tmp.coords.x, this.tmp.coords.y, 0);
40
+ extent.center(this._transform.coords);
41
+ center.set(this._transform.coords.x, this._transform.coords.y, 0);
37
42
  return center;
38
43
  }
39
-
40
- // get position 3D cartesian
41
- vertexPosition(params) {
42
- this.tmp.position.set(params.projected.x, params.projected.y, 0);
43
- return this.tmp.position;
44
+ vertexPosition(coordinates) {
45
+ this._transform.position.set(coordinates.x, coordinates.y, 0);
46
+ return this._transform.position;
44
47
  }
45
-
46
- // get normal for last vertex
47
48
  vertexNormal() {
48
- return this.tmp.normal;
49
+ return this._transform.normal;
49
50
  }
50
-
51
- // coord u tile to projected
52
- uProjecte(u, params) {
53
- params.projected.x = params.extent.west + u * (params.extent.east - params.extent.west);
51
+ uProject(u, extent) {
52
+ return extent.west + u * (extent.east - extent.west);
54
53
  }
55
-
56
- // coord v tile to projected
57
- vProjecte(v, params) {
58
- params.projected.y = params.extent.south + v * (params.extent.north - params.extent.south);
54
+ vProject(v, extent) {
55
+ return extent.south + v * (extent.north - extent.south);
59
56
  }
60
- computeSharableExtent(extent) {
61
- // compute sharable extent to pool the geometries
57
+ computeShareableExtent(extent) {
58
+ // compute shareable extent to pool the geometries
62
59
  // the geometry in common extent is identical to the existing input
63
60
  // with a translation
64
- const sharableExtent = new Extent(extent.crs, 0, Math.abs(extent.west - extent.east), 0, Math.abs(extent.north - extent.south));
65
61
  return {
66
- sharableExtent,
62
+ shareableExtent: new Extent(extent.crs, {
63
+ west: 0,
64
+ east: Math.abs(extent.west - extent.east),
65
+ south: 0,
66
+ north: Math.abs(extent.north - extent.south)
67
+ }),
67
68
  quaternion,
68
69
  position: this.center(extent).clone()
69
70
  };
70
71
  }
71
- }
72
- export default PlanarTileBuilder;
72
+ }
@@ -1,17 +1,23 @@
1
1
  import * as THREE from 'three';
2
- import TileGeometry from "../TileGeometry.js";
2
+ import { TileGeometry } from "../TileGeometry.js";
3
3
  import Cache from "../Scheduler/Cache.js";
4
- import computeBuffers from "./computeBufferTileGeometry.js";
4
+ import { computeBuffers } from "./computeBufferTileGeometry.js";
5
5
  import OBB from "../../Renderer/OBB.js";
6
6
  const cacheBuffer = new Map();
7
7
  const cacheTile = new Cache();
8
- export default function newTileGeometry(builder, params) {
8
+
9
+ /**
10
+ * Reference to a tile's extent with rigid transformations.
11
+ * Enables reuse of geometry, saving a bit of memory.
12
+ */
13
+
14
+ export function newTileGeometry(builder, params) {
9
15
  const {
10
- sharableExtent,
16
+ shareableExtent,
11
17
  quaternion,
12
18
  position
13
- } = builder.computeSharableExtent(params.extent);
14
- const south = sharableExtent.south.toFixed(6);
19
+ } = builder.computeShareableExtent(params.extent);
20
+ const south = shareableExtent.south.toFixed(6);
15
21
  const bufferKey = `${builder.crs}_${params.disableSkirt ? 0 : 1}_${params.segments}`;
16
22
  let promiseGeometry = cacheTile.get(south, params.level, bufferKey);
17
23
 
@@ -22,49 +28,38 @@ export default function newTileGeometry(builder, params) {
22
28
  resolve = r;
23
29
  });
24
30
  cacheTile.set(promiseGeometry, south, params.level, bufferKey);
25
- params.extent = sharableExtent;
31
+ params.extent = shareableExtent;
26
32
  params.center = builder.center(params.extent).clone();
27
- // Read previously cached values (index and uv.wgs84 only depend on the # of triangles)
33
+ // Read previously cached values (index and uv.wgs84 only
34
+ // depend on the # of triangles)
28
35
  let cachedBuffers = cacheBuffer.get(bufferKey);
29
36
  params.buildIndexAndUv_0 = !cachedBuffers;
30
- params.builder = builder;
31
37
  let buffers;
32
38
  try {
33
- buffers = computeBuffers(params);
39
+ buffers = computeBuffers(builder, params);
34
40
  } catch (e) {
35
41
  return Promise.reject(e);
36
42
  }
37
43
  if (!cachedBuffers) {
38
44
  cachedBuffers = {};
45
+ // We know the fields will exist due to the condition
46
+ // matching with the one for buildIndexAndUv_0.
47
+ // TODO: Make this brain-based check compiler-based.
39
48
  cachedBuffers.index = new THREE.BufferAttribute(buffers.index, 1);
40
49
  cachedBuffers.uv = new THREE.BufferAttribute(buffers.uvs[0], 2);
41
50
 
42
51
  // Update cacheBuffer
43
52
  cacheBuffer.set(bufferKey, cachedBuffers);
44
53
  }
45
- buffers.index = cachedBuffers.index;
46
- buffers.uvs[0] = cachedBuffers.uv;
47
- buffers.position = new THREE.BufferAttribute(buffers.position, 3);
48
- buffers.normal = new THREE.BufferAttribute(buffers.normal, 3);
49
- if (params.builder.uvCount > 1) {
50
- buffers.uvs[1] = new THREE.BufferAttribute(buffers.uvs[1], 1);
51
- }
52
- const geometry = new TileGeometry(params, buffers);
53
- geometry.OBB = new OBB(geometry.boundingBox.min, geometry.boundingBox.max);
54
- geometry._count = 0;
55
- geometry.dispose = () => {
56
- geometry._count--;
57
- if (geometry._count <= 0) {
58
- // To avoid remove index buffer and attribute buffer uv
59
- // error un-bound buffer in webgl with VAO rendering.
60
- // Could be removed if the attribute buffer deleting is
61
- // taken into account in the buffer binding state (in THREE.WebGLBindingStates code).
62
- geometry.index = null;
63
- delete geometry.attributes.uv;
64
- THREE.BufferGeometry.prototype.dispose.call(geometry);
65
- cacheTile.delete(south, params.level, bufferKey);
66
- }
54
+ const gpuBuffers = {
55
+ index: cachedBuffers.index,
56
+ uvs: [cachedBuffers.uv, ...(buffers.uvs[1] !== undefined ? [new THREE.BufferAttribute(buffers.uvs[1], 1)] : [])],
57
+ position: new THREE.BufferAttribute(buffers.position, 3),
58
+ normal: new THREE.BufferAttribute(buffers.normal, 3)
67
59
  };
60
+ const geometry = new TileGeometry(builder, params, gpuBuffers);
61
+ geometry.OBB = new OBB(geometry.boundingBox.min, geometry.boundingBox.max);
62
+ geometry.initRefCount(cacheTile, [south, params.level, bufferKey]);
68
63
  resolve(geometry);
69
64
  return Promise.resolve({
70
65
  geometry,
@@ -3,14 +3,52 @@ export function getBufferIndexSize(segments, noSkirt) {
3
3
  const triangles = segments * segments * 2 + (noSkirt ? 0 : 4 * segments * 2);
4
4
  return triangles * 3;
5
5
  }
6
- export default function computeBuffers(params) {
7
- // Create output buffers.
8
- const outBuffers = {
9
- index: null,
10
- position: null,
11
- normal: null,
12
- // 2 UV set per tile: wgs84 (uv[0]) and pm (uv[1])
13
- // - wgs84: 1 texture per tile because tiles are using wgs84 projection
6
+ function getUintArrayConstructor(highestValue) {
7
+ let picked = null;
8
+ if (highestValue < 2 ** 8) {
9
+ picked = Uint8Array;
10
+ } else if (highestValue < 2 ** 16) {
11
+ picked = Uint16Array;
12
+ } else if (highestValue < 2 ** 32) {
13
+ picked = Uint32Array;
14
+ } else {
15
+ throw new Error('Value is too high');
16
+ }
17
+ return picked;
18
+ }
19
+ function allocateIndexBuffer(nVertex, nSeg, params) {
20
+ if (!params.buildIndexAndUv_0) {
21
+ return undefined;
22
+ }
23
+ const indexBufferSize = getBufferIndexSize(nSeg, params.disableSkirt);
24
+ const indexConstructor = getUintArrayConstructor(nVertex);
25
+ const tileLen = indexBufferSize;
26
+ const skirtLen = 4 * nSeg;
27
+ const indexBuffer = new ArrayBuffer((
28
+ // Tile
29
+ tileLen
30
+ // Skirt
31
+ + (params.disableSkirt ? 0 : skirtLen)) * indexConstructor.BYTES_PER_ELEMENT);
32
+ const index = new indexConstructor(indexBuffer);
33
+ const skirt = !params.disableSkirt ? index.subarray(tileLen, tileLen + skirtLen) : undefined;
34
+ return {
35
+ index,
36
+ skirt
37
+ };
38
+ }
39
+ function allocateBuffers(nVertex, nSeg, builder, params) {
40
+ const {
41
+ index,
42
+ skirt
43
+ } = allocateIndexBuffer(nVertex, nSeg, params) ?? {};
44
+ return {
45
+ index,
46
+ skirt,
47
+ position: new Float32Array(nVertex * 3),
48
+ normal: new Float32Array(nVertex * 3),
49
+ // 2 UV set per tile: wgs84 (uv[0]) and pseudo-mercator (pm, uv[1])
50
+ // - wgs84: 1 texture per tile because tiles are using wgs84
51
+ // projection
14
52
  // - pm: use multiple textures per tile.
15
53
  // +-------------------------+
16
54
  // | |
@@ -24,142 +62,157 @@ export default function computeBuffers(params) {
24
62
  // +-------------------------+
25
63
  // * u = wgs84.u
26
64
  // * v = textureid + v in builder texture
27
- uvs: []
65
+ uvs: [params.buildIndexAndUv_0 ? new Float32Array(nVertex * 2) : undefined, builder.computeExtraOffset !== undefined ? new Float32Array(nVertex) : undefined]
66
+ };
67
+ }
68
+ function computeUv0(uv, id, u, v) {
69
+ uv[id * 2 + 0] = u;
70
+ uv[id * 2 + 1] = v;
71
+ }
72
+ function initComputeUv1(value) {
73
+ return (uv, id) => {
74
+ uv[id] = value;
28
75
  };
29
- const computeUvs = [];
30
- const builder = params.builder;
31
- const nSeg = params.segments;
32
- // segments count :
33
- // Tile : (nSeg + 1) * (nSeg + 1)
34
- // Skirt : 8 * (nSeg - 1)
35
- const nVertex = (nSeg + 1) * (nSeg + 1) + (params.disableSkirt ? 0 : 4 * nSeg);
36
- if (nVertex > 2 ** 32) {
76
+ }
77
+ /** Compute buffers describing a tile according to a builder and its params. */
78
+ // TODO: Split this even further into subfunctions
79
+ export function computeBuffers(builder, params) {
80
+ // n seg, n+1 vert + <- skirt, n verts per side
81
+ // <---------------> / |
82
+ // +---+---+---+---+ |
83
+ // | / | / | / | / | | Vertices:
84
+ // +---+---+---+---+ - + tile = (n + 1)^2
85
+ // | / | / | / | / | | skirt = 4n
86
+ // +---+---+---+---+ - +
87
+ // | / | / | / | / | | Segments:
88
+ // +---+---+---+---+ - + tile = 2 * n * (n + 1) + n^2
89
+ // | / | / | / | / | | skirt = 2n * 4
90
+ // +---+---+---+---+ |
91
+ const nSeg = Math.max(2, params.segments);
92
+ const nVertex = nSeg + 1;
93
+ const nTileVertex = nVertex ** 2;
94
+ const nSkirtVertex = params.disableSkirt ? 0 : 4 * nSeg;
95
+ const nTotalVertex = nTileVertex + nSkirtVertex;
96
+
97
+ // Computer should combust before this happens
98
+ if (nTotalVertex > 2 ** 32) {
37
99
  throw new Error('Tile segments count is too big');
38
100
  }
39
- outBuffers.position = new Float32Array(nVertex * 3);
40
- outBuffers.normal = new Float32Array(nVertex * 3);
41
- const uvCount = params.builder.uvCount;
42
- if (uvCount > 1) {
43
- outBuffers.uvs[1] = new Float32Array(nVertex);
44
- }
45
- computeUvs[0] = () => {};
46
- const bufferIndexSize = getBufferIndexSize(nSeg, params.disableSkirt);
47
- if (params.buildIndexAndUv_0) {
48
- if (nVertex < 2 ** 8) {
49
- outBuffers.index = new Uint8Array(bufferIndexSize);
50
- } else if (nVertex < 2 ** 16) {
51
- outBuffers.index = new Uint16Array(bufferIndexSize);
52
- } else if (nVertex < 2 ** 32) {
53
- outBuffers.index = new Uint32Array(bufferIndexSize);
101
+ const outBuffers = allocateBuffers(nTotalVertex, nSeg, builder, params);
102
+ const computeUvs = [params.buildIndexAndUv_0 ? computeUv0 : () => {}];
103
+ params = builder.prepare(params);
104
+ for (let y = 0; y <= nSeg; y++) {
105
+ const v = y / nSeg;
106
+ params.coordinates.y = builder.vProject(v, params.extent);
107
+ if (builder.computeExtraOffset !== undefined) {
108
+ computeUvs[1] = initComputeUv1(builder.computeExtraOffset(params));
54
109
  }
55
- outBuffers.uvs[0] = new Float32Array(nVertex * 2);
56
- computeUvs[0] = (id, u, v) => {
57
- outBuffers.uvs[0][id * 2 + 0] = u;
58
- outBuffers.uvs[0][id * 2 + 1] = v;
59
- };
60
- }
61
- const widthSegments = Math.max(2, Math.floor(nSeg) || 2);
62
- const heightSegments = Math.max(2, Math.floor(nSeg) || 2);
63
- let idVertex = 0;
64
- const vertices = [];
65
- let skirt = [];
66
- const skirtEnd = [];
67
- builder.prepare(params);
68
- for (let y = 0; y <= heightSegments; y++) {
69
- const verticesRow = [];
70
- const v = y / heightSegments;
71
- builder.vProjecte(v, params);
72
- if (uvCount > 1) {
73
- const u = builder.computeUvs[1](params);
74
- computeUvs[1] = id => {
75
- outBuffers.uvs[1][id] = u;
76
- };
77
- }
78
- for (let x = 0; x <= widthSegments; x++) {
79
- const u = x / widthSegments;
80
- const id_m3 = idVertex * 3;
81
- builder.uProjecte(u, params);
82
- const vertex = builder.vertexPosition(params, params.projected);
83
- const normal = builder.vertexNormal(params);
110
+ for (let x = 0; x <= nSeg; x++) {
111
+ const u = x / nSeg;
112
+ const id_m3 = (y * nVertex + x) * 3;
113
+ params.coordinates.x = builder.uProject(u, params.extent);
114
+ const vertex = builder.vertexPosition(params.coordinates);
115
+ const normal = builder.vertexNormal();
84
116
 
85
117
  // move geometry to center world
86
118
  vertex.sub(params.center);
87
119
 
88
120
  // align normal to z axis
89
- if (params.quatNormalToZ) {
90
- vertex.applyQuaternion(params.quatNormalToZ);
91
- normal.applyQuaternion(params.quatNormalToZ);
121
+ // HACK: this check style is not great
122
+ if ('quatNormalToZ' in params) {
123
+ const quat = params.quatNormalToZ;
124
+ vertex.applyQuaternion(quat);
125
+ normal.applyQuaternion(quat);
92
126
  }
93
127
  vertex.toArray(outBuffers.position, id_m3);
94
128
  normal.toArray(outBuffers.normal, id_m3);
95
- for (const computeUv of computeUvs) {
96
- computeUv(idVertex, u, v);
97
- }
98
- if (!params.disableSkirt) {
99
- if (y !== 0 && y !== heightSegments) {
100
- if (x === widthSegments) {
101
- skirt.push(idVertex);
102
- } else if (x === 0) {
103
- skirtEnd.push(idVertex);
104
- }
129
+ for (const [index, computeUv] of computeUvs.entries()) {
130
+ if (computeUv !== undefined) {
131
+ computeUv(outBuffers.uvs[index], y * nVertex + x, u, v);
105
132
  }
106
133
  }
107
- verticesRow.push(idVertex);
108
- idVertex++;
109
- }
110
- vertices.push(verticesRow);
111
- if (y === 0) {
112
- skirt = skirt.concat(verticesRow);
113
- } else if (y === heightSegments) {
114
- skirt = skirt.concat(verticesRow.slice().reverse());
115
134
  }
116
135
  }
117
- if (!params.disableSkirt) {
118
- skirt = skirt.concat(skirtEnd.reverse());
136
+
137
+ // Fill skirt index buffer
138
+ if (params.buildIndexAndUv_0 && !params.disableSkirt) {
139
+ for (let x = 0; x < nVertex; x++) {
140
+ // -------->
141
+ // 0---1---2
142
+ // | / | / | [0-9] = assign order
143
+ // +---+---+
144
+ // | / | / |
145
+ // +---+---+
146
+ outBuffers.skirt[x] = x;
147
+ // +---+---+
148
+ // | / | / | [0-9] = assign order
149
+ // +---+---x x = skipped for now
150
+ // | / | / |
151
+ // 0---1---2
152
+ // <--------
153
+ outBuffers.skirt[2 * nVertex - 2 + x] = nVertex ** 2 - (x + 1);
154
+ }
155
+ for (let y = 1; y < nVertex - 1; y++) {
156
+ // +---+---s |
157
+ // | / | / | | o = stored vertices
158
+ // +---+---o | s = already stored
159
+ // | / | / | |
160
+ // +---+---s v
161
+ outBuffers.skirt[nVertex - 1 + y] = y * nVertex + (nVertex - 1);
162
+ // ^ s---+---+
163
+ // | | / | / | o = stored vertices
164
+ // | o---+---+ s = already stored
165
+ // | | / | / |
166
+ // | s---+---+
167
+ outBuffers.skirt[3 * nVertex - 3 + y] = nVertex * (nVertex - 1 - y);
168
+ }
119
169
  }
120
- function bufferize(va, vb, vc, idVertex) {
121
- outBuffers.index[idVertex + 0] = va;
122
- outBuffers.index[idVertex + 1] = vb;
123
- outBuffers.index[idVertex + 2] = vc;
124
- return idVertex + 3;
170
+
171
+ /** Copy passed indices at the desired index of the output index buffer. */
172
+ function bufferizeTri(id, va, vb, vc) {
173
+ outBuffers.index[id + 0] = va;
174
+ outBuffers.index[id + 1] = vb;
175
+ outBuffers.index[id + 2] = vc;
125
176
  }
126
- let idVertex2 = 0;
127
177
  if (params.buildIndexAndUv_0) {
128
- for (let y = 0; y < heightSegments; y++) {
129
- for (let x = 0; x < widthSegments; x++) {
130
- const v1 = vertices[y][x + 1];
131
- const v2 = vertices[y][x];
132
- const v3 = vertices[y + 1][x];
133
- const v4 = vertices[y + 1][x + 1];
134
- idVertex2 = bufferize(v4, v2, v1, idVertex2);
135
- idVertex2 = bufferize(v4, v3, v2, idVertex2);
178
+ for (let y = 0; y < nSeg; y++) {
179
+ for (let x = 0; x < nSeg; x++) {
180
+ const v1 = y * nVertex + (x + 1);
181
+ const v2 = y * nVertex + x;
182
+ const v3 = (y + 1) * nVertex + x;
183
+ const v4 = (y + 1) * nVertex + (x + 1);
184
+ const id = (y * nSeg + x) * 6;
185
+ bufferizeTri(id, /**/v4, v2, v1);
186
+ bufferizeTri(id + 3, v4, v3, v2);
136
187
  }
137
188
  }
138
189
  }
139
- const iStart = idVertex;
140
190
 
141
- // TODO: WARNING beware skirt's size influences performance
142
- // The size of the skirt is now a ratio of the size of the tile.
143
- // To be perfect it should depend on the real elevation delta but too heavy to compute
144
- if (!params.disableSkirt) {
145
- // We compute the actual size of tile segment to use later for the skirt.
191
+ // PERF: Beware skirt's size influences performance
192
+ // INFO: The size of the skirt is now a ratio of the size of the tile.
193
+ // To be perfect it should depend on the real elevation delta but too heavy
194
+ // to compute
195
+ if (params.buildIndexAndUv_0 && !params.disableSkirt) {
196
+ // We compute the actual size of tile segment to use later for
197
+ // the skirt.
146
198
  const segmentSize = new THREE.Vector3().fromArray(outBuffers.position).distanceTo(new THREE.Vector3().fromArray(outBuffers.position, 3));
147
- let buildIndexSkirt = function () {};
148
- let buildUVSkirt = function () {};
149
- if (params.buildIndexAndUv_0) {
150
- buildIndexSkirt = function (id, v1, v2, v3, v4) {
151
- id = bufferize(v1, v2, v3, id);
152
- id = bufferize(v1, v3, v4, id);
153
- return id;
154
- };
155
- buildUVSkirt = function (id) {
156
- outBuffers.uvs[0][idVertex * 2 + 0] = outBuffers.uvs[0][id * 2 + 0];
157
- outBuffers.uvs[0][idVertex * 2 + 1] = outBuffers.uvs[0][id * 2 + 1];
158
- };
159
- }
160
- for (let i = 0; i < skirt.length; i++) {
161
- const id = skirt[i];
162
- const id_m3 = idVertex * 3;
199
+ const buildSkirt = {
200
+ index: (id, v1, v2, v3, v4) => {
201
+ bufferizeTri(id, v1, v2, v3);
202
+ bufferizeTri(id + 3, v1, v3, v4);
203
+ return id + 6;
204
+ },
205
+ uv: (buf, idTo, idFrom) => {
206
+ buf[idTo * 2 + 0] = buf[idFrom * 2 + 0];
207
+ buf[idTo * 2 + 1] = buf[idFrom * 2 + 1];
208
+ }
209
+ };
210
+
211
+ // Alias for readability
212
+ const start = nTileVertex;
213
+ for (let i = 0; i < outBuffers.skirt.length; i++) {
214
+ const id = outBuffers.skirt[i];
215
+ const id_m3 = (start + i) * 3;
163
216
  const id2_m3 = id * 3;
164
217
  outBuffers.position[id_m3 + 0] = outBuffers.position[id2_m3 + 0] - outBuffers.normal[id2_m3 + 0] * segmentSize;
165
218
  outBuffers.position[id_m3 + 1] = outBuffers.position[id2_m3 + 1] - outBuffers.normal[id2_m3 + 1] * segmentSize;
@@ -167,17 +220,23 @@ export default function computeBuffers(params) {
167
220
  outBuffers.normal[id_m3 + 0] = outBuffers.normal[id2_m3 + 0];
168
221
  outBuffers.normal[id_m3 + 1] = outBuffers.normal[id2_m3 + 1];
169
222
  outBuffers.normal[id_m3 + 2] = outBuffers.normal[id2_m3 + 2];
170
- buildUVSkirt(id);
171
- if (uvCount > 1) {
172
- outBuffers.uvs[1][idVertex] = outBuffers.uvs[1][id];
223
+ buildSkirt.uv(outBuffers.uvs[0], start + i, id);
224
+ if (outBuffers.uvs[1] !== undefined) {
225
+ outBuffers.uvs[1][start + i] = outBuffers.uvs[1][id];
173
226
  }
174
- const idf = (i + 1) % skirt.length;
175
- const v2 = idVertex;
176
- const v3 = idf === 0 ? iStart : idVertex + 1;
177
- const v4 = skirt[idf];
178
- idVertex2 = buildIndexSkirt(idVertex2, id, v2, v3, v4);
179
- idVertex++;
227
+ const idf = (i + 1) % outBuffers.skirt.length;
228
+ const v2 = start + i;
229
+ const v3 = idf === 0 ? start : start + i + 1;
230
+ const v4 = outBuffers.skirt[idf];
231
+ buildSkirt.index(6 * nSeg ** 2 + i * 6, id, v2, v3, v4);
180
232
  }
181
233
  }
182
- return outBuffers;
234
+
235
+ // Dropping skirt view
236
+ return {
237
+ index: outBuffers.index,
238
+ position: outBuffers.position,
239
+ uvs: outBuffers.uvs,
240
+ normal: outBuffers.normal
241
+ };
183
242
  }