@cesium/engine 22.3.0 → 23.0.0

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 (193) hide show
  1. package/Build/Workers/{chunk-EAAH543Q.js → chunk-2GL2EUEE.js} +11 -11
  2. package/Build/Workers/{chunk-EUDHHS7K.js → chunk-2WI4HGJU.js} +6 -6
  3. package/Build/Workers/{chunk-LWZHJWYK.js → chunk-36LBFITA.js} +665 -366
  4. package/Build/Workers/{chunk-7U5YNLF3.js → chunk-3B65YFXC.js} +1 -1
  5. package/Build/Workers/{chunk-D63Z7KKL.js → chunk-4LGFX2P5.js} +11 -11
  6. package/Build/Workers/{chunk-D6OKR3BQ.js → chunk-4UNQX2MP.js} +2 -2
  7. package/Build/Workers/{chunk-BO22JHBX.js → chunk-52K3GJKG.js} +3 -3
  8. package/Build/Workers/{chunk-XLIJV3YZ.js → chunk-56OHFSLH.js} +10 -10
  9. package/Build/Workers/{chunk-AWELU5C6.js → chunk-5A7YSAXT.js} +14 -14
  10. package/Build/Workers/{chunk-T5MJDW43.js → chunk-5JP5FG7U.js} +7 -7
  11. package/Build/Workers/{chunk-NVL7JXAQ.js → chunk-5R7SBUTW.js} +10 -10
  12. package/Build/Workers/chunk-5VKZVPO5.js +1829 -0
  13. package/Build/Workers/{chunk-YHPBT4I5.js → chunk-6FVFM2KB.js} +5 -5
  14. package/Build/Workers/{chunk-WHLGBMBC.js → chunk-6SLGTBB2.js} +5 -5
  15. package/Build/Workers/{chunk-VIQIKMTZ.js → chunk-7KRN6JPQ.js} +14 -14
  16. package/Build/Workers/{chunk-TCOUGKXF.js → chunk-AA33B6PU.js} +4 -4
  17. package/Build/Workers/{chunk-S2KVL7OJ.js → chunk-AP6XWET5.js} +8 -8
  18. package/Build/Workers/{chunk-5PJB7ASO.js → chunk-APDKMX7W.js} +6 -6
  19. package/Build/Workers/{chunk-IXL46IYV.js → chunk-ARCFIOKA.js} +12 -12
  20. package/Build/Workers/{chunk-KIJR26N3.js → chunk-BNBD2YZK.js} +16 -16
  21. package/Build/Workers/{chunk-4R6FGUFP.js → chunk-DT5SJBKA.js} +29 -15
  22. package/Build/Workers/{chunk-FUDC3KOT.js → chunk-ESD4IEOU.js} +5 -5
  23. package/Build/Workers/{chunk-K2PLKJJG.js → chunk-FSDVXW7M.js} +5 -5
  24. package/Build/Workers/{chunk-4BBANFU6.js → chunk-G3YT7M7A.js} +1 -1
  25. package/Build/Workers/{chunk-K4PGSAR5.js → chunk-GN5NEUDT.js} +8 -8
  26. package/Build/Workers/{chunk-OOYICVOK.js → chunk-HYLEKKO5.js} +1 -1
  27. package/Build/Workers/{chunk-FDOLXORR.js → chunk-HYTFXWMY.js} +7 -7
  28. package/Build/Workers/{chunk-7SLNBIZS.js → chunk-IFA7VHHP.js} +560 -277
  29. package/Build/Workers/{chunk-N66PIK46.js → chunk-IYVDOB5V.js} +4 -4
  30. package/Build/Workers/{chunk-ZWWN2CQH.js → chunk-JUGY5AZN.js} +4 -4
  31. package/Build/Workers/{chunk-4O2ARYS7.js → chunk-KPYU6YZG.js} +1 -1
  32. package/Build/Workers/{chunk-TY5JXMVO.js → chunk-L7RDJ4V7.js} +1 -1
  33. package/Build/Workers/{chunk-L4OFWHNI.js → chunk-LDQWNMEC.js} +1 -1
  34. package/Build/Workers/{chunk-N6XBJBI7.js → chunk-MQJG522T.js} +6 -6
  35. package/Build/Workers/{chunk-FS42VX2H.js → chunk-MT5M7RLZ.js} +2 -2
  36. package/Build/Workers/{chunk-7ATKQRBM.js → chunk-N4AWE7TZ.js} +10 -10
  37. package/Build/Workers/{chunk-EOSX23OS.js → chunk-NAYRNPEP.js} +4 -4
  38. package/Build/Workers/{chunk-NO3LMU7T.js → chunk-NNHU33JK.js} +7 -7
  39. package/Build/Workers/{chunk-HWGP4GVC.js → chunk-NQCAZU7S.js} +13 -13
  40. package/Build/Workers/{chunk-6GBGEUWR.js → chunk-NUYLNQKV.js} +2 -2
  41. package/Build/Workers/{chunk-E4YDCSQK.js → chunk-OC6X22PG.js} +9 -9
  42. package/Build/Workers/{chunk-ZGGVEGTA.js → chunk-OHBM4YG4.js} +12 -12
  43. package/Build/Workers/{chunk-6WDMPXQ7.js → chunk-OMXN7YF4.js} +12 -12
  44. package/Build/Workers/{chunk-LK7GEFGB.js → chunk-OQ3EAJNW.js} +2 -2
  45. package/Build/Workers/{chunk-M5DVYXJJ.js → chunk-OQBPOKPZ.js} +6 -6
  46. package/Build/Workers/{chunk-WUWPKBOZ.js → chunk-PQVNT5CJ.js} +6 -6
  47. package/Build/Workers/{chunk-W5NV72VR.js → chunk-QA24Q62E.js} +17 -17
  48. package/Build/Workers/{chunk-PJLRXIMS.js → chunk-QQX7S5QT.js} +17 -17
  49. package/Build/Workers/{chunk-D2PEV362.js → chunk-QTOHIXGF.js} +10 -10
  50. package/Build/Workers/{chunk-MASEF4OV.js → chunk-R7M4XNPP.js} +8 -8
  51. package/Build/Workers/{chunk-2MLJ46ZZ.js → chunk-SGKTBHFQ.js} +13 -13
  52. package/Build/Workers/{chunk-EY5HOJFQ.js → chunk-SQTRWKO2.js} +5 -5
  53. package/Build/Workers/{chunk-AFGP5BXS.js → chunk-T43FXHNC.js} +7 -7
  54. package/Build/Workers/{chunk-IHFAFGR2.js → chunk-UEEGWJJP.js} +2 -2
  55. package/Build/Workers/{chunk-TMGLPEZW.js → chunk-WKXDCVBO.js} +4 -4
  56. package/Build/Workers/{chunk-VRAAQ3FS.js → chunk-Y5AJSEEN.js} +2 -2
  57. package/Build/Workers/{chunk-Y5MRBKQN.js → chunk-ZIW5FCIW.js} +18 -18
  58. package/Build/Workers/combineGeometry.js +24 -24
  59. package/Build/Workers/createBoxGeometry.js +18 -18
  60. package/Build/Workers/createBoxOutlineGeometry.js +16 -16
  61. package/Build/Workers/createCircleGeometry.js +26 -26
  62. package/Build/Workers/createCircleOutlineGeometry.js +19 -19
  63. package/Build/Workers/createCoplanarPolygonGeometry.js +33 -33
  64. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +31 -31
  65. package/Build/Workers/createCorridorGeometry.js +29 -29
  66. package/Build/Workers/createCorridorOutlineGeometry.js +28 -28
  67. package/Build/Workers/createCylinderGeometry.js +20 -20
  68. package/Build/Workers/createCylinderOutlineGeometry.js +18 -18
  69. package/Build/Workers/createEllipseGeometry.js +26 -26
  70. package/Build/Workers/createEllipseOutlineGeometry.js +19 -19
  71. package/Build/Workers/createEllipsoidGeometry.js +19 -19
  72. package/Build/Workers/createEllipsoidOutlineGeometry.js +18 -18
  73. package/Build/Workers/createFrustumGeometry.js +18 -18
  74. package/Build/Workers/createFrustumOutlineGeometry.js +18 -18
  75. package/Build/Workers/createGeometry.js +24 -24
  76. package/Build/Workers/createGroundPolylineGeometry.js +22 -22
  77. package/Build/Workers/createPlaneGeometry.js +16 -16
  78. package/Build/Workers/createPlaneOutlineGeometry.js +15 -15
  79. package/Build/Workers/createPolygonGeometry.js +32 -32
  80. package/Build/Workers/createPolygonOutlineGeometry.js +30 -30
  81. package/Build/Workers/createPolylineGeometry.js +25 -25
  82. package/Build/Workers/createPolylineVolumeGeometry.js +31 -31
  83. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +27 -27
  84. package/Build/Workers/createRectangleGeometry.js +27 -27
  85. package/Build/Workers/createRectangleOutlineGeometry.js +20 -20
  86. package/Build/Workers/createSimplePolylineGeometry.js +23 -23
  87. package/Build/Workers/createSphereGeometry.js +19 -19
  88. package/Build/Workers/createSphereOutlineGeometry.js +18 -18
  89. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  90. package/Build/Workers/createVectorTileClampedPolylines.js +14 -14
  91. package/Build/Workers/createVectorTileGeometries.js +24 -24
  92. package/Build/Workers/createVectorTilePoints.js +13 -13
  93. package/Build/Workers/createVectorTilePolygons.js +22 -22
  94. package/Build/Workers/createVectorTilePolylines.js +14 -14
  95. package/Build/Workers/createVerticesFromCesium3DTilesTerrain.js +25 -25
  96. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +22 -22
  97. package/Build/Workers/createVerticesFromHeightmap.js +22 -22
  98. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +20 -20
  99. package/Build/Workers/createWallGeometry.js +24 -24
  100. package/Build/Workers/createWallOutlineGeometry.js +23 -23
  101. package/Build/Workers/decodeDraco.js +10 -10
  102. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  103. package/Build/Workers/decodeI3S.js +10 -10
  104. package/Build/Workers/gaussianSplatSorter.js +4 -4
  105. package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
  106. package/Build/Workers/incrementallyBuildTerrainPicker.js +10 -10
  107. package/Build/Workers/transcodeKTX2.js +6 -6
  108. package/Build/Workers/transferTypedArrayTest.js +1 -1
  109. package/Build/Workers/upsampleQuantizedTerrainMesh.js +22 -22
  110. package/Build/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +25 -25
  111. package/Source/Core/AttributeCompression.js +53 -6
  112. package/Source/Core/Cartesian2.js +689 -684
  113. package/Source/Core/Cartesian3.js +1044 -1043
  114. package/Source/Core/Cartesian4.js +816 -813
  115. package/Source/Core/GoogleMaps.js +23 -2
  116. package/Source/Core/Ion.js +1 -1
  117. package/Source/Core/OpenCageGeocoderService.js +2 -3
  118. package/Source/Core/globalTypes.js +16 -0
  119. package/Source/Renderer/ShaderDestination.js +54 -13
  120. package/Source/Scene/ArcGisMapService.js +1 -1
  121. package/Source/Scene/Billboard.js +7 -4
  122. package/Source/Scene/BillboardCollection.js +64 -25
  123. package/Source/Scene/BufferLoader.js +65 -74
  124. package/Source/Scene/CubeMapPanorama.js +351 -0
  125. package/Source/Scene/DerivedCommand.js +8 -31
  126. package/Source/Scene/DracoLoader.js +79 -78
  127. package/Source/Scene/EquirectangularPanorama.js +264 -0
  128. package/Source/Scene/FrameState.js +7 -0
  129. package/Source/Scene/GaussianSplatPrimitive.js +906 -167
  130. package/Source/Scene/GlobeSurfaceShaderSet.js +36 -32
  131. package/Source/Scene/GltfBufferViewLoader.js +109 -118
  132. package/Source/Scene/GltfDracoLoader.js +167 -176
  133. package/Source/Scene/GltfImageLoader.js +91 -101
  134. package/Source/Scene/GltfIndexBufferLoader.js +228 -241
  135. package/Source/Scene/GltfJsonLoader.js +90 -99
  136. package/Source/Scene/GltfLoader.js +313 -324
  137. package/Source/Scene/GltfSpzLoader.js +127 -134
  138. package/Source/Scene/GltfStructuralMetadataLoader.js +181 -186
  139. package/Source/Scene/GltfTextureLoader.js +217 -231
  140. package/Source/Scene/GltfVertexBufferLoader.js +267 -276
  141. package/Source/Scene/GoogleStreetViewCubeMapPanoramaProvider.js +341 -0
  142. package/Source/Scene/Label.js +6 -4
  143. package/Source/Scene/LabelCollection.js +59 -1
  144. package/Source/Scene/MetadataClassProperty.js +212 -7
  145. package/Source/Scene/MetadataComponentType.js +162 -127
  146. package/Source/Scene/MetadataSchemaLoader.js +60 -67
  147. package/Source/Scene/MetadataTable.js +14 -0
  148. package/Source/Scene/MetadataTableProperty.js +14 -0
  149. package/Source/Scene/Model/B3dmLoader.js +216 -224
  150. package/Source/Scene/Model/CustomShader.js +6 -1
  151. package/Source/Scene/Model/CustomShaderPipelineStage.js +122 -7
  152. package/Source/Scene/Model/GeoJsonLoader.js +53 -61
  153. package/Source/Scene/Model/GeometryPipelineStage.js +17 -3
  154. package/Source/Scene/Model/I3dmLoader.js +232 -240
  155. package/Source/Scene/Model/MaterialPipelineStage.js +1 -1
  156. package/Source/Scene/Model/MetadataPipelineStage.js +438 -22
  157. package/Source/Scene/Model/PntsLoader.js +78 -89
  158. package/Source/Scene/Panorama.js +53 -0
  159. package/Source/Scene/PanoramaProvider.js +43 -0
  160. package/Source/Scene/PointPrimitiveCollection.js +14 -22
  161. package/Source/Scene/PropertyTable.js +43 -0
  162. package/Source/Scene/PropertyTexture.js +1 -1
  163. package/Source/Scene/PropertyTextureProperty.js +0 -97
  164. package/Source/Scene/ResourceLoader.js +84 -92
  165. package/Source/Scene/Scene.js +12 -0
  166. package/Source/Scene/SkyBox.js +29 -164
  167. package/Source/Scene/StructuralMetadata.js +18 -3
  168. package/Source/Scene/parseStructuralMetadata.js +244 -0
  169. package/Source/Shaders/BillboardCollectionFS.glsl +66 -40
  170. package/Source/Shaders/BillboardCollectionFS.js +67 -40
  171. package/Source/Shaders/BillboardCollectionVS.glsl +22 -31
  172. package/Source/Shaders/BillboardCollectionVS.js +22 -31
  173. package/Source/Shaders/Builtin/CzmBuiltins.js +4 -0
  174. package/Source/Shaders/Builtin/Functions/decodeRGB8.glsl +22 -0
  175. package/Source/Shaders/Builtin/Functions/decodeRGB8.js +24 -0
  176. package/Source/Shaders/Builtin/Functions/unpackTexture.glsl +35 -0
  177. package/Source/Shaders/Builtin/Functions/unpackTexture.js +37 -0
  178. package/Source/Shaders/CubeMapPanoramaVS.glsl +11 -0
  179. package/Source/Shaders/CubeMapPanoramaVS.js +13 -0
  180. package/Source/Shaders/Model/MetadataStageFS.glsl +2 -1
  181. package/Source/Shaders/Model/MetadataStageFS.js +2 -1
  182. package/Source/Shaders/Model/MetadataStageVS.glsl +2 -1
  183. package/Source/Shaders/Model/MetadataStageVS.js +2 -1
  184. package/Source/Shaders/Model/ModelFS.glsl +2 -2
  185. package/Source/Shaders/Model/ModelFS.js +2 -2
  186. package/Source/Shaders/Model/ModelVS.glsl +2 -2
  187. package/Source/Shaders/Model/ModelVS.js +2 -2
  188. package/Source/Shaders/PointPrimitiveCollectionVS.glsl +8 -39
  189. package/Source/Shaders/PointPrimitiveCollectionVS.js +8 -39
  190. package/index.d.ts +564 -189
  191. package/index.js +127 -119
  192. package/package.json +1 -1
  193. package/Build/Workers/chunk-LYBNPUEI.js +0 -1443
@@ -6,6 +6,18 @@ import PropertyTexture from "./PropertyTexture.js";
6
6
  import PropertyAttribute from "./PropertyAttribute.js";
7
7
  import StructuralMetadata from "./StructuralMetadata.js";
8
8
  import MetadataTable from "./MetadataTable.js";
9
+ import Sampler from "../Renderer/Sampler.js";
10
+ import Texture from "../Renderer/Texture.js";
11
+ import PixelFormat from "../Core/PixelFormat.js";
12
+ import PixelDatatype from "../Renderer/PixelDatatype.js";
13
+ import RuntimeError from "../Core/RuntimeError.js";
14
+ import oneTimeWarning from "../Core/oneTimeWarning.js";
15
+ import TextureWrap from "../Renderer/TextureWrap.js";
16
+ import TextureMagnificationFilter from "../Renderer/TextureMagnificationFilter.js";
17
+ import TextureMinificationFilter from "../Renderer/TextureMinificationFilter.js";
18
+ import ContextLimits from "../Renderer/ContextLimits.js";
19
+ import MetadataComponentType from "./MetadataComponentType.js";
20
+ import MetadataType from "./MetadataType.js";
9
21
 
10
22
  /**
11
23
  * Parse the <code>EXT_structural_metadata</code> glTF extension to create a
@@ -16,6 +28,7 @@ import MetadataTable from "./MetadataTable.js";
16
28
  * @param {MetadataSchema} options.schema The parsed schema.
17
29
  * @param {Object<string, Uint8Array>} [options.bufferViews] An object mapping bufferView IDs to Uint8Array objects.
18
30
  * @param {Object<string, Texture>} [options.textures] An object mapping texture IDs to {@link Texture} objects.
31
+ * @param {Context} [options.context] The current rendering context.
19
32
  * @return {StructuralMetadata} A structural metadata object
20
33
  * @private
21
34
  * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
@@ -38,12 +51,20 @@ function parseStructuralMetadata(options) {
38
51
  for (let i = 0; i < extension.propertyTables.length; i++) {
39
52
  const propertyTable = extension.propertyTables[i];
40
53
  const classDefinition = schema.classes[propertyTable.class];
54
+ const propertyTableTexture = createTextureForPropertyTable(
55
+ propertyTable,
56
+ options.bufferViews,
57
+ classDefinition,
58
+ options.context,
59
+ );
60
+
41
61
  const metadataTable = new MetadataTable({
42
62
  count: propertyTable.count,
43
63
  properties: propertyTable.properties,
44
64
  class: classDefinition,
45
65
  bufferViews: options.bufferViews,
46
66
  });
67
+
47
68
  propertyTables.push(
48
69
  new PropertyTable({
49
70
  id: i,
@@ -52,6 +73,7 @@ function parseStructuralMetadata(options) {
52
73
  metadataTable: metadataTable,
53
74
  extras: propertyTable.extras,
54
75
  extensions: propertyTable.extensions,
76
+ texture: propertyTableTexture,
55
77
  }),
56
78
  );
57
79
  }
@@ -99,4 +121,226 @@ function parseStructuralMetadata(options) {
99
121
  });
100
122
  }
101
123
 
124
+ // Always use four channels for property table textures.
125
+ const NUM_CHANNELS = 4;
126
+
127
+ /**
128
+ * Creates a texture from a set of property table properties (those which are GPU compatible).
129
+ * Each row of the texture is a property, with each column corresponding to a given feature.
130
+ *
131
+ * @param {PropertyTable} propertyTable The property table.
132
+ * @param {Object<string, Uint8Array>} bufferViews An object mapping bufferView IDs to Uint8Array objects for the given property table.
133
+ * @param {MetadataClass} classDefinition Class defined in the schema
134
+ * @param {Context} context The rendering context.
135
+ * @returns {Texture|undefined} The created texture, or <code>undefined</code> if no properties are GPU compatible.
136
+ *
137
+ * @private
138
+ */
139
+ function createTextureForPropertyTable(
140
+ propertyTable,
141
+ bufferViews,
142
+ classDefinition,
143
+ context,
144
+ ) {
145
+ const properties = propertyTable.properties;
146
+ if (!defined(properties)) {
147
+ return undefined;
148
+ }
149
+
150
+ const numFeatures = propertyTable.count;
151
+
152
+ let gpuCompatiblePropertyBufferViews;
153
+ try {
154
+ gpuCompatiblePropertyBufferViews = collectGpuCompatiblePropertyBufferViews(
155
+ properties,
156
+ bufferViews,
157
+ classDefinition,
158
+ numFeatures,
159
+ );
160
+ } catch (error) {
161
+ console.warn(
162
+ `Failed to create texture for property table "${propertyTable.name}": ${error.message}`,
163
+ );
164
+ return undefined;
165
+ }
166
+
167
+ const numGpuCompatibleProperties = gpuCompatiblePropertyBufferViews.length;
168
+
169
+ if (numGpuCompatibleProperties === 0) {
170
+ return undefined;
171
+ }
172
+
173
+ // In the future, we could use multiple textures if we would exceed the maximum texture size.
174
+ if (
175
+ numFeatures > ContextLimits.maximumTextureSize ||
176
+ numGpuCompatibleProperties > ContextLimits.maximumTextureSize
177
+ ) {
178
+ oneTimeWarning(
179
+ "PropertyTableTextureExceedsMaximumSize",
180
+ `Cannot create a texture for the property table "${propertyTable.name}" because it exceeds the maximum texture size of ${ContextLimits.maximumTextureSize}.`,
181
+ );
182
+ return undefined;
183
+ }
184
+
185
+ const packedBufferView = packPropertyTablePropertiesIntoRGBA8(
186
+ gpuCompatiblePropertyBufferViews,
187
+ numFeatures,
188
+ );
189
+
190
+ // Create a sampler fit for sampling raw data without mipmapping / filtering etc.
191
+ const sampler = new Sampler({
192
+ wrapS: TextureWrap.CLAMP_TO_EDGE,
193
+ wrapT: TextureWrap.CLAMP_TO_EDGE,
194
+ minificationFilter: TextureMinificationFilter.NEAREST,
195
+ magnificationFilter: TextureMagnificationFilter.NEAREST,
196
+ });
197
+
198
+ return Texture.create({
199
+ context: context,
200
+ pixelFormat: PixelFormat.RGBA,
201
+ pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
202
+ sampler: sampler,
203
+ flipY: false,
204
+ source: {
205
+ width: numFeatures,
206
+ height: numGpuCompatibleProperties,
207
+ arrayBufferView: packedBufferView,
208
+ },
209
+ });
210
+ }
211
+
212
+ function collectGpuCompatiblePropertyBufferViews(
213
+ properties,
214
+ bufferViews,
215
+ classDefinition,
216
+ numFeatures,
217
+ ) {
218
+ const bufferViewsForThisTable = [];
219
+ const classProperties = classDefinition.properties;
220
+
221
+ // It's possible for a primitive in a tileset to only use a subset of the class properties defined in the schema.
222
+ // For instance, the Design Tiler merges classes together by default, and omits properties in primitives that aren't used.
223
+ // To make the default values available to the GPU, and to avoid compiling different versions of the shader for each primitive,
224
+ // we iterate over _all_ class properties here - not just the properties in the property table.
225
+ for (const [propertyId, classProperty] of Object.entries(classProperties)) {
226
+ // Certain properties like strings, dynamic-sized arrays, and 64-bit types cannot be represented natively on the GPU.
227
+ if (!classProperty.isGpuCompatible(NUM_CHANNELS)) {
228
+ continue;
229
+ }
230
+
231
+ const property = properties[propertyId];
232
+ const bufferView = defined(property)
233
+ ? bufferViews[property.values]
234
+ : createNoDataBufferView(classProperty, numFeatures);
235
+
236
+ const bufferViewLength = bufferView.length;
237
+ const bytesPerElement = classProperty.bytesPerElement();
238
+ const numBufferElements = bufferViewLength / bytesPerElement;
239
+ if (numBufferElements !== numFeatures) {
240
+ throw new RuntimeError(
241
+ `Property with ID: "${propertyId}" has (${numBufferElements}), which does not match number of features in the property table: (${numFeatures}).`,
242
+ );
243
+ }
244
+
245
+ bufferViewsForThisTable.push({
246
+ view: bufferView,
247
+ bytesPerElement: bytesPerElement,
248
+ });
249
+ }
250
+
251
+ return bufferViewsForThisTable;
252
+ }
253
+
254
+ /**
255
+ * When a property is part of a tileset class schema but not used in a property table,
256
+ * we create a buffer view filled with the property's noData value.
257
+ *
258
+ * @param {MetadataClassProperty} classProperty The class property definition.
259
+ * @param {number} numFeatures The number of features in the property table.
260
+ *
261
+ * @returns {Uint8Array} A buffer view filled with the property's noData value.
262
+ *
263
+ * @private
264
+ */
265
+ function createNoDataBufferView(classProperty, numFeatures) {
266
+ // noData can be a number, an array of numbers (e.g. for vecN types), or a nested array of numbers (e.g. for arrays of vecN types).
267
+ let noData = classProperty.noData;
268
+ const metadataComponentCount = MetadataType.getComponentCount(
269
+ classProperty.type,
270
+ );
271
+ const metadataArrayLength = classProperty.isArray
272
+ ? classProperty.arrayLength
273
+ : 1;
274
+
275
+ // Special case: noData enum values are specified as strings, so we need to convert them to numbers here.
276
+ if (classProperty.type === MetadataType.ENUM) {
277
+ const enumDefinition = classProperty.enumType;
278
+ noData = enumDefinition.valuesByName[noData];
279
+ }
280
+
281
+ // Wrap noData in an array (up to two times) so we can treat it uniformly in the loop below.
282
+ if (metadataComponentCount === 1) {
283
+ noData = [noData];
284
+ }
285
+
286
+ if (metadataArrayLength === 1) {
287
+ noData = [noData];
288
+ }
289
+
290
+ const bytesPerElement = classProperty.bytesPerElement();
291
+ const buffer = new ArrayBuffer(bytesPerElement * numFeatures);
292
+ const view = new DataView(buffer);
293
+ const setter = MetadataComponentType.getDataViewSetter(
294
+ view,
295
+ classProperty.componentType,
296
+ );
297
+
298
+ for (let i = 0; i < numFeatures; i++) {
299
+ for (let j = 0; j < metadataArrayLength; j++) {
300
+ for (let k = 0; k < metadataComponentCount; k++) {
301
+ setter(bytesPerElement * i + j + k, noData[j][k]);
302
+ }
303
+ }
304
+ }
305
+
306
+ return new Uint8Array(buffer);
307
+ }
308
+
309
+ // Make one big buffer view to load into the texture
310
+ // Since each texel is always 4 bytes (RGBA8 format), elements less than 4 bytes need to be padded (respecting little-endian order).
311
+ function packPropertyTablePropertiesIntoRGBA8(
312
+ bufferViewsForThisTable,
313
+ numFeatures,
314
+ ) {
315
+ const numGpuCompatibleProperties = bufferViewsForThisTable.length;
316
+ const packedBufferView = new Uint8Array(
317
+ numGpuCompatibleProperties * numFeatures * NUM_CHANNELS,
318
+ );
319
+
320
+ for (let i = 0, offset = 0; i < bufferViewsForThisTable.length; i++) {
321
+ const bufferView = bufferViewsForThisTable[i].view;
322
+ const bytesPerElement = bufferViewsForThisTable[i].bytesPerElement;
323
+ const numElements = bufferView.length / bytesPerElement;
324
+
325
+ for (let j = 0; j < numElements; j++) {
326
+ const sourceOffset = j * bytesPerElement;
327
+ const destOffset = offset + j * NUM_CHANNELS;
328
+
329
+ packedBufferView.set(
330
+ bufferView.subarray(sourceOffset, sourceOffset + bytesPerElement),
331
+ destOffset,
332
+ );
333
+
334
+ // Pad remaining channels with 0
335
+ for (let k = bytesPerElement; k < NUM_CHANNELS; k++) {
336
+ packedBufferView[destOffset + k] = 0;
337
+ }
338
+ }
339
+
340
+ offset += numElements * NUM_CHANNELS;
341
+ }
342
+
343
+ return packedBufferView;
344
+ }
345
+
102
346
  export default parseStructuralMetadata;
@@ -9,7 +9,7 @@ uniform vec4 u_highlightColor;
9
9
  in vec2 v_textureCoordinates;
10
10
  in vec4 v_pickColor;
11
11
  in vec4 v_color;
12
- in float v_splitDirection;
12
+ flat in vec2 v_splitDirectionAndEllipsoidDepthEC;
13
13
 
14
14
  #ifdef SDF
15
15
  in vec4 v_outlineColor;
@@ -126,28 +126,39 @@ void doThreePointDepthTest(float eyeDepth, bool applyTranslate) {
126
126
  float globeDepth3 = getGlobeDepth(adjustedST, vec2(1.0, 1.0), applyTranslate, dimensions, imageSize); // top right corner
127
127
  if (globeDepth3 == 0.0 || globeDepth3 < epsilonEyeDepth) return;
128
128
 
129
- // All three key points are occluded, discard the fragment (and by extension the entire billboard)
129
+ // All three key points are occluded, discard the fragment (and by extension the entire billboard)
130
130
  discard;
131
131
  }
132
132
  #endif
133
133
 
134
- // Extra manual depth testing is done to allow more control over how a billboard is occluded
135
- // by the globe when near and far from the camera.
136
- void doDepthTest(float globeDepth) {
134
+ bool getDepthTestEnabled() {
137
135
  float temp = v_compressed.y;
138
136
  temp = temp * SHIFT_RIGHT1;
139
137
  float temp2 = (temp - floor(temp)) * SHIFT_LEFT1;
140
- bool enableDepthCheck = temp2 != 0.0;
141
- if (!enableDepthCheck) return;
138
+ return temp2 != 0.0;
139
+ }
140
+
141
+ float getRelativeEyeDepth(float eyeDepth, float distanceToEllipsoid, float epsilon) {
142
+ float depthDifferential = eyeDepth - distanceToEllipsoid;
143
+ float depthRatio = abs(depthDifferential / distanceToEllipsoid);
144
+ if (depthRatio < epsilon) {
145
+ // The approximations are imprecise, so use an epsilon check for small value differences and assume a value of 0.0
146
+ return 0.0;
147
+ }
148
+
149
+ return depthDifferential;
150
+ }
142
151
 
143
- float eyeDepth = v_compressed.x;
152
+ // Extra manual depth testing is done to allow more control over how a billboard is occluded
153
+ // by the globe when near and far from the camera.
154
+ void doDepthTest(float eyeDepth, float globeDepth) {
144
155
 
145
156
  #ifdef FS_THREE_POINT_DEPTH_CHECK
146
157
  // If the billboard is clamped to the ground and within a given distance, we do a 3-point depth test. This test is performed in the vertex shader, unless
147
158
  // vertex texture sampling is not supported, in which case we do it here.
148
159
  bool applyTranslate = floor(temp) != 0.0;
149
160
  doThreePointDepthTest(eyeDepth, applyTranslate);
150
-
161
+
151
162
  #elif defined(VS_THREE_POINT_DEPTH_CHECK)
152
163
  // Since discarding vertices is not possible, the vertex shader sets eyeDepth to 0 to indicate the depth test failed. Apply the discard here.
153
164
  if (eyeDepth > -u_threePointDepthTestDistance) {
@@ -157,27 +168,58 @@ void doDepthTest(float globeDepth) {
157
168
  return;
158
169
  }
159
170
  #endif
171
+ bool useGlobeDepth = eyeDepth > -u_coarseDepthTestDistance;
172
+ if (useGlobeDepth && globeDepth == 0.0) {
173
+ // Pixel is not on the globe, so there is no distance to compare against. Pass.
174
+ return;
175
+ }
160
176
 
161
- // If we're far away, we just compare against a flat, camera-facing depth-plane at the ellipsoid's center.
162
- // If we're close, we compare against the globe depth texture (which includes depth from the 3D tile pass).
163
-
164
- if (globeDepth == 0.0) return; // Not on globe
165
- float distanceToEllipsoidCenter = -length(czm_viewerPositionWC); // depth is negative by convention
166
- float testDistance = (eyeDepth > -u_coarseDepthTestDistance) ? globeDepth : distanceToEllipsoidCenter;
167
- if (eyeDepth < testDistance) {
177
+ // If the camera is close, compare against the globe depth texture that includes depth from the 3D tile pass.
178
+ if (useGlobeDepth && getRelativeEyeDepth(eyeDepth, globeDepth, czm_epsilon1) < 0.0) {
168
179
  discard;
169
180
  }
170
181
  }
171
182
 
183
+ #ifdef LOG_DEPTH
184
+ void writeDepth(float eyeDepth, float globeDepth, float distanceToEllipsoid) {
185
+ // If we've made it here, the manual depth test above determined that this fragment should be visible.
186
+ // But the automatic depth test must still run in order to write the result to the depth buffer, and its results may
187
+ // disagree with our manual depth test's results. To prefer our manual results when in front of the globe, apply an offset towards the camera.
188
+
189
+ float depthArg = v_depthFromNearPlusOne;
190
+
191
+ if (globeDepth != 0.0 && getRelativeEyeDepth(eyeDepth, distanceToEllipsoid, czm_epsilon3) > 0.0) {
192
+ float globeDepthFromNearPlusOne = (-globeDepth - czm_currentFrustum.x) + 1.0;
193
+ float nudge = max(globeDepthFromNearPlusOne * 5e-6, czm_epsilon7);
194
+ float globeOnTop = max(1.0, globeDepthFromNearPlusOne - nudge);
195
+ depthArg = min(depthArg, globeOnTop);
196
+ }
197
+
198
+ czm_writeLogDepth(depthArg);
199
+ }
200
+ #endif
201
+
172
202
  void main()
173
203
  {
174
- if (v_splitDirection < 0.0 && gl_FragCoord.x > czm_splitPosition) discard;
175
- if (v_splitDirection > 0.0 && gl_FragCoord.x < czm_splitPosition) discard;
176
-
177
- vec2 fragSt = gl_FragCoord.xy / czm_viewport.zw;
178
- float globeDepth = getGlobeDepthAtCoords(fragSt);
179
- doDepthTest(globeDepth);
180
-
204
+ if (v_splitDirectionAndEllipsoidDepthEC.x < 0.0 && gl_FragCoord.x > czm_splitPosition) {
205
+ discard;
206
+ }
207
+ if (v_splitDirectionAndEllipsoidDepthEC.x > 0.0 && gl_FragCoord.x < czm_splitPosition) {
208
+ discard;
209
+ }
210
+
211
+ if (getDepthTestEnabled()) {
212
+ vec2 fragSt = gl_FragCoord.xy / czm_viewport.zw;
213
+ float eyeDepth = v_compressed.x;
214
+ float globeDepth = getGlobeDepthAtCoords(fragSt);
215
+ float distanceToEllipsoid = -v_splitDirectionAndEllipsoidDepthEC.y;
216
+ doDepthTest(eyeDepth, globeDepth);
217
+
218
+ #ifdef LOG_DEPTH
219
+ writeDepth(eyeDepth, globeDepth, distanceToEllipsoid);
220
+ #endif
221
+ }
222
+
181
223
  vec4 color = texture(u_atlas, v_textureCoordinates);
182
224
 
183
225
  #ifdef SDF
@@ -242,20 +284,4 @@ void main()
242
284
  color *= u_highlightColor;
243
285
  #endif
244
286
  out_FragColor = color;
245
-
246
- #ifdef LOG_DEPTH
247
- // If we've made it here, we passed our manual depth test, above. But the automatic depth test will
248
- // still run, and some fragments of the billboard may clip against the globe. To prevent that,
249
- // ensure the depth value we write out is in front of the globe depth.
250
- float depthArg = v_depthFromNearPlusOne;
251
-
252
- if (globeDepth != 0.0) { // On the globe
253
- float globeDepthFromNearPlusOne = (-globeDepth - czm_currentFrustum.x) + 1.0;
254
- float nudge = max(globeDepthFromNearPlusOne * 5e-6, czm_epsilon7);
255
- float globeOnTop = max(1.0, globeDepthFromNearPlusOne - nudge);
256
- depthArg = min(depthArg, globeOnTop);
257
- }
258
-
259
- czm_writeLogDepth(depthArg);
260
- #endif
261
- }
287
+ }
@@ -10,7 +10,7 @@ uniform vec4 u_highlightColor;\n\
10
10
  in vec2 v_textureCoordinates;\n\
11
11
  in vec4 v_pickColor;\n\
12
12
  in vec4 v_color;\n\
13
- in float v_splitDirection;\n\
13
+ flat in vec2 v_splitDirectionAndEllipsoidDepthEC;\n\
14
14
  \n\
15
15
  #ifdef SDF\n\
16
16
  in vec4 v_outlineColor;\n\
@@ -127,28 +127,39 @@ void doThreePointDepthTest(float eyeDepth, bool applyTranslate) {\n\
127
127
  float globeDepth3 = getGlobeDepth(adjustedST, vec2(1.0, 1.0), applyTranslate, dimensions, imageSize); // top right corner\n\
128
128
  if (globeDepth3 == 0.0 || globeDepth3 < epsilonEyeDepth) return;\n\
129
129
  \n\
130
- // All three key points are occluded, discard the fragment (and by extension the entire billboard) \n\
130
+ // All three key points are occluded, discard the fragment (and by extension the entire billboard)\n\
131
131
  discard;\n\
132
132
  }\n\
133
133
  #endif\n\
134
134
  \n\
135
- // Extra manual depth testing is done to allow more control over how a billboard is occluded \n\
136
- // by the globe when near and far from the camera.\n\
137
- void doDepthTest(float globeDepth) {\n\
135
+ bool getDepthTestEnabled() {\n\
138
136
  float temp = v_compressed.y;\n\
139
137
  temp = temp * SHIFT_RIGHT1;\n\
140
138
  float temp2 = (temp - floor(temp)) * SHIFT_LEFT1;\n\
141
- bool enableDepthCheck = temp2 != 0.0;\n\
142
- if (!enableDepthCheck) return;\n\
139
+ return temp2 != 0.0;\n\
140
+ }\n\
141
+ \n\
142
+ float getRelativeEyeDepth(float eyeDepth, float distanceToEllipsoid, float epsilon) {\n\
143
+ float depthDifferential = eyeDepth - distanceToEllipsoid;\n\
144
+ float depthRatio = abs(depthDifferential / distanceToEllipsoid);\n\
145
+ if (depthRatio < epsilon) {\n\
146
+ // The approximations are imprecise, so use an epsilon check for small value differences and assume a value of 0.0\n\
147
+ return 0.0;\n\
148
+ }\n\
149
+ \n\
150
+ return depthDifferential;\n\
151
+ }\n\
143
152
  \n\
144
- float eyeDepth = v_compressed.x;\n\
153
+ // Extra manual depth testing is done to allow more control over how a billboard is occluded\n\
154
+ // by the globe when near and far from the camera.\n\
155
+ void doDepthTest(float eyeDepth, float globeDepth) {\n\
145
156
  \n\
146
157
  #ifdef FS_THREE_POINT_DEPTH_CHECK\n\
147
158
  // If the billboard is clamped to the ground and within a given distance, we do a 3-point depth test. This test is performed in the vertex shader, unless\n\
148
159
  // vertex texture sampling is not supported, in which case we do it here.\n\
149
160
  bool applyTranslate = floor(temp) != 0.0;\n\
150
161
  doThreePointDepthTest(eyeDepth, applyTranslate);\n\
151
- \n\
162
+ \n\
152
163
  #elif defined(VS_THREE_POINT_DEPTH_CHECK)\n\
153
164
  // Since discarding vertices is not possible, the vertex shader sets eyeDepth to 0 to indicate the depth test failed. Apply the discard here.\n\
154
165
  if (eyeDepth > -u_threePointDepthTestDistance) {\n\
@@ -158,27 +169,58 @@ void doDepthTest(float globeDepth) {\n\
158
169
  return;\n\
159
170
  }\n\
160
171
  #endif\n\
172
+ bool useGlobeDepth = eyeDepth > -u_coarseDepthTestDistance;\n\
173
+ if (useGlobeDepth && globeDepth == 0.0) {\n\
174
+ // Pixel is not on the globe, so there is no distance to compare against. Pass.\n\
175
+ return;\n\
176
+ }\n\
161
177
  \n\
162
- // If we're far away, we just compare against a flat, camera-facing depth-plane at the ellipsoid's center.\n\
163
- // If we're close, we compare against the globe depth texture (which includes depth from the 3D tile pass).\n\
164
- \n\
165
- if (globeDepth == 0.0) return; // Not on globe \n\
166
- float distanceToEllipsoidCenter = -length(czm_viewerPositionWC); // depth is negative by convention\n\
167
- float testDistance = (eyeDepth > -u_coarseDepthTestDistance) ? globeDepth : distanceToEllipsoidCenter;\n\
168
- if (eyeDepth < testDistance) {\n\
178
+ // If the camera is close, compare against the globe depth texture that includes depth from the 3D tile pass.\n\
179
+ if (useGlobeDepth && getRelativeEyeDepth(eyeDepth, globeDepth, czm_epsilon1) < 0.0) {\n\
169
180
  discard;\n\
170
181
  }\n\
171
182
  }\n\
172
183
  \n\
184
+ #ifdef LOG_DEPTH\n\
185
+ void writeDepth(float eyeDepth, float globeDepth, float distanceToEllipsoid) {\n\
186
+ // If we've made it here, the manual depth test above determined that this fragment should be visible.\n\
187
+ // But the automatic depth test must still run in order to write the result to the depth buffer, and its results may\n\
188
+ // disagree with our manual depth test's results. To prefer our manual results when in front of the globe, apply an offset towards the camera.\n\
189
+ \n\
190
+ float depthArg = v_depthFromNearPlusOne;\n\
191
+ \n\
192
+ if (globeDepth != 0.0 && getRelativeEyeDepth(eyeDepth, distanceToEllipsoid, czm_epsilon3) > 0.0) { \n\
193
+ float globeDepthFromNearPlusOne = (-globeDepth - czm_currentFrustum.x) + 1.0;\n\
194
+ float nudge = max(globeDepthFromNearPlusOne * 5e-6, czm_epsilon7);\n\
195
+ float globeOnTop = max(1.0, globeDepthFromNearPlusOne - nudge);\n\
196
+ depthArg = min(depthArg, globeOnTop);\n\
197
+ }\n\
198
+ \n\
199
+ czm_writeLogDepth(depthArg);\n\
200
+ }\n\
201
+ #endif\n\
202
+ \n\
173
203
  void main()\n\
174
204
  {\n\
175
- if (v_splitDirection < 0.0 && gl_FragCoord.x > czm_splitPosition) discard;\n\
176
- if (v_splitDirection > 0.0 && gl_FragCoord.x < czm_splitPosition) discard;\n\
177
- \n\
178
- vec2 fragSt = gl_FragCoord.xy / czm_viewport.zw;\n\
179
- float globeDepth = getGlobeDepthAtCoords(fragSt);\n\
180
- doDepthTest(globeDepth);\n\
181
- \n\
205
+ if (v_splitDirectionAndEllipsoidDepthEC.x < 0.0 && gl_FragCoord.x > czm_splitPosition) {\n\
206
+ discard;\n\
207
+ }\n\
208
+ if (v_splitDirectionAndEllipsoidDepthEC.x > 0.0 && gl_FragCoord.x < czm_splitPosition) {\n\
209
+ discard;\n\
210
+ }\n\
211
+ \n\
212
+ if (getDepthTestEnabled()) {\n\
213
+ vec2 fragSt = gl_FragCoord.xy / czm_viewport.zw;\n\
214
+ float eyeDepth = v_compressed.x;\n\
215
+ float globeDepth = getGlobeDepthAtCoords(fragSt);\n\
216
+ float distanceToEllipsoid = -v_splitDirectionAndEllipsoidDepthEC.y;\n\
217
+ doDepthTest(eyeDepth, globeDepth);\n\
218
+ \n\
219
+ #ifdef LOG_DEPTH\n\
220
+ writeDepth(eyeDepth, globeDepth, distanceToEllipsoid);\n\
221
+ #endif\n\
222
+ }\n\
223
+ \n\
182
224
  vec4 color = texture(u_atlas, v_textureCoordinates);\n\
183
225
  \n\
184
226
  #ifdef SDF\n\
@@ -243,20 +285,5 @@ void main()\n\
243
285
  color *= u_highlightColor;\n\
244
286
  #endif\n\
245
287
  out_FragColor = color;\n\
246
- \n\
247
- #ifdef LOG_DEPTH\n\
248
- // If we've made it here, we passed our manual depth test, above. But the automatic depth test will\n\
249
- // still run, and some fragments of the billboard may clip against the globe. To prevent that,\n\
250
- // ensure the depth value we write out is in front of the globe depth.\n\
251
- float depthArg = v_depthFromNearPlusOne;\n\
252
- \n\
253
- if (globeDepth != 0.0) { // On the globe\n\
254
- float globeDepthFromNearPlusOne = (-globeDepth - czm_currentFrustum.x) + 1.0;\n\
255
- float nudge = max(globeDepthFromNearPlusOne * 5e-6, czm_epsilon7);\n\
256
- float globeOnTop = max(1.0, globeDepthFromNearPlusOne - nudge);\n\
257
- depthArg = min(depthArg, globeOnTop);\n\
258
- }\n\
259
- \n\
260
- czm_writeLogDepth(depthArg);\n\
261
- #endif\n\
262
- }";
288
+ }\n\
289
+ ";