itowns 2.45.1-next.0 → 2.45.1-next.1
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.
- package/dist/455.js +2 -0
- package/dist/455.js.map +1 -0
- package/dist/debug.js +3 -0
- package/dist/debug.js.LICENSE.txt +13 -0
- package/dist/debug.js.map +1 -0
- package/dist/itowns.js +3 -0
- package/dist/itowns.js.LICENSE.txt +5 -0
- package/dist/itowns.js.map +1 -0
- package/dist/itowns_lasparser.js +2 -0
- package/dist/itowns_lasparser.js.map +1 -0
- package/dist/itowns_lasworker.js +2 -0
- package/dist/itowns_lasworker.js.map +1 -0
- package/dist/itowns_potree2worker.js +2 -0
- package/dist/itowns_potree2worker.js.map +1 -0
- package/dist/itowns_widgets.js +2 -0
- package/dist/itowns_widgets.js.map +1 -0
- package/lib/Controls/FirstPersonControls.js +308 -0
- package/lib/Controls/FlyControls.js +175 -0
- package/lib/Controls/GlobeControls.js +1178 -0
- package/lib/Controls/PlanarControls.js +1025 -0
- package/lib/Controls/StateControl.js +432 -0
- package/lib/Controls/StreetControls.js +392 -0
- package/lib/Converter/Feature2Mesh.js +612 -0
- package/lib/Converter/Feature2Texture.js +174 -0
- package/lib/Converter/convertToTile.js +70 -0
- package/lib/Converter/textureConverter.js +43 -0
- package/lib/Core/3DTiles/C3DTBatchTable.js +131 -0
- package/lib/Core/3DTiles/C3DTBatchTableHierarchyExtension.js +96 -0
- package/lib/Core/3DTiles/C3DTBoundingVolume.js +156 -0
- package/lib/Core/3DTiles/C3DTExtensions.js +97 -0
- package/lib/Core/3DTiles/C3DTFeature.js +110 -0
- package/lib/Core/3DTiles/C3DTilesEnums.js +20 -0
- package/lib/Core/3DTiles/C3DTileset.js +99 -0
- package/lib/Core/3DTiles/utils/BinaryPropertyAccessor.js +100 -0
- package/lib/Core/AnimationPlayer.js +142 -0
- package/lib/Core/CopcNode.js +174 -0
- package/lib/Core/Deprecated/Undeprecator.js +74 -0
- package/lib/Core/EntwinePointTileNode.js +126 -0
- package/lib/Core/Feature.js +488 -0
- package/lib/Core/Geographic/GeoidGrid.js +108 -0
- package/lib/Core/Label.js +222 -0
- package/lib/Core/MainLoop.js +209 -0
- package/lib/Core/Picking.js +255 -0
- package/lib/Core/PointCloudNode.js +42 -0
- package/lib/Core/Potree2Node.js +206 -0
- package/lib/Core/Potree2PointAttributes.js +139 -0
- package/lib/Core/PotreeNode.js +101 -0
- package/lib/Core/Prefab/Globe/Atmosphere.js +293 -0
- package/lib/Core/Prefab/Globe/GlobeLayer.js +152 -0
- package/lib/Core/Prefab/Globe/GlobeTileBuilder.js +110 -0
- package/lib/Core/Prefab/Globe/SkyShader.js +78 -0
- package/lib/Core/Prefab/GlobeView.js +155 -0
- package/lib/Core/Prefab/Planar/PlanarLayer.js +59 -0
- package/lib/Core/Prefab/Planar/PlanarTileBuilder.js +71 -0
- package/lib/Core/Prefab/PlanarView.js +62 -0
- package/lib/Core/Prefab/TileBuilder.js +82 -0
- package/lib/Core/Prefab/computeBufferTileGeometry.js +248 -0
- package/lib/Core/Scheduler/Cache.js +17 -0
- package/lib/Core/Scheduler/CancelledCommandException.js +15 -0
- package/lib/Core/Scheduler/Scheduler.js +294 -0
- package/lib/Core/Style.js +660 -0
- package/lib/Core/StyleOptions.js +486 -0
- package/lib/Core/System/Capabilities.js +63 -0
- package/lib/Core/Tile/Tile.js +205 -0
- package/lib/Core/Tile/TileGrid.js +49 -0
- package/lib/Core/TileGeometry.js +124 -0
- package/lib/Core/TileMesh.js +108 -0
- package/lib/Core/View.js +1115 -0
- package/lib/Layer/C3DTilesLayer.js +459 -0
- package/lib/Layer/ColorLayer.js +154 -0
- package/lib/Layer/CopcLayer.js +63 -0
- package/lib/Layer/ElevationLayer.js +139 -0
- package/lib/Layer/EntwinePointTileLayer.js +71 -0
- package/lib/Layer/FeatureGeometryLayer.js +77 -0
- package/lib/Layer/GeoidLayer.js +80 -0
- package/lib/Layer/GeometryLayer.js +233 -0
- package/lib/Layer/InfoLayer.js +64 -0
- package/lib/Layer/LabelLayer.js +469 -0
- package/lib/Layer/Layer.js +335 -0
- package/lib/Layer/LayerUpdateState.js +89 -0
- package/lib/Layer/LayerUpdateStrategy.js +80 -0
- package/lib/Layer/OGC3DTilesLayer.js +543 -0
- package/lib/Layer/OrientedImageLayer.js +227 -0
- package/lib/Layer/PointCloudLayer.js +405 -0
- package/lib/Layer/Potree2Layer.js +171 -0
- package/lib/Layer/PotreeLayer.js +72 -0
- package/lib/Layer/RasterLayer.js +37 -0
- package/lib/Layer/ReferencingLayerProperties.js +62 -0
- package/lib/Layer/TiledGeometryLayer.js +459 -0
- package/lib/Loader/LASLoader.js +193 -0
- package/lib/Loader/Potree2BrotliLoader.js +261 -0
- package/lib/Loader/Potree2Loader.js +207 -0
- package/lib/Main.js +113 -0
- package/lib/MainBundle.js +4 -0
- package/lib/Parser/B3dmParser.js +174 -0
- package/lib/Parser/CameraCalibrationParser.js +94 -0
- package/lib/Parser/GDFParser.js +72 -0
- package/lib/Parser/GTXParser.js +75 -0
- package/lib/Parser/GeoJsonParser.js +212 -0
- package/lib/Parser/GpxParser.js +25 -0
- package/lib/Parser/ISGParser.js +71 -0
- package/lib/Parser/KMLParser.js +25 -0
- package/lib/Parser/LASParser.js +137 -0
- package/lib/Parser/MapBoxUrlParser.js +83 -0
- package/lib/Parser/PntsParser.js +131 -0
- package/lib/Parser/Potree2BinParser.js +92 -0
- package/lib/Parser/PotreeBinParser.js +106 -0
- package/lib/Parser/PotreeCinParser.js +29 -0
- package/lib/Parser/ShapefileParser.js +78 -0
- package/lib/Parser/VectorTileParser.js +215 -0
- package/lib/Parser/XbilParser.js +120 -0
- package/lib/Parser/deprecated/LegacyGLTFLoader.js +1386 -0
- package/lib/Parser/iGLTFLoader.js +168 -0
- package/lib/Process/3dTilesProcessing.js +304 -0
- package/lib/Process/FeatureProcessing.js +76 -0
- package/lib/Process/LayeredMaterialNodeProcessing.js +229 -0
- package/lib/Process/ObjectRemovalHelper.js +97 -0
- package/lib/Process/handlerNodeError.js +23 -0
- package/lib/Provider/3dTilesProvider.js +149 -0
- package/lib/Provider/DataSourceProvider.js +24 -0
- package/lib/Provider/Fetcher.js +233 -0
- package/lib/Provider/PointCloudProvider.js +45 -0
- package/lib/Provider/TileProvider.js +16 -0
- package/lib/Provider/URLBuilder.js +116 -0
- package/lib/Renderer/Camera.js +281 -0
- package/lib/Renderer/Color.js +56 -0
- package/lib/Renderer/ColorLayersOrdering.js +115 -0
- package/lib/Renderer/CommonMaterial.js +31 -0
- package/lib/Renderer/Label2DRenderer.js +192 -0
- package/lib/Renderer/LayeredMaterial.js +243 -0
- package/lib/Renderer/OBB.js +150 -0
- package/lib/Renderer/OrientedImageCamera.js +118 -0
- package/lib/Renderer/OrientedImageMaterial.js +167 -0
- package/lib/Renderer/PointsMaterial.js +485 -0
- package/lib/Renderer/RasterTile.js +243 -0
- package/lib/Renderer/RenderMode.js +31 -0
- package/lib/Renderer/Shader/ShaderChunk.js +160 -0
- package/lib/Renderer/Shader/ShaderUtils.js +47 -0
- package/lib/Renderer/SphereHelper.js +17 -0
- package/lib/Renderer/WebXR.js +51 -0
- package/lib/Renderer/c3DEngine.js +214 -0
- package/lib/Source/C3DTilesGoogleSource.js +74 -0
- package/lib/Source/C3DTilesIonSource.js +54 -0
- package/lib/Source/C3DTilesSource.js +30 -0
- package/lib/Source/CopcSource.js +126 -0
- package/lib/Source/EntwinePointTileSource.js +72 -0
- package/lib/Source/FileSource.js +188 -0
- package/lib/Source/OGC3DTilesGoogleSource.js +29 -0
- package/lib/Source/OGC3DTilesIonSource.js +34 -0
- package/lib/Source/OGC3DTilesSource.js +21 -0
- package/lib/Source/OrientedImageSource.js +59 -0
- package/lib/Source/Potree2Source.js +167 -0
- package/lib/Source/PotreeSource.js +82 -0
- package/lib/Source/Source.js +202 -0
- package/lib/Source/TMSSource.js +144 -0
- package/lib/Source/VectorTilesSource.js +182 -0
- package/lib/Source/WFSSource.js +170 -0
- package/lib/Source/WMSSource.js +167 -0
- package/lib/Source/WMTSSource.js +92 -0
- package/lib/ThreeExtended/capabilities/WebGL.js +69 -0
- package/lib/ThreeExtended/libs/ktx-parse.module.js +506 -0
- package/lib/ThreeExtended/libs/zstddec.module.js +29 -0
- package/lib/ThreeExtended/loaders/DDSLoader.js +200 -0
- package/lib/ThreeExtended/loaders/DRACOLoader.js +400 -0
- package/lib/ThreeExtended/loaders/GLTFLoader.js +2879 -0
- package/lib/ThreeExtended/loaders/KTX2Loader.js +709 -0
- package/lib/ThreeExtended/math/ColorSpaces.js +59 -0
- package/lib/ThreeExtended/utils/BufferGeometryUtils.js +846 -0
- package/lib/ThreeExtended/utils/WorkerPool.js +70 -0
- package/lib/Utils/CameraUtils.js +554 -0
- package/lib/Utils/DEMUtils.js +350 -0
- package/lib/Utils/FeaturesUtils.js +156 -0
- package/lib/Utils/Gradients.js +16 -0
- package/lib/Utils/ThreeUtils.js +115 -0
- package/lib/Utils/gui/C3DTilesStyle.js +218 -0
- package/lib/Utils/gui/Main.js +7 -0
- package/lib/Utils/gui/Minimap.js +152 -0
- package/lib/Utils/gui/Navigation.js +245 -0
- package/lib/Utils/gui/Scale.js +104 -0
- package/lib/Utils/gui/Searchbar.js +234 -0
- package/lib/Utils/gui/Widget.js +80 -0
- package/lib/Utils/placeObjectOnGround.js +136 -0
- package/lib/Worker/LASLoaderWorker.js +19 -0
- package/lib/Worker/Potree2Worker.js +21 -0
- package/package.json +2 -2
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import View, { VIEW_EVENTS } from "../View.js";
|
|
3
|
+
import GlobeControls from "../../Controls/GlobeControls.js";
|
|
4
|
+
import { Coordinates, ellipsoidSizes } from '@itowns/geographic';
|
|
5
|
+
import GlobeLayer from "./Globe/GlobeLayer.js";
|
|
6
|
+
import Atmosphere from "./Globe/Atmosphere.js";
|
|
7
|
+
import CameraUtils from "../../Utils/CameraUtils.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Fires when the view is completely loaded. Controls and view's functions can be called then.
|
|
11
|
+
* @event GlobeView#initialized
|
|
12
|
+
* @property target {view} dispatched on view
|
|
13
|
+
* @property type {string} initialized
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Fires when a layer is added
|
|
17
|
+
* @event GlobeView#layer-added
|
|
18
|
+
* @property layerId {string} the id of the layer
|
|
19
|
+
* @property target {view} dispatched on view
|
|
20
|
+
* @property type {string} layers-added
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Fires when a layer is removed
|
|
24
|
+
* @event GlobeView#layer-removed
|
|
25
|
+
* @property layerId {string} the id of the layer
|
|
26
|
+
* @property target {view} dispatched on view
|
|
27
|
+
* @property type {string} layers-added
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Fires when the layers oder has changed
|
|
31
|
+
* @event GlobeView#layers-order-changed
|
|
32
|
+
* @property new {object}
|
|
33
|
+
* @property new.sequence {array}
|
|
34
|
+
* @property new.sequence.0 {number} the new layer at position 0
|
|
35
|
+
* @property new.sequence.1 {number} the new layer at position 1
|
|
36
|
+
* @property new.sequence.2 {number} the new layer at position 2
|
|
37
|
+
* @property previous {object}
|
|
38
|
+
* @property previous.sequence {array}
|
|
39
|
+
* @property previous.sequence.0 {number} the previous layer at position 0
|
|
40
|
+
* @property previous.sequence.1 {number} the previous layer at position 1
|
|
41
|
+
* @property previous.sequence.2 {number} the previous layer at position 2
|
|
42
|
+
* @property target {view} dispatched on view
|
|
43
|
+
* @property type {string} layers-order-changed
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Globe's EVENT
|
|
48
|
+
* @property GLOBE_INITIALIZED {string} Deprecated: emit one time when globe is initialized (use VIEW_EVENTS.INITIALIZED instead).
|
|
49
|
+
* @property LAYER_ADDED {string} Deprecated: emit when layer id added in viewer (use VIEW_EVENTS.LAYER_ADDED instead).
|
|
50
|
+
* @property LAYER_REMOVED {string} Deprecated: emit when layer id removed in viewer (use VIEW_EVENTS.LAYER_REMOVED instead).
|
|
51
|
+
* @property COLOR_LAYERS_ORDER_CHANGED {string} Deprecated: emit when color layers order change (use VIEW_EVENTS.COLOR_LAYERS_ORDER_CHANGED instead).
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
export const GLOBE_VIEW_EVENTS = {
|
|
55
|
+
GLOBE_INITIALIZED: VIEW_EVENTS.INITIALIZED,
|
|
56
|
+
LAYER_ADDED: VIEW_EVENTS.LAYER_ADDED,
|
|
57
|
+
LAYER_REMOVED: VIEW_EVENTS.LAYER_REMOVED,
|
|
58
|
+
COLOR_LAYERS_ORDER_CHANGED: VIEW_EVENTS.COLOR_LAYERS_ORDER_CHANGED
|
|
59
|
+
};
|
|
60
|
+
class GlobeView extends View {
|
|
61
|
+
/**
|
|
62
|
+
* Creates a view of a globe.
|
|
63
|
+
*
|
|
64
|
+
* @extends View
|
|
65
|
+
*
|
|
66
|
+
* @example <caption><b>Instance GlobeView.</b></caption>
|
|
67
|
+
* var viewerDiv = document.getElementById('viewerDiv');
|
|
68
|
+
* const placement = {
|
|
69
|
+
* coord: new itowns.Coordinates('EPSG:4326', 2.351323, 48.856712),
|
|
70
|
+
* range: 25000000,
|
|
71
|
+
* }
|
|
72
|
+
* var view = new itowns.GlobeView(viewerDiv, placement);
|
|
73
|
+
*
|
|
74
|
+
* @param {HTMLDivElement} viewerDiv - Where to attach the view and display it
|
|
75
|
+
* in the DOM.
|
|
76
|
+
* @param {CameraTransformOptions|Extent} placement - An object to place view
|
|
77
|
+
* @param {object} [options] - See options of {@link View}.
|
|
78
|
+
* @param {Object} [options.controls] - See options of {@link GlobeControls}
|
|
79
|
+
*/
|
|
80
|
+
constructor(viewerDiv) {
|
|
81
|
+
let placement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
82
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
83
|
+
THREE.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
84
|
+
// Setup View
|
|
85
|
+
super('EPSG:4978', viewerDiv, options);
|
|
86
|
+
this.isGlobeView = true;
|
|
87
|
+
this.camera3D.near = Math.max(15.0, 0.000002352 * ellipsoidSizes.x);
|
|
88
|
+
this.camera3D.far = ellipsoidSizes.x * 10;
|
|
89
|
+
const tileLayer = new GlobeLayer('globe', options.object3d, options);
|
|
90
|
+
this.mainLoop.gfxEngine.label2dRenderer.infoTileLayer = tileLayer.info;
|
|
91
|
+
this.addLayer(tileLayer);
|
|
92
|
+
this.tileLayer = tileLayer;
|
|
93
|
+
if (!placement.isExtent) {
|
|
94
|
+
placement.coord = placement.coord || new Coordinates('EPSG:4326', 0, 0);
|
|
95
|
+
placement.tilt = placement.tilt || 89.5;
|
|
96
|
+
placement.heading = placement.heading || 0;
|
|
97
|
+
placement.range = placement.range || ellipsoidSizes.x * 2.0;
|
|
98
|
+
}
|
|
99
|
+
if (options.noControls) {
|
|
100
|
+
CameraUtils.transformCameraToLookAtTarget(this, this.camera3D, placement);
|
|
101
|
+
} else {
|
|
102
|
+
this.controls = new GlobeControls(this, placement, options.controls);
|
|
103
|
+
this.controls.handleCollision = typeof options.handleCollision !== 'undefined' ? options.handleCollision : true;
|
|
104
|
+
}
|
|
105
|
+
this.addLayer(new Atmosphere('atmosphere', options.atmosphere));
|
|
106
|
+
|
|
107
|
+
// GlobeView needs this.camera.resize to set perpsective matrix camera
|
|
108
|
+
this.camera.resize(viewerDiv.clientWidth, viewerDiv.clientHeight);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Add layer in viewer.
|
|
113
|
+
* The layer id must be unique.
|
|
114
|
+
*
|
|
115
|
+
* The `layer.whenReady` is a promise that resolves when
|
|
116
|
+
* the layer is done. This promise is also returned by
|
|
117
|
+
* `addLayer` allowing to chain call.
|
|
118
|
+
*
|
|
119
|
+
* The layer added is attached, by default to `GlobeLayer` (`GlobeView.tileLayer`).
|
|
120
|
+
* If you want add a unattached layer use `View#addLayer` parent method.
|
|
121
|
+
*
|
|
122
|
+
* @param {LayerOptions|Layer|GeometryLayer} layer The layer to add in view.
|
|
123
|
+
* @return {Promise} a promise resolved with the new layer object when it is fully initialized or rejected if any error occurred.
|
|
124
|
+
*/
|
|
125
|
+
addLayer(layer) {
|
|
126
|
+
if (!layer || !layer.isLayer) {
|
|
127
|
+
return Promise.reject(new Error('Add Layer type object'));
|
|
128
|
+
}
|
|
129
|
+
if (layer.isColorLayer) {
|
|
130
|
+
if (!this.tileLayer.tileMatrixSets.includes(layer.source.crs)) {
|
|
131
|
+
return layer._reject(`Only ${this.tileLayer.tileMatrixSets} tileMatrixSet are currently supported for color layers`);
|
|
132
|
+
}
|
|
133
|
+
} else if (layer.isElevationLayer) {
|
|
134
|
+
if (layer.source.crs !== this.tileLayer.tileMatrixSets[0]) {
|
|
135
|
+
return layer._reject(`Only ${this.tileLayer.tileMatrixSets[0]} tileMatrixSet is currently supported for elevation layers`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return super.addLayer(layer, this.tileLayer);
|
|
139
|
+
}
|
|
140
|
+
getPixelsToDegrees() {
|
|
141
|
+
let pixels = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
142
|
+
let screenCoord = arguments.length > 1 ? arguments[1] : undefined;
|
|
143
|
+
return this.getMetersToDegrees(this.getPixelsToMeters(pixels, screenCoord));
|
|
144
|
+
}
|
|
145
|
+
getPixelsToDegreesFromDistance() {
|
|
146
|
+
let pixels = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
147
|
+
let distance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
|
|
148
|
+
return this.getMetersToDegrees(this.getPixelsToMetersFromDistance(pixels, distance));
|
|
149
|
+
}
|
|
150
|
+
getMetersToDegrees() {
|
|
151
|
+
let meters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
152
|
+
return THREE.MathUtils.radToDeg(2 * Math.asin(meters / (2 * ellipsoidSizes.x)));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
export default GlobeView;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import TiledGeometryLayer from "../../../Layer/TiledGeometryLayer.js";
|
|
3
|
+
import { globalExtentTMS } from "../../Tile/TileGrid.js";
|
|
4
|
+
import { PlanarTileBuilder } from "./PlanarTileBuilder.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @property {boolean} isPlanarLayer - Used to checkout whether this layer is a
|
|
8
|
+
* PlanarLayer. Default is true. You should not change this, as it is used
|
|
9
|
+
* internally for optimisation.
|
|
10
|
+
* @extends TiledGeometryLayer
|
|
11
|
+
*/
|
|
12
|
+
class PlanarLayer extends TiledGeometryLayer {
|
|
13
|
+
/**
|
|
14
|
+
* A {@link TiledGeometryLayer} to use with a {@link PlanarView}. It has
|
|
15
|
+
* specific method for updating and subdivising its grid.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} id - The id of the layer, that should be unique. It is
|
|
18
|
+
* not mandatory, but an error will be emitted if this layer is added a
|
|
19
|
+
* {@link View} that already has a layer going by that id.
|
|
20
|
+
* @param {Extent} extent - The extent to define the layer within.
|
|
21
|
+
* @param {THREE.Object3d} [object3d=THREE.Group] - The object3d used to
|
|
22
|
+
* contain the geometry of the TiledGeometryLayer. It is usually a
|
|
23
|
+
* `THREE.Group`, but it can be anything inheriting from a `THREE.Object3d`.
|
|
24
|
+
* @param {Object} [config] - Optional configuration, all elements in it
|
|
25
|
+
* will be merged as is in the layer. For example, if the configuration
|
|
26
|
+
* contains three elements `name, protocol, extent`, these elements will be
|
|
27
|
+
* available using `layer.name` or something else depending on the property
|
|
28
|
+
* name.
|
|
29
|
+
* @param {number} [config.maxSubdivisionLevel=5] - Maximum subdivision
|
|
30
|
+
* level for this tiled layer.
|
|
31
|
+
*
|
|
32
|
+
* @throws {Error} `object3d` must be a valid `THREE.Object3d`.
|
|
33
|
+
*/
|
|
34
|
+
constructor(id, extent, object3d) {
|
|
35
|
+
let config = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
36
|
+
const {
|
|
37
|
+
minSubdivisionLevel = 0,
|
|
38
|
+
maxSubdivisionLevel = 5,
|
|
39
|
+
...tiledConfig
|
|
40
|
+
} = config;
|
|
41
|
+
const tileMatrixSets = [extent.crs];
|
|
42
|
+
if (!globalExtentTMS.get(extent.crs)) {
|
|
43
|
+
// Add new global extent for this new crs projection.
|
|
44
|
+
globalExtentTMS.set(extent.crs, extent);
|
|
45
|
+
}
|
|
46
|
+
const builder = new PlanarTileBuilder({
|
|
47
|
+
crs: extent.crs
|
|
48
|
+
});
|
|
49
|
+
super(id, object3d || new THREE.Group(), [extent], builder, {
|
|
50
|
+
tileMatrixSets,
|
|
51
|
+
...tiledConfig
|
|
52
|
+
});
|
|
53
|
+
this.isPlanarLayer = true;
|
|
54
|
+
this.extent = extent;
|
|
55
|
+
this.minSubdivisionLevel = minSubdivisionLevel;
|
|
56
|
+
this.maxSubdivisionLevel = maxSubdivisionLevel;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export default PlanarLayer;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { Coordinates, Extent } from '@itowns/geographic';
|
|
3
|
+
const quaternion = new THREE.Quaternion();
|
|
4
|
+
const center = new THREE.Vector3();
|
|
5
|
+
|
|
6
|
+
/** Specialized parameters for the [PlanarTileBuilder]. */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* TileBuilder implementation for the purpose of generating planar
|
|
10
|
+
* tile arrangements.
|
|
11
|
+
*/
|
|
12
|
+
export class PlanarTileBuilder {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
if (options.projection) {
|
|
15
|
+
console.warn('PlanarTileBuilder projection parameter is deprecated,' + ' use crs instead.');
|
|
16
|
+
options.crs ??= options.projection;
|
|
17
|
+
}
|
|
18
|
+
this._crs = options.crs;
|
|
19
|
+
this._transform = {
|
|
20
|
+
coords: new Coordinates('EPSG:4326', 0, 0),
|
|
21
|
+
position: new THREE.Vector3(),
|
|
22
|
+
normal: new THREE.Vector3(0, 0, 1)
|
|
23
|
+
};
|
|
24
|
+
this._uvCount = options.uvCount ?? 1;
|
|
25
|
+
}
|
|
26
|
+
get uvCount() {
|
|
27
|
+
return this._uvCount;
|
|
28
|
+
}
|
|
29
|
+
get crs() {
|
|
30
|
+
return this._crs;
|
|
31
|
+
}
|
|
32
|
+
prepare(params) {
|
|
33
|
+
const newParams = params;
|
|
34
|
+
newParams.nbRow = 2 ** (params.level + 1.0);
|
|
35
|
+
newParams.coordinates = new Coordinates(this.crs);
|
|
36
|
+
return newParams;
|
|
37
|
+
}
|
|
38
|
+
center(extent) {
|
|
39
|
+
extent.center(this._transform.coords);
|
|
40
|
+
center.set(this._transform.coords.x, this._transform.coords.y, 0);
|
|
41
|
+
return center;
|
|
42
|
+
}
|
|
43
|
+
vertexPosition(coordinates) {
|
|
44
|
+
this._transform.position.set(coordinates.x, coordinates.y, 0);
|
|
45
|
+
return this._transform.position;
|
|
46
|
+
}
|
|
47
|
+
vertexNormal() {
|
|
48
|
+
return this._transform.normal;
|
|
49
|
+
}
|
|
50
|
+
uProject(u, extent) {
|
|
51
|
+
return extent.west + u * (extent.east - extent.west);
|
|
52
|
+
}
|
|
53
|
+
vProject(v, extent) {
|
|
54
|
+
return extent.south + v * (extent.north - extent.south);
|
|
55
|
+
}
|
|
56
|
+
computeShareableExtent(extent) {
|
|
57
|
+
// compute shareable extent to pool the geometries
|
|
58
|
+
// the geometry in common extent is identical to the existing input
|
|
59
|
+
// with a translation
|
|
60
|
+
return {
|
|
61
|
+
shareableExtent: new Extent(extent.crs).setFromExtent({
|
|
62
|
+
west: 0,
|
|
63
|
+
east: Math.abs(extent.west - extent.east),
|
|
64
|
+
south: 0,
|
|
65
|
+
north: Math.abs(extent.north - extent.south)
|
|
66
|
+
}),
|
|
67
|
+
quaternion,
|
|
68
|
+
position: this.center(extent).clone()
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import View from "../View.js";
|
|
3
|
+
import CameraUtils from "../../Utils/CameraUtils.js";
|
|
4
|
+
import PlanarControls from "../../Controls/PlanarControls.js";
|
|
5
|
+
import PlanarLayer from "./Planar/PlanarLayer.js";
|
|
6
|
+
class PlanarView extends View {
|
|
7
|
+
/**
|
|
8
|
+
* @extends View
|
|
9
|
+
*
|
|
10
|
+
* @example <caption><b>Instance with placement on the ground.</b></caption>
|
|
11
|
+
* var viewerDiv = document.getElementById('viewerDiv');
|
|
12
|
+
* const extent = new Extent('EPSG:3946', 1837816.94334, 1847692.32501, 5170036.4587, 5178412.82698);
|
|
13
|
+
* var view = new itowns.PlanarView(viewerDiv, extent, { placement: { heading: -49.6, range: 6200, tilt: 17 } });
|
|
14
|
+
*
|
|
15
|
+
* @param {HTMLDivElement} viewerDiv - Where to attach the view and display it
|
|
16
|
+
* in the DOM.
|
|
17
|
+
* @param {Extent} extent - The ground extent.
|
|
18
|
+
* @param {Object} [options] - See options of {@link View}.
|
|
19
|
+
* @param {boolean} [options.noControls=false] - If true, no controls are associated to the view.
|
|
20
|
+
* @param {Object} [options.controls] - options for the {@link PlanarControls} associated to the view, if
|
|
21
|
+
* `options.noControls` is false.
|
|
22
|
+
* @param {CameraUtils~CameraTransformOptions|Extent} [options.placement] - The
|
|
23
|
+
* {@link CameraUtils~CameraTransformOptions} to apply to view's camera or the extent it must display at
|
|
24
|
+
* initialization. By default, camera will display the view's extent (given in `extent` parameter).
|
|
25
|
+
*/
|
|
26
|
+
constructor(viewerDiv, extent) {
|
|
27
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
28
|
+
THREE.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
29
|
+
|
|
30
|
+
// Setup View
|
|
31
|
+
super(extent.crs, viewerDiv, options);
|
|
32
|
+
this.isPlanarView = true;
|
|
33
|
+
|
|
34
|
+
// Configure camera
|
|
35
|
+
const dim = extent.planarDimensions();
|
|
36
|
+
const max = Math.max(dim.x, dim.y);
|
|
37
|
+
this.camera3D.near = 0.1;
|
|
38
|
+
this.camera3D.far = this.camera3D.isOrthographicCamera ? 2000 : 2 * max;
|
|
39
|
+
this.camera3D.updateProjectionMatrix();
|
|
40
|
+
const tileLayer = new PlanarLayer('planar', extent, options.object3d, options);
|
|
41
|
+
this.mainLoop.gfxEngine.label2dRenderer.infoTileLayer = tileLayer.info;
|
|
42
|
+
this.addLayer(tileLayer);
|
|
43
|
+
|
|
44
|
+
// Configure camera
|
|
45
|
+
const placement = options.placement || {};
|
|
46
|
+
if (!placement.isExtent) {
|
|
47
|
+
placement.coord = placement.coord || extent.center();
|
|
48
|
+
placement.tilt = placement.tilt || 90;
|
|
49
|
+
placement.heading = placement.heading || 0;
|
|
50
|
+
placement.range = placement.range || max;
|
|
51
|
+
}
|
|
52
|
+
CameraUtils.transformCameraToLookAtTarget(this, this.camera3D, placement);
|
|
53
|
+
if (!options.noControls) {
|
|
54
|
+
this.controls = new PlanarControls(this, options.controls);
|
|
55
|
+
}
|
|
56
|
+
this.tileLayer = tileLayer;
|
|
57
|
+
}
|
|
58
|
+
addLayer(layer) {
|
|
59
|
+
return super.addLayer(layer, this.tileLayer);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export default PlanarView;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { TileGeometry } from "../TileGeometry.js";
|
|
3
|
+
import { LRUCache } from 'lru-cache';
|
|
4
|
+
import { computeBuffers } from "./computeBufferTileGeometry.js";
|
|
5
|
+
import OBB from "../../Renderer/OBB.js";
|
|
6
|
+
const cacheBuffer = new Map();
|
|
7
|
+
const cacheTile = new LRUCache({
|
|
8
|
+
max: 500
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reference to a tile's extent with rigid transformations.
|
|
13
|
+
* Enables reuse of geometry, saving a bit of memory.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export function newTileGeometry(builder, params) {
|
|
17
|
+
const {
|
|
18
|
+
shareableExtent,
|
|
19
|
+
quaternion,
|
|
20
|
+
position
|
|
21
|
+
} = builder.computeShareableExtent(params.extent);
|
|
22
|
+
const south = shareableExtent.south.toFixed(6);
|
|
23
|
+
const bufferKey = `${builder.crs}_${params.disableSkirt ? 0 : 1}_${params.segments}`;
|
|
24
|
+
const key = `s${south}l${params.level}bK${bufferKey}`;
|
|
25
|
+
let promiseGeometry = cacheTile.get(key);
|
|
26
|
+
|
|
27
|
+
// build geometry if doesn't exist
|
|
28
|
+
if (!promiseGeometry) {
|
|
29
|
+
let resolve;
|
|
30
|
+
promiseGeometry = new Promise(r => {
|
|
31
|
+
resolve = r;
|
|
32
|
+
});
|
|
33
|
+
cacheTile.set(key, promiseGeometry);
|
|
34
|
+
params.extent = shareableExtent;
|
|
35
|
+
params.center = builder.center(params.extent).clone();
|
|
36
|
+
// Read previously cached values (index and uv.wgs84 only
|
|
37
|
+
// depend on the # of triangles)
|
|
38
|
+
let cachedBuffers = cacheBuffer.get(bufferKey);
|
|
39
|
+
let buffers;
|
|
40
|
+
try {
|
|
41
|
+
buffers = computeBuffers(builder, params, cachedBuffers !== undefined ? {
|
|
42
|
+
index: cachedBuffers.index.array,
|
|
43
|
+
uv: cachedBuffers.uv.array
|
|
44
|
+
} : undefined);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return Promise.reject(e);
|
|
47
|
+
}
|
|
48
|
+
if (!cachedBuffers) {
|
|
49
|
+
// We know the fields will exist due to the condition
|
|
50
|
+
// matching with the one for buildIndexAndUv_0.
|
|
51
|
+
// TODO: Make this brain-based check compiler-based.
|
|
52
|
+
|
|
53
|
+
cachedBuffers = {
|
|
54
|
+
index: new THREE.BufferAttribute(buffers.index, 1),
|
|
55
|
+
uv: new THREE.BufferAttribute(buffers.uvs[0], 2)
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Update cacheBuffer
|
|
59
|
+
cacheBuffer.set(bufferKey, cachedBuffers);
|
|
60
|
+
}
|
|
61
|
+
const gpuBuffers = {
|
|
62
|
+
index: cachedBuffers.index,
|
|
63
|
+
uvs: [cachedBuffers.uv, ...(buffers.uvs[1] !== undefined ? [new THREE.BufferAttribute(buffers.uvs[1], 1)] : [])],
|
|
64
|
+
position: new THREE.BufferAttribute(buffers.position, 3),
|
|
65
|
+
normal: new THREE.BufferAttribute(buffers.normal, 3)
|
|
66
|
+
};
|
|
67
|
+
const geometry = new TileGeometry(builder, params, gpuBuffers);
|
|
68
|
+
geometry.OBB = new OBB(geometry.boundingBox.min, geometry.boundingBox.max);
|
|
69
|
+
geometry.initRefCount(cacheTile, key);
|
|
70
|
+
resolve(geometry);
|
|
71
|
+
return Promise.resolve({
|
|
72
|
+
geometry,
|
|
73
|
+
quaternion,
|
|
74
|
+
position
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return promiseGeometry.then(geometry => ({
|
|
78
|
+
geometry,
|
|
79
|
+
quaternion,
|
|
80
|
+
position
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
export function getBufferIndexSize(segments, noSkirt) {
|
|
3
|
+
const triangles = segments * segments * 2 + (noSkirt ? 0 : 4 * segments * 2);
|
|
4
|
+
return triangles * 3;
|
|
5
|
+
}
|
|
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, cache) {
|
|
20
|
+
const indexBufferSize = getBufferIndexSize(nSeg, params.disableSkirt);
|
|
21
|
+
const indexConstructor = getUintArrayConstructor(nVertex);
|
|
22
|
+
const tileLen = indexBufferSize;
|
|
23
|
+
const skirtLen = 4 * nSeg;
|
|
24
|
+
if (cache !== undefined) {
|
|
25
|
+
return {
|
|
26
|
+
index: cache,
|
|
27
|
+
skirt: cache.subarray(tileLen, tileLen + skirtLen)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const indexBuffer = new ArrayBuffer((
|
|
31
|
+
// Tile
|
|
32
|
+
tileLen
|
|
33
|
+
// Skirt
|
|
34
|
+
+ (params.disableSkirt ? 0 : skirtLen)) * indexConstructor.BYTES_PER_ELEMENT);
|
|
35
|
+
const index = new indexConstructor(indexBuffer);
|
|
36
|
+
const skirt = !params.disableSkirt ? index.subarray(tileLen, tileLen + skirtLen) : undefined;
|
|
37
|
+
return {
|
|
38
|
+
index,
|
|
39
|
+
skirt
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function allocateBuffers(nVertex, nSeg, builder, params, cache) {
|
|
43
|
+
const {
|
|
44
|
+
index,
|
|
45
|
+
skirt
|
|
46
|
+
} = allocateIndexBuffer(nVertex, nSeg, params, cache?.index);
|
|
47
|
+
return {
|
|
48
|
+
index,
|
|
49
|
+
skirt,
|
|
50
|
+
position: new Float32Array(nVertex * 3),
|
|
51
|
+
normal: new Float32Array(nVertex * 3),
|
|
52
|
+
// 2 UV set per tile: wgs84 (uv[0]) and pseudo-mercator (pm, uv[1])
|
|
53
|
+
// - wgs84: 1 texture per tile because tiles are using wgs84
|
|
54
|
+
// projection
|
|
55
|
+
// - pm: use multiple textures per tile.
|
|
56
|
+
// +-------------------------+
|
|
57
|
+
// | |
|
|
58
|
+
// | Texture 0 |
|
|
59
|
+
// +-------------------------+
|
|
60
|
+
// | |
|
|
61
|
+
// | Texture 1 |
|
|
62
|
+
// +-------------------------+
|
|
63
|
+
// | |
|
|
64
|
+
// | Texture 2 |
|
|
65
|
+
// +-------------------------+
|
|
66
|
+
// * u = wgs84.u
|
|
67
|
+
// * v = textureid + v in builder texture
|
|
68
|
+
uvs: [cache?.uv ?? new Float32Array(nVertex * 2), builder.computeExtraOffset !== undefined ? new Float32Array(nVertex) : undefined]
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function computeUv0(uv, id, u, v) {
|
|
72
|
+
uv[id * 2 + 0] = u;
|
|
73
|
+
uv[id * 2 + 1] = v;
|
|
74
|
+
}
|
|
75
|
+
function initComputeUv1(value) {
|
|
76
|
+
return (uv, id) => {
|
|
77
|
+
uv[id] = value;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/** Compute buffers describing a tile according to a builder and its params. */
|
|
81
|
+
// TODO: Split this even further into subfunctions
|
|
82
|
+
export function computeBuffers(builder, params, cache) {
|
|
83
|
+
// n seg, n+1 vert + <- skirt, n verts per side
|
|
84
|
+
// <---------------> / |
|
|
85
|
+
// +---+---+---+---+ |
|
|
86
|
+
// | / | / | / | / | | Vertices:
|
|
87
|
+
// +---+---+---+---+ - + tile = (n + 1)^2
|
|
88
|
+
// | / | / | / | / | | skirt = 4n
|
|
89
|
+
// +---+---+---+---+ - +
|
|
90
|
+
// | / | / | / | / | | Segments:
|
|
91
|
+
// +---+---+---+---+ - + tile = 2 * n * (n + 1) + n^2
|
|
92
|
+
// | / | / | / | / | | skirt = 2n * 4
|
|
93
|
+
// +---+---+---+---+ |
|
|
94
|
+
const nSeg = Math.max(2, params.segments);
|
|
95
|
+
const nVertex = nSeg + 1;
|
|
96
|
+
const nTileVertex = nVertex ** 2;
|
|
97
|
+
const nSkirtVertex = params.disableSkirt ? 0 : 4 * nSeg;
|
|
98
|
+
const nTotalVertex = nTileVertex + nSkirtVertex;
|
|
99
|
+
|
|
100
|
+
// Computer should combust before this happens
|
|
101
|
+
if (nTotalVertex > 2 ** 32) {
|
|
102
|
+
throw new Error('Tile segments count is too big');
|
|
103
|
+
}
|
|
104
|
+
const outBuffers = allocateBuffers(nTotalVertex, nSeg, builder, params, cache);
|
|
105
|
+
const computeUvs = [cache === undefined ? computeUv0 : () => {}];
|
|
106
|
+
params = builder.prepare(params);
|
|
107
|
+
for (let y = 0; y <= nSeg; y++) {
|
|
108
|
+
const v = y / nSeg;
|
|
109
|
+
params.coordinates.y = builder.vProject(v, params.extent);
|
|
110
|
+
if (builder.computeExtraOffset !== undefined) {
|
|
111
|
+
computeUvs[1] = initComputeUv1(builder.computeExtraOffset(params));
|
|
112
|
+
}
|
|
113
|
+
for (let x = 0; x <= nSeg; x++) {
|
|
114
|
+
const u = x / nSeg;
|
|
115
|
+
const id_m3 = (y * nVertex + x) * 3;
|
|
116
|
+
params.coordinates.x = builder.uProject(u, params.extent);
|
|
117
|
+
const vertex = builder.vertexPosition(params.coordinates);
|
|
118
|
+
const normal = builder.vertexNormal();
|
|
119
|
+
|
|
120
|
+
// move geometry to center world
|
|
121
|
+
vertex.sub(params.center);
|
|
122
|
+
|
|
123
|
+
// align normal to z axis
|
|
124
|
+
// HACK: this check style is not great
|
|
125
|
+
if ('quatNormalToZ' in params) {
|
|
126
|
+
const quat = params.quatNormalToZ;
|
|
127
|
+
vertex.applyQuaternion(quat);
|
|
128
|
+
normal.applyQuaternion(quat);
|
|
129
|
+
}
|
|
130
|
+
vertex.toArray(outBuffers.position, id_m3);
|
|
131
|
+
normal.toArray(outBuffers.normal, id_m3);
|
|
132
|
+
for (const [index, computeUv] of computeUvs.entries()) {
|
|
133
|
+
if (computeUv !== undefined) {
|
|
134
|
+
computeUv(outBuffers.uvs[index], y * nVertex + x, u, v);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Fill skirt index buffer
|
|
141
|
+
if (cache === undefined && !params.disableSkirt) {
|
|
142
|
+
for (let x = 0; x < nVertex; x++) {
|
|
143
|
+
// -------->
|
|
144
|
+
// 0---1---2
|
|
145
|
+
// | / | / | [0-9] = assign order
|
|
146
|
+
// +---+---+
|
|
147
|
+
// | / | / |
|
|
148
|
+
// +---+---+
|
|
149
|
+
outBuffers.skirt[x] = x;
|
|
150
|
+
// +---+---+
|
|
151
|
+
// | / | / | [0-9] = assign order
|
|
152
|
+
// +---+---x x = skipped for now
|
|
153
|
+
// | / | / |
|
|
154
|
+
// 0---1---2
|
|
155
|
+
// <--------
|
|
156
|
+
outBuffers.skirt[2 * nVertex - 2 + x] = nVertex ** 2 - (x + 1);
|
|
157
|
+
}
|
|
158
|
+
for (let y = 1; y < nVertex - 1; y++) {
|
|
159
|
+
// +---+---s |
|
|
160
|
+
// | / | / | | o = stored vertices
|
|
161
|
+
// +---+---o | s = already stored
|
|
162
|
+
// | / | / | |
|
|
163
|
+
// +---+---s v
|
|
164
|
+
outBuffers.skirt[nVertex - 1 + y] = y * nVertex + (nVertex - 1);
|
|
165
|
+
// ^ s---+---+
|
|
166
|
+
// | | / | / | o = stored vertices
|
|
167
|
+
// | o---+---+ s = already stored
|
|
168
|
+
// | | / | / |
|
|
169
|
+
// | s---+---+
|
|
170
|
+
outBuffers.skirt[3 * nVertex - 3 + y] = nVertex * (nVertex - 1 - y);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Copy passed indices at the desired index of the output index buffer. */
|
|
175
|
+
function bufferizeTri(id, va, vb, vc) {
|
|
176
|
+
outBuffers.index[id + 0] = va;
|
|
177
|
+
outBuffers.index[id + 1] = vb;
|
|
178
|
+
outBuffers.index[id + 2] = vc;
|
|
179
|
+
}
|
|
180
|
+
if (cache === undefined) {
|
|
181
|
+
for (let y = 0; y < nSeg; y++) {
|
|
182
|
+
for (let x = 0; x < nSeg; x++) {
|
|
183
|
+
const v1 = y * nVertex + (x + 1);
|
|
184
|
+
const v2 = y * nVertex + x;
|
|
185
|
+
const v3 = (y + 1) * nVertex + x;
|
|
186
|
+
const v4 = (y + 1) * nVertex + (x + 1);
|
|
187
|
+
const id = (y * nSeg + x) * 6;
|
|
188
|
+
bufferizeTri(id, /**/v4, v2, v1);
|
|
189
|
+
bufferizeTri(id + 3, v4, v3, v2);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// PERF: Beware skirt's size influences performance
|
|
195
|
+
// INFO: The size of the skirt is now a ratio of the size of the tile.
|
|
196
|
+
// To be perfect it should depend on the real elevation delta but too heavy
|
|
197
|
+
// to compute
|
|
198
|
+
if (!params.disableSkirt) {
|
|
199
|
+
// We compute the actual size of tile segment to use later for
|
|
200
|
+
// the skirt.
|
|
201
|
+
const segmentSize = new THREE.Vector3().fromArray(outBuffers.position).distanceTo(new THREE.Vector3().fromArray(outBuffers.position, 3));
|
|
202
|
+
const buildSkirt = cache === undefined ? {
|
|
203
|
+
index: (id, v1, v2, v3, v4) => {
|
|
204
|
+
bufferizeTri(id, v1, v2, v3);
|
|
205
|
+
bufferizeTri(id + 3, v1, v3, v4);
|
|
206
|
+
return id + 6;
|
|
207
|
+
},
|
|
208
|
+
uv: (buf, idTo, idFrom) => {
|
|
209
|
+
buf[idTo * 2 + 0] = buf[idFrom * 2 + 0];
|
|
210
|
+
buf[idTo * 2 + 1] = buf[idFrom * 2 + 1];
|
|
211
|
+
}
|
|
212
|
+
} : {
|
|
213
|
+
index: () => {},
|
|
214
|
+
uv: () => {}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// Alias for readability
|
|
218
|
+
const start = nTileVertex;
|
|
219
|
+
for (let i = 0; i < outBuffers.skirt.length; i++) {
|
|
220
|
+
const id = outBuffers.skirt[i];
|
|
221
|
+
const id_m3 = (start + i) * 3;
|
|
222
|
+
const id2_m3 = id * 3;
|
|
223
|
+
outBuffers.position[id_m3 + 0] = outBuffers.position[id2_m3 + 0] - outBuffers.normal[id2_m3 + 0] * segmentSize;
|
|
224
|
+
outBuffers.position[id_m3 + 1] = outBuffers.position[id2_m3 + 1] - outBuffers.normal[id2_m3 + 1] * segmentSize;
|
|
225
|
+
outBuffers.position[id_m3 + 2] = outBuffers.position[id2_m3 + 2] - outBuffers.normal[id2_m3 + 2] * segmentSize;
|
|
226
|
+
outBuffers.normal[id_m3 + 0] = outBuffers.normal[id2_m3 + 0];
|
|
227
|
+
outBuffers.normal[id_m3 + 1] = outBuffers.normal[id2_m3 + 1];
|
|
228
|
+
outBuffers.normal[id_m3 + 2] = outBuffers.normal[id2_m3 + 2];
|
|
229
|
+
buildSkirt.uv(outBuffers.uvs[0], start + i, id);
|
|
230
|
+
if (outBuffers.uvs[1] !== undefined) {
|
|
231
|
+
outBuffers.uvs[1][start + i] = outBuffers.uvs[1][id];
|
|
232
|
+
}
|
|
233
|
+
const idf = (i + 1) % outBuffers.skirt.length;
|
|
234
|
+
const v2 = start + i;
|
|
235
|
+
const v3 = idf === 0 ? start : start + i + 1;
|
|
236
|
+
const v4 = outBuffers.skirt[idf];
|
|
237
|
+
buildSkirt.index(6 * nSeg ** 2 + i * 6, id, v2, v3, v4);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Dropping skirt view
|
|
242
|
+
return {
|
|
243
|
+
index: outBuffers.index,
|
|
244
|
+
position: outBuffers.position,
|
|
245
|
+
uvs: outBuffers.uvs,
|
|
246
|
+
normal: outBuffers.normal
|
|
247
|
+
};
|
|
248
|
+
}
|