diff --git a/examples/website/geojson/app.jsx b/examples/website/geojson/app.jsx index 669880eb7d1..fb3caa1d1ea 100644 --- a/examples/website/geojson/app.jsx +++ b/examples/website/geojson/app.jsx @@ -94,6 +94,7 @@ export default function App({data = DATA_URL, mapStyle = MAP_STYLE}) { new GeoJsonLayer({ id: 'geojson', data, + autoHighlight: true, opacity: 0.8, stroked: false, filled: true, diff --git a/modules/core/src/index.ts b/modules/core/src/index.ts index 73af0dc997a..93195a67d1e 100644 --- a/modules/core/src/index.ts +++ b/modules/core/src/index.ts @@ -135,7 +135,7 @@ export type { TextureSource, Material } from './types/layer-props'; -export type {FilterContext} from './passes/layers-pass'; +export type {FilterContext, LayerParameters} from './passes/layers-pass'; export type {PickingInfo, GetPickingInfoParams} from './lib/picking/pick-info'; export type {ConstructorOf as _ConstructorOf} from './types/types'; export type {BinaryAttribute} from './lib/attribute/attribute'; diff --git a/modules/core/src/lib/deck-picker.ts b/modules/core/src/lib/deck-picker.ts index 957efe4437d..ea7f3bef9f5 100644 --- a/modules/core/src/lib/deck-picker.ts +++ b/modules/core/src/lib/deck-picker.ts @@ -145,16 +145,15 @@ export default class DeckPicker { _resizeBuffer() { // Create a frame buffer if not already available if (!this.pickingFBO) { - this.pickingFBO = this.device.createFramebuffer({colorAttachments: ['rgba8unorm']}); + this.pickingFBO = this.device.createFramebuffer({ + colorAttachments: ['rgba8unorm'], + depthStencilAttachment: 'depth16unorm' + }); if (this.device.isTextureFormatRenderable('rgba32float')) { const depthFBO = this.device.createFramebuffer({ - colorAttachments: [ - this.device.createTexture({ - format: 'rgba32float' - // type: GL.FLOAT - }) - ] + colorAttachments: ['rgba32float'], + depthStencilAttachment: 'depth16unorm' }); this.depthFBO = depthFBO; } diff --git a/modules/core/src/lib/deck.ts b/modules/core/src/lib/deck.ts index 97bc4074c11..54bc2152672 100644 --- a/modules/core/src/lib/deck.ts +++ b/modules/core/src/lib/deck.ts @@ -35,8 +35,7 @@ import {luma} from '@luma.gl/core'; import {WebGLDevice} from '@luma.gl/webgl'; import {Timeline} from '@luma.gl/engine'; import {AnimationLoop} from '@luma.gl/engine'; -import {GL} from '@luma.gl/constants'; -import type {Device, DeviceProps, Framebuffer} from '@luma.gl/core'; +import type {Device, DeviceProps, Framebuffer, Parameters} from '@luma.gl/core'; import type {ShaderModule} from '@luma.gl/shadertools'; import {Stats} from '@probe.gl/stats'; @@ -114,7 +113,7 @@ export type DeckProps = { pickingRadius?: number; /** WebGL parameters to be set before each frame is rendered. */ - parameters?: any; + parameters?: Parameters; /** If supplied, will be called before a layer is drawn to determine whether it should be rendered. */ layerFilter?: ((context: FilterContext) => boolean) | null; @@ -946,14 +945,6 @@ export default class Deck { // instrumentGLContext(this.device.gl, {enable: true, copyState: true}); } - this.device.setParametersWebGL({ - blend: true, - blendFunc: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA, GL.ONE, GL.ONE_MINUS_SRC_ALPHA], - polygonOffsetFill: true, - depthTest: true, - depthFunc: GL.LEQUAL - }); - this.props.onDeviceInitialized(this.device); if (this.device instanceof WebGLDevice) { // Legacy callback - warn? diff --git a/modules/core/src/lib/layer.ts b/modules/core/src/lib/layer.ts index d9e1d64d5e4..a4887b5006e 100644 --- a/modules/core/src/lib/layer.ts +++ b/modules/core/src/lib/layer.ts @@ -52,7 +52,7 @@ import type {DefaultProps} from '../lifecycle/prop-types'; import type {LayerData, LayerProps} from '../types/layer-props'; import type {LayerContext} from './layer-manager'; import type {BinaryAttribute} from './attribute/attribute'; -import {RenderPass} from '@luma.gl/core'; +import type {RenderPass, Parameters as DeviceParameters} from '@luma.gl/core'; import {PickingProps} from '@luma.gl/shadertools'; const TRACE_CHANGE_FLAG = 'layer.changeFlag'; @@ -1046,7 +1046,7 @@ export default abstract class Layer extends Component< renderPass: RenderPass; moduleParameters: any; uniforms: any; - parameters: any; + parameters: DeviceParameters; }): void { this._updateAttributeTransition(); @@ -1069,28 +1069,19 @@ export default abstract class Layer extends Component< this.setShaderModuleProps({picking: {isActive, isAttribute}}); } - // Apply polygon offset to avoid z-fighting - // TODO - move to draw-layers - const {getPolygonOffset} = this.props; - const offsets = (getPolygonOffset && getPolygonOffset(uniforms)) || [0, 0]; - - context.device.setParametersWebGL({polygonOffset: offsets}); - for (const model of this.getModels()) { model.setParameters(parameters); } // Call subclass lifecycle method - context.device.withParametersWebGL(parameters, () => { - const opts = {renderPass, moduleParameters, uniforms, parameters, context}; + const opts = {renderPass, moduleParameters, uniforms, parameters, context}; - // extensions - for (const extension of this.props.extensions) { - extension.draw.call(this, opts, extension); - } + // extensions + for (const extension of this.props.extensions) { + extension.draw.call(this, opts, extension); + } - this.draw(opts); - }); + this.draw(opts); } finally { this.props = currentProps; } diff --git a/modules/core/src/passes/layers-pass.ts b/modules/core/src/passes/layers-pass.ts index eb3377f32ad..6236429409e 100644 --- a/modules/core/src/passes/layers-pass.ts +++ b/modules/core/src/passes/layers-pass.ts @@ -1,4 +1,4 @@ -import type {Device, RenderPassParameters} from '@luma.gl/core'; +import type {Device, RenderPassParameters, Parameters} from '@luma.gl/core'; import type {Framebuffer, RenderPass} from '@luma.gl/core'; import Pass from './pass'; @@ -9,6 +9,8 @@ import type {Effect} from '../lib/effect'; export type Rect = {x: number; y: number; width: number; height: number}; +export type LayerParameters = Parameters & RenderPassParameters; + export type LayersPassRenderOptions = { /** @deprecated TODO v9 recommend we rename this to framebuffer to minimize confusion */ target?: Framebuffer | null; @@ -36,7 +38,7 @@ type DrawLayerParameters = { shouldDrawLayer: boolean; layerRenderIndex?: number; moduleParameters?: any; - layerParameters?: any; + layerParameters?: LayerParameters; }; export type FilterContext = { @@ -54,6 +56,14 @@ export type RenderStats = { pickableCount: number; }; +const DEFAULT_PARAMETERS: LayerParameters = { + blendColorSrcFactor: 'src-alpha', + blendColorDstFactor: 'one-minus-src-alpha', + blendAlphaSrcFactor: 'one', + blendAlphaDstFactor: 'one-minus-src-alpha', + depthCompare: 'less-equal' +}; + /** A Pass that renders all layers */ export default class LayersPass extends Pass { _lastRenderIndex: number = -1; @@ -72,9 +82,6 @@ export default class LayersPass extends Pass { if (options.colorMask) { parameters.colorMask = colorMask; } - if (options.scissorRect) { - parameters.scissorRect = options.scissorRect; - } const renderPass = this.device.beginRenderPass({ framebuffer: options.target, @@ -125,6 +132,7 @@ export default class LayersPass extends Pass { target, moduleParameters, viewport: subViewport, + scissorRect: options.scissorRect, view, pass: options.pass, layers: options.layers @@ -191,7 +199,9 @@ export default class LayersPass extends Pass { moduleParameters ); layerParam.layerParameters = { + ...DEFAULT_PARAMETERS, ...layer.context.deck?.props.parameters, + ...layer.props.parameters, ...this.getLayerParameters(layer, layerIndex, viewport) }; } @@ -206,8 +216,8 @@ export default class LayersPass extends Pass { /* eslint-disable max-depth, max-statements */ private _drawLayersInViewport( renderPass: RenderPass, - {layers, moduleParameters: globalModuleParameters, pass, target, viewport, view}, - drawLayerParams + {layers, moduleParameters: globalModuleParameters, pass, target, viewport, view, scissorRect}, + drawLayerParams: DrawLayerParameters[] ): RenderStats { const glViewport = getGLViewport(this.device, { moduleParameters: globalModuleParameters, @@ -215,18 +225,6 @@ export default class LayersPass extends Pass { viewport }); - // TODO v9 - remove WebGL specific logic - if (view && view.props.clear) { - const clearOpts = view.props.clear === true ? {color: true, depth: true} : view.props.clear; - this.device.withParametersWebGL( - { - scissorTest: true, - scissor: glViewport - }, - () => this.device.clearWebGL(clearOpts) - ); - } - // render layers in normal colors const renderStatus = { totalCount: layers.length, @@ -235,7 +233,11 @@ export default class LayersPass extends Pass { pickableCount: 0 }; - renderPass.setParameters({viewport: glViewport}); + renderPass.setParameters({viewport: glViewport, scissorRect: scissorRect || glViewport}); + if (view?.props.clear) { + // @ts-expect-error WEBGLRenderPass protected method + renderPass.clear?.(); + } // render layers in normal colors for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) { @@ -252,8 +254,10 @@ export default class LayersPass extends Pass { } else if (shouldDrawLayer) { // Draw the layer renderStatus.visibleCount++; + // layerParameters and layerRenderIndex are always present in this context + renderPass.setParameters(layerParameters!); - this._lastRenderIndex = Math.max(this._lastRenderIndex, layerRenderIndex); + this._lastRenderIndex = Math.max(this._lastRenderIndex, layerRenderIndex!); // overwrite layer.context.viewport with the sub viewport moduleParameters.viewport = viewport; @@ -268,7 +272,7 @@ export default class LayersPass extends Pass { renderPass, moduleParameters, uniforms: {layerIndex: layerRenderIndex}, - parameters: layerParameters + parameters: layerParameters! }); } catch (err) { layer.raiseError(err as Error, `drawing ${layer} to ${pass}`); @@ -289,8 +293,15 @@ export default class LayersPass extends Pass { return null; } - protected getLayerParameters(layer: Layer, layerIndex: number, viewport: Viewport): any { - return layer.props.parameters; + protected getLayerParameters( + layer: Layer, + layerIndex: number, + viewport: Viewport + ): LayerParameters { + const {getPolygonOffset} = layer.props; + const offsets = (getPolygonOffset && getPolygonOffset({layerIndex})) || [0, 0]; + + return {depthBias: offsets[0], depthBiasSlopeScale: offsets[1]}; } /* Private */ diff --git a/modules/core/src/passes/pick-layers-pass.ts b/modules/core/src/passes/pick-layers-pass.ts index 79996a9522e..655f26a9444 100644 --- a/modules/core/src/passes/pick-layers-pass.ts +++ b/modules/core/src/passes/pick-layers-pass.ts @@ -1,4 +1,9 @@ -import LayersPass, {LayersPassRenderOptions, RenderStats, Rect} from './layers-pass'; +import LayersPass, { + LayersPassRenderOptions, + LayerParameters, + RenderStats, + Rect +} from './layers-pass'; import type {Framebuffer, RenderPipelineParameters} from '@luma.gl/core'; import log from '../utils/log'; @@ -123,29 +128,19 @@ export default class PickLayersPass extends LayersPass { }; } - protected getLayerParameters(layer: Layer, layerIndex: number, viewport: Viewport): any { - const pickParameters = { - // TODO - When used as a custom layer in older Mapbox versions, context - // state was dirty. Mapbox fixed that; we should test and remove the workaround. - // https://github.com/mapbox/mapbox-gl-js/issues/7801 - depthMask: true, - depthTest: true, - depthRange: [0, 1], - ...layer.props.parameters, - // Blending - ...PICKING_BLENDING, - blend: !this.pickZ - }; + protected getLayerParameters( + layer: Layer, + layerIndex: number, + viewport: Viewport + ): LayerParameters { + const pickParameters: LayerParameters = super.getLayerParameters(layer, layerIndex, viewport); const {pickable, operation} = layer.props; - if (!this._colorEncoderState) { - pickParameters.blend = false; + if (!this._colorEncoderState || operation.includes('terrain')) { + pickParameters.blendColorOperation = 'none'; } else if (pickable && operation.includes('draw')) { - pickParameters.blend = true; - pickParameters.blendColor = encodeColor(this._colorEncoderState, layer, viewport); - } - if (operation.includes('terrain')) { - pickParameters.blend = false; + Object.assign(pickParameters, PICKING_BLENDING); + pickParameters.blendConstant = encodeColor(this._colorEncoderState, layer, viewport); } return pickParameters; diff --git a/modules/core/src/passes/shadow-pass.ts b/modules/core/src/passes/shadow-pass.ts index 753517c6fb8..4be008b1c69 100644 --- a/modules/core/src/passes/shadow-pass.ts +++ b/modules/core/src/passes/shadow-pass.ts @@ -1,7 +1,7 @@ import type {Device, Framebuffer, Texture} from '@luma.gl/core'; import type Layer from '../lib/layer'; import type Viewport from '../viewports/viewport'; -import LayersPass from './layers-pass'; +import LayersPass, {LayerParameters} from './layers-pass'; export default class ShadowPass extends LayersPass { shadowMap: Texture; @@ -67,8 +67,16 @@ export default class ShadowPass extends LayersPass { super.render({...params, clearColor, target, pass: 'shadow'}); } - protected getLayerParameters(layer: Layer<{}>, layerIndex: number, viewport: Viewport) { - return {...layer.props.parameters, blend: false, depthRange: [0, 1], depthTest: true}; + protected getLayerParameters( + layer: Layer<{}>, + layerIndex: number, + viewport: Viewport + ): LayerParameters { + return { + ...super.getLayerParameters(layer, layerIndex, viewport), + blendColorOperation: 'none', + depthCompare: 'less-equal' + }; } shouldDrawLayer(layer) { diff --git a/modules/core/src/types/layer-props.ts b/modules/core/src/types/layer-props.ts index 0a641ab0069..b4806f7c8ac 100644 --- a/modules/core/src/types/layer-props.ts +++ b/modules/core/src/types/layer-props.ts @@ -6,7 +6,7 @@ import type {ConstructorOf, NumericArray, TypedArray} from './types'; import type {PickingInfo} from '../lib/picking/pick-info'; import type {MjolnirEvent} from 'mjolnir.js'; -import type {Texture, TextureProps} from '@luma.gl/core'; +import type {Texture, TextureProps, Parameters} from '@luma.gl/core'; import type {Buffer} from '@luma.gl/core'; import type {Loader} from '@loaders.gl/loader-utils'; import type {LightingModuleSettings} from '../shaderlib/index'; @@ -185,7 +185,7 @@ export type LayerProps = { /** * Override the WebGL parameters used to draw this layer. See https://luma.gl/modules/gltools/docs/api-reference/parameter-setting#parameters */ - parameters?: any; + parameters?: Parameters; /** * Create smooth transitions when prop values update. */ diff --git a/modules/extensions/src/collision-filter/collision-filter-pass.ts b/modules/extensions/src/collision-filter/collision-filter-pass.ts index 55e9780026e..25f7c42a707 100644 --- a/modules/extensions/src/collision-filter/collision-filter-pass.ts +++ b/modules/extensions/src/collision-filter/collision-filter-pass.ts @@ -1,5 +1,11 @@ import {Framebuffer} from '@luma.gl/core'; -import {Layer, _LayersPass as LayersPass, LayersPassRenderOptions, Viewport} from '@deck.gl/core'; +import { + Layer, + _LayersPass as LayersPass, + LayerParameters, + LayersPassRenderOptions, + Viewport +} from '@deck.gl/core'; type CollisionFilterPassRenderOptions = LayersPassRenderOptions & {}; @@ -12,8 +18,12 @@ export default class CollisionFilterPass extends LayersPass { this.render({...options, clearColor, scissorRect, target, pass: 'collision'}); } - protected getLayerParameters(layer: Layer, layerIndex: number, viewport: Viewport): any { - return {...layer.props.parameters, blend: false, depthRange: [0, 1], depthTest: true}; + protected getLayerParameters( + layer: Layer, + layerIndex: number, + viewport: Viewport + ): LayerParameters { + return {blendColorOperation: 'none', depthCompare: 'less-equal'}; } getModuleParameters() { diff --git a/modules/extensions/src/mask/mask-pass.ts b/modules/extensions/src/mask/mask-pass.ts index 933d8f21f55..ef009df317e 100644 --- a/modules/extensions/src/mask/mask-pass.ts +++ b/modules/extensions/src/mask/mask-pass.ts @@ -1,5 +1,11 @@ import type {Device, Framebuffer, RenderPipelineParameters, Texture} from '@luma.gl/core'; -import {Layer, _LayersPass as LayersPass, LayersPassRenderOptions, Viewport} from '@deck.gl/core'; +import { + Layer, + _LayersPass as LayersPass, + LayerParameters, + LayersPassRenderOptions, + Viewport +} from '@deck.gl/core'; type MaskPassRenderOptions = LayersPassRenderOptions & { /** The channel to render into, 0:red, 1:green, 2:blue, 3:alpha */ @@ -50,13 +56,12 @@ export default class MaskPass extends LayersPass { super.render({...options, clearColor, colorMask, target: this.fbo, pass: 'mask'}); } - protected getLayerParameters(layer: Layer<{}>, layerIndex: number, viewport: Viewport) { - return { - ...layer.props.parameters, - blend: true, - depthTest: false, - ...MASK_BLENDING - }; + protected getLayerParameters( + layer: Layer<{}>, + layerIndex: number, + viewport: Viewport + ): LayerParameters { + return {depthCompare: 'less-equal', ...MASK_BLENDING}; } shouldDrawLayer(layer) { diff --git a/modules/extensions/src/terrain/terrain-pass.ts b/modules/extensions/src/terrain/terrain-pass.ts index fca054ce06e..380fefbc073 100644 --- a/modules/extensions/src/terrain/terrain-pass.ts +++ b/modules/extensions/src/terrain/terrain-pass.ts @@ -1,5 +1,11 @@ import {RenderPipelineParameters} from '@luma.gl/core'; -import {Layer, Viewport, _LayersPass as LayersPass, LayersPassRenderOptions} from '@deck.gl/core'; +import { + Layer, + Viewport, + _LayersPass as LayersPass, + LayerParameters, + LayersPassRenderOptions +} from '@deck.gl/core'; import type {HeightMapBuilder} from './height-map-builder'; import type {TerrainCover} from './terrain-cover'; @@ -75,11 +81,13 @@ export class TerrainPass extends LayersPass { }); } - protected getLayerParameters(layer: Layer<{}>, layerIndex: number, viewport: Viewport) { + protected getLayerParameters( + layer: Layer<{}>, + layerIndex: number, + viewport: Viewport + ): LayerParameters { return { - ...layer.props.parameters, - blend: true, - depthTest: false, + depthCompare: 'always', ...(layer.props.operation.includes('terrain') && TERRAIN_BLENDING) }; } diff --git a/modules/extensions/src/terrain/terrain-picking-pass.ts b/modules/extensions/src/terrain/terrain-picking-pass.ts index 9c44e020c57..990561f3291 100644 --- a/modules/extensions/src/terrain/terrain-picking-pass.ts +++ b/modules/extensions/src/terrain/terrain-picking-pass.ts @@ -2,7 +2,8 @@ import { Layer, Viewport, LayersPassRenderOptions, - _PickLayersPass as PickLayersPass + _PickLayersPass as PickLayersPass, + LayerParameters } from '@deck.gl/core'; import type {TerrainCover} from './terrain-cover'; @@ -68,14 +69,17 @@ export class TerrainPickingPass extends PickLayersPass { }); } - protected getLayerParameters(layer: Layer, layerIndex: number, viewport: Viewport): any { - let parameters: any; + protected getLayerParameters( + layer: Layer, + layerIndex: number, + viewport: Viewport + ): LayerParameters { + let parameters: LayerParameters; if (this.drawParameters[layer.id]) { parameters = this.drawParameters[layer.id]; } else { parameters = super.getLayerParameters(layer, layerIndex, viewport); - parameters.blend = true; } - return {...parameters, depthTest: false}; + return {...parameters, depthCompare: 'always'}; } }