@@ -55,6 +55,7 @@ type SortedMesh = {
5555 worldViewProjection : mat4 ;
5656 nodeModelMatrix : mat4 ;
5757 isLightMesh : boolean ;
58+ modelOpacity : number ;
5859 materialOverride ?: MaterialOverride ;
5960 modelColor ?: [ number , number , number , number ] ;
6061} ;
@@ -164,7 +165,7 @@ function setupMeshDraw(definesValues: Array<string>, dynamicBuffers: Array<Verte
164165}
165166
166167function drawMesh ( sortedMesh : SortedMesh , painter : Painter , layer : ModelStyleLayer , modelParameters : ModelParameters , stencilMode : StencilMode , colorMode : ColorMode ) {
167- const opacity = layer . paint . get ( 'model-opacity' ) . constantOr ( 1.0 ) ;
168+ const opacity = sortedMesh . modelOpacity ;
168169
169170 assert ( opacity > 0 ) ;
170171 const context = painter . context ;
@@ -295,7 +296,7 @@ export function prepare(layer: ModelStyleLayer, sourceCache: SourceCache, painte
295296 }
296297}
297298
298- function prepareMeshes ( painter : Painter , node : ModelNode , modelMatrix : mat4 , projectionMatrix : mat4 , modelIndex : number , transparentMeshes : Array < SortedMesh > , opaqueMeshes : Array < SortedMesh > , materialOverrides : ModelMaterialOverrides , modelColorMix ?: [ number , number , number , number ] ) {
299+ function prepareMeshes ( painter : Painter , node : ModelNode , modelMatrix : mat4 , projectionMatrix : mat4 , modelIndex : number , transparentMeshes : Array < SortedMesh > , opaqueMeshes : Array < SortedMesh > , materialOverrides : ModelMaterialOverrides , modelOpacity : number , modelColorMix ?: [ number , number , number , number ] ) {
299300
300301 const transform = painter . transform ;
301302
@@ -317,21 +318,21 @@ function prepareMeshes(painter: Painter, node: ModelNode, modelMatrix: mat4, pro
317318 if ( materialOverride && materialOverride . opacity <= 0 ) continue ;
318319
319320 if ( mesh . material . alphaMode !== 'BLEND' ) {
320- const opaqueMesh : SortedMesh = { mesh, depth : 0.0 , modelIndex, worldViewProjection, nodeModelMatrix, isLightMesh, materialOverride, modelColor : modelColorMix } ;
321+ const opaqueMesh : SortedMesh = { mesh, depth : 0.0 , modelIndex, worldViewProjection, nodeModelMatrix, isLightMesh, materialOverride, modelOpacity , modelColor : modelColorMix } ;
321322 opaqueMeshes . push ( opaqueMesh ) ;
322323 continue ;
323324 }
324325
325326 const centroidPos = vec3 . transformMat4 ( [ ] , mesh . centroid , worldViewProjection ) ;
326327 // Filter meshes behind the camera if in perspective mode
327328 if ( ! transform . isOrthographic && centroidPos [ 2 ] <= 0.0 ) continue ;
328- const transparentMesh : SortedMesh = { mesh, depth : centroidPos [ 2 ] , modelIndex, worldViewProjection, nodeModelMatrix, isLightMesh, materialOverride, modelColor : modelColorMix } ;
329+ const transparentMesh : SortedMesh = { mesh, depth : centroidPos [ 2 ] , modelIndex, worldViewProjection, nodeModelMatrix, isLightMesh, materialOverride, modelOpacity , modelColor : modelColorMix } ;
329330 transparentMeshes . push ( transparentMesh ) ;
330331 }
331332 }
332333 if ( node . children ) {
333334 for ( const child of node . children ) {
334- prepareMeshes ( painter , child , modelMatrix , projectionMatrix , modelIndex , transparentMeshes , opaqueMeshes , materialOverrides , modelColorMix ) ;
335+ prepareMeshes ( painter , child , modelMatrix , projectionMatrix , modelIndex , transparentMeshes , opaqueMeshes , materialOverrides , modelOpacity , modelColorMix ) ;
335336 }
336337 }
337338}
@@ -485,6 +486,7 @@ function drawModels(painter: Painter, sourceCache: SourceCache, layer: ModelStyl
485486 const rotation = layer . paint . get ( 'model-rotation' ) . evaluate ( modelFeature , modelFeatureState ) ;
486487 const scale = layer . paint . get ( 'model-scale' ) . evaluate ( modelFeature , modelFeatureState ) ;
487488 const translation = layer . paint . get ( 'model-translation' ) . evaluate ( modelFeature , modelFeatureState ) ;
489+ const modelOpacity = layer . paint . get ( 'model-opacity' ) . evaluate ( modelFeature , modelFeatureState ) ;
488490
489491 evaluateFeatureStateForNodeOverrides ( layer , model . id , modelFeatureState , model . featureProperties , model . nodeOverrideNames , model . nodeOverrides ) ;
490492 evaluateFeatureStateForMaterialOverrides ( layer , model . id , modelFeatureState , model . featureProperties , model . materialOverrideNames , model . materialOverrides ) ;
@@ -505,7 +507,7 @@ function drawModels(painter: Painter, sourceCache: SourceCache, layer: ModelStyl
505507 const modelParameters = { zScaleMatrix, negCameraPosMatrix} ;
506508 modelParametersVector . push ( modelParameters ) ;
507509 for ( const node of model . nodes ) {
508- prepareMeshes ( painter , node , model . matrix , painter . transform . expandedFarZProjMatrix , modelIndex , transparentMeshes , opaqueMeshes , model . materialOverrides ) ;
510+ prepareMeshes ( painter , node , model . matrix , painter . transform . expandedFarZProjMatrix , modelIndex , transparentMeshes , opaqueMeshes , model . materialOverrides , modelOpacity ) ;
509511 }
510512 modelIndex ++ ;
511513 }
@@ -527,25 +529,33 @@ function drawModels(painter: Painter, sourceCache: SourceCache, layer: ModelStyl
527529 return ;
528530 }
529531
530- drawSortedMeshes ( painter , layer , opacity , transparentMeshes , opaqueMeshes , modelParametersVector ) ;
532+ drawSortedMeshes ( painter , layer , transparentMeshes , opaqueMeshes , modelParametersVector ) ;
531533
532534 cleanup ( ) ;
533535}
534536
535- function drawSortedMeshes ( painter : Painter , layer : ModelStyleLayer , opacity : number , transparentMeshes : Array < SortedMesh > , opaqueMeshes : Array < SortedMesh > , modelParametersVector : Array < ModelParameters > ) {
536- // Draw opaque meshes
537- if ( opacity === 1 ) {
538- for ( const opaqueMesh of opaqueMeshes ) {
539- drawMesh ( opaqueMesh , painter , layer , modelParametersVector [ opaqueMesh . modelIndex ] , StencilMode . disabled , painter . colorModeForRenderPass ( ) ) ;
540- }
541- } else {
542- for ( const opaqueMesh of opaqueMeshes ) {
537+ function drawSortedMeshes ( painter : Painter , layer : ModelStyleLayer , transparentMeshes : Array < SortedMesh > , opaqueMeshes : Array < SortedMesh > , modelParametersVector : Array < ModelParameters > ) {
538+ let needsStencilClear = false ;
539+
540+ // Render opaque meshes first.
541+ // The per-feature model-opacity can be less than 1.0 even for opaque meshes.
542+ // In that case we need to render one extra pass to write into the depth buffer.
543+ for ( const opaqueMesh of opaqueMeshes ) {
544+ if ( opaqueMesh . modelOpacity !== 1.0 ) {
543545 // If we have layer opacity draw with two passes opaque meshes
544546 drawMesh ( opaqueMesh , painter , layer , modelParametersVector [ opaqueMesh . modelIndex ] , StencilMode . disabled , ColorMode . disabled ) ;
547+ needsStencilClear = true ;
545548 }
546- for ( const opaqueMesh of opaqueMeshes ) {
549+ }
550+ for ( const opaqueMesh of opaqueMeshes ) {
551+ if ( opaqueMesh . modelOpacity !== 1.0 ) {
547552 drawMesh ( opaqueMesh , painter , layer , modelParametersVector [ opaqueMesh . modelIndex ] , painter . stencilModeFor3D ( ) , painter . colorModeForRenderPass ( ) ) ;
553+ } else {
554+ drawMesh ( opaqueMesh , painter , layer , modelParametersVector [ opaqueMesh . modelIndex ] , StencilMode . disabled , painter . colorModeForRenderPass ( ) ) ;
548555 }
556+ }
557+
558+ if ( needsStencilClear ) {
549559 painter . resetStencilClippingMasks ( ) ;
550560 }
551561
@@ -673,6 +683,8 @@ function drawVectorLayerModels(painter: Painter, source: SourceCache, layer: Mod
673683
674684 const layerIndex = painter . style . order . indexOf ( layer . fqid ) ;
675685
686+ const layerOpacity = layer . paint . get ( 'model-opacity' ) . constantOr ( 1.0 ) ;
687+
676688 for ( const coord of coords ) {
677689 const tile = source . getTile ( coord ) ;
678690 const bucket = tile . getBucket ( layer ) as ModelBucket | null | undefined ;
@@ -776,7 +788,7 @@ function drawVectorLayerModels(painter: Painter, source: SourceCache, layer: Mod
776788 modelParametersVector . push ( modelParameters ) ;
777789
778790 for ( const node of model . nodes ) {
779- prepareMeshes ( painter , node , modelMatrix , painter . transform . expandedFarZProjMatrix , modelIndex , transparentMeshes , opaqueMeshes , model . materialOverrides , colorMix ) ;
791+ prepareMeshes ( painter , node , modelMatrix , painter . transform . expandedFarZProjMatrix , modelIndex , transparentMeshes , opaqueMeshes , model . materialOverrides , layerOpacity , colorMix ) ;
780792 }
781793 ++ modelIndex ;
782794 }
@@ -798,7 +810,7 @@ function drawVectorLayerModels(painter: Painter, source: SourceCache, layer: Mod
798810 drawShadowCaster ( transparentMesh . mesh , transparentMesh . nodeModelMatrix , painter , layer ) ;
799811 }
800812 } else {
801- drawSortedMeshes ( painter , layer , 1.0 , transparentMeshes , opaqueMeshes , modelParametersVector ) ;
813+ drawSortedMeshes ( painter , layer , transparentMeshes , opaqueMeshes , modelParametersVector ) ;
802814 }
803815
804816 }
0 commit comments