88 Cesium3DTileStyle ,
99 Cesium3DTilesVoxelProvider ,
1010 CustomShader ,
11+ CustomShaderTranslucencyMode ,
1112 Ellipsoid ,
1213 GeoJsonDataSource ,
1314 ImageBasedLighting ,
@@ -17,6 +18,9 @@ import {
1718 Matrix3 ,
1819 Matrix4 ,
1920 Rectangle ,
21+ Resource ,
22+ Scene ,
23+ UniformType ,
2024 Viewer ,
2125 VoxelPrimitive ,
2226} from 'cesium' ;
@@ -131,7 +135,7 @@ export async function create3DTilesetFromConfig(
131135 config : LayerConfig ,
132136 tileLoadCallback ,
133137) {
134- let resource : string | IonResource | AmazonS3Resource ;
138+ let resource : string | AmazonS3Resource | IonResource | Resource ;
135139 if ( config . aws_s3_bucket && config . aws_s3_key ) {
136140 resource = new AmazonS3Resource ( {
137141 sessionService,
@@ -140,10 +144,27 @@ export async function create3DTilesetFromConfig(
140144 } ) ;
141145 } else if ( config . url ) {
142146 resource = config . url ;
143- } else {
147+ } else if ( config . assetId ) {
144148 resource = await IonResource . fromAssetId ( config . assetId ! , {
145149 accessToken : config . ionToken ,
146150 } ) ;
151+ } else if ( config . ogc ) {
152+ const url =
153+ config . ogc . styleId === undefined
154+ ? `https://ogc-api.gst-viewer.swissgeol.ch/collections/${ config . ogc . id } /download_format/tiles3d`
155+ : `https://ogc-api.gst-viewer.swissgeol.ch/collections/${ config . ogc . id } /styles/${ config . ogc . styleId } /download_format/tiles3d` ;
156+ resource = new Resource ( {
157+ url,
158+ headers : {
159+ // This is the Authorization required to access the Seismic layers.
160+ // This is a read-only auth level and safe to expose.
161+ // The reason these credentials exist is related to how GST categorizes and exposes its data.
162+ // They are not intended for security and can thus be public.
163+ Authorization : 'Basic T0dDLVNlaXNtaWNzOk9HQy1TZWlzbWljc18yMDI1Kg==' ,
164+ } ,
165+ } ) ;
166+ } else {
167+ throw new Error ( `layer is missing a usable source: ${ config . layer } ` ) ;
147168 }
148169
149170 const tileset : PickableCesium3DTileset = await Cesium3DTileset . fromUrl (
@@ -167,28 +188,53 @@ export async function create3DTilesetFromConfig(
167188 }
168189
169190 tileset . pickable = config . pickable ?? false ;
170- viewer . scene . primitives . add ( tileset ) ;
191+
192+ const updateShader = ( opacity : number ) => {
193+ const requiredTranslucency =
194+ opacity === 1
195+ ? CustomShaderTranslucencyMode . OPAQUE
196+ : CustomShaderTranslucencyMode . TRANSLUCENT ;
197+
198+ const needsNewShader =
199+ tileset . customShader === undefined ||
200+ tileset . customShader . translucencyMode !== requiredTranslucency ;
201+
202+ if ( needsNewShader ) {
203+ tileset . customShader = new CustomShader ( {
204+ translucencyMode : requiredTranslucency ,
205+ fragmentShaderText : `
206+ void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
207+ material.specular = vec3(0.0); // no view-dependent spec
208+ material.occlusion = 1.0; // full diffuse
209+ material.alpha = u_alpha;
210+ }
211+ ` ,
212+ uniforms : {
213+ u_alpha : {
214+ type : UniformType . FLOAT ,
215+ value : opacity ,
216+ } ,
217+ } ,
218+ } ) ;
219+ } else {
220+ tileset . customShader ! . setUniform ( 'u_alpha' , opacity ) ;
221+ }
222+ } ;
223+ updateShader ( config . opacity ?? 1 ) ;
224+
225+ tileset . imageBasedLighting = new ImageBasedLighting ( ) ;
226+ tileset . imageBasedLighting . imageBasedLightingFactor = new Cartesian2 ( 1 , 0 ) ;
171227
172228 config . setVisibility = ( visible ) => {
173229 tileset . show = ! ! visible ;
174230 } ;
175231
176232 if ( ! config . opacityDisabled ) {
177233 config . setOpacity = ( opacity ) => {
178- const style = config . style ;
179- if ( style && ( style . color || style . labelColor ) ) {
180- const { propertyName, colorType, colorValue } = styleColorParser ( style ) ;
181- const color = `${ colorType } (${ colorValue } , ${ opacity } )` ;
182- tileset . style = new Cesium3DTileStyle ( {
183- ...style ,
184- [ propertyName ] : color ,
185- } ) ;
186- } else {
187- const color = `vec4(1, 1, 1, ${ opacity } )` ;
188- tileset . style = new Cesium3DTileStyle ( { ...style , color } ) ;
189- }
234+ updateShader ( opacity ) ;
235+ viewer . scene . requestRender ( ) ;
190236 } ;
191- config . setOpacity ( config . opacity ? config . opacity : 1 ) ;
237+ config . setOpacity ( config . opacity ?? 1 ) ;
192238 }
193239
194240 if ( tileLoadCallback ) {
@@ -197,7 +243,7 @@ export async function create3DTilesetFromConfig(
197243 ) ;
198244 }
199245
200- if ( config . propsOrder ) {
246+ if ( config . propsOrder && tileset . properties ) {
201247 tileset . properties . propsOrder = config . propsOrder ;
202248 }
203249 if ( config . heightOffset ) {
@@ -221,21 +267,29 @@ export async function create3DTilesetFromConfig(
221267
222268 tileset . colorBlendMode = Cesium3DTileColorBlendMode . REPLACE ;
223269
224- tileset . customShader = new CustomShader ( {
225- fragmentShaderText : `
226- void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
227- material.specular = vec3(0.0); // no view-dependent spec
228- material.occlusion = 1.0; // full diffuse
229- }
230- ` ,
231- } ) ;
270+ // Disable `pickPosition` until the tileset is loaded.
271+ // Without this, hovering over the viewer will cause a render error due to `layout-cursor-info` attempting to pick
272+ // the incomplete tileset.
273+ pickSuppressionCount += 1 ;
274+ viewer . scene . pickPosition = pickSuppression ;
232275
233- tileset . imageBasedLighting = new ImageBasedLighting ( ) ;
234- tileset . imageBasedLighting . imageBasedLightingFactor = new Cartesian2 ( 1 , 0 ) ;
276+ tileset . allTilesLoaded . addEventListener ( ( ) => {
277+ pickSuppressionCount -= 1 ;
278+ if ( pickSuppressionCount === 0 ) {
279+ viewer . scene . pickPosition = originalPick ;
280+ }
281+ } ) ;
235282
283+ viewer . scene . primitives . add ( tileset ) ;
236284 return tileset ;
237285}
238286
287+ const originalPick = Scene . prototype . pickPosition ;
288+ let pickSuppressionCount = 0 ;
289+ const pickSuppression : typeof originalPick = ( ) => {
290+ return null as unknown as Cartesian3 ;
291+ } ;
292+
239293export async function createSwisstopoWMTSImageryLayer (
240294 viewer : Viewer ,
241295 config : LayerConfig ,
@@ -297,24 +351,6 @@ export function createCesiumObject(
297351 return factories [ config . type ! ] ( viewer , config , tileLoadCallback ) ;
298352}
299353
300- function styleColorParser ( style : any ) {
301- const propertyName = style . color ? 'color' : 'labelColor' ;
302- let colorType = style [ propertyName ] . slice (
303- 0 ,
304- style [ propertyName ] . indexOf ( '(' ) ,
305- ) ;
306- const lastIndex =
307- colorType === 'rgba'
308- ? style [ propertyName ] . lastIndexOf ( ',' )
309- : style [ propertyName ] . indexOf ( ')' ) ;
310- const colorValue = style [ propertyName ] . slice (
311- style [ propertyName ] . indexOf ( '(' ) + 1 ,
312- lastIndex ,
313- ) ;
314- colorType = colorType === 'rgb' ? 'rgba' : colorType ;
315- return { propertyName, colorType, colorValue } ;
316- }
317-
318354export function getBoxFromRectangle (
319355 rectangle : Rectangle ,
320356 height : number ,
0 commit comments