Skip to content

Commit b04748b

Browse files
authored
feat(core): Support clear color, depth, and stencil on multiple views (#9650)
1 parent a1f5321 commit b04748b

File tree

5 files changed

+139
-26
lines changed

5 files changed

+139
-26
lines changed

docs/api-reference/core/view.md

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,37 @@ The `viewState` property is intended to support a number of use cases:
8181
* Overriding a partial set of view state properties from a selected view state.
8282

8383

84-
#### `clear` (boolean | object, optional) {#clear}
84+
#### `clear` (boolean, optional) {#clear}
8585

86-
Clears the contents (pixels) of the viewport. The value of the `clear` prop is passed as an argument to luma.gl's `clear` function. If `true` clears color and depth buffers. If an object, behaviour is controlled by the following fields:
86+
Clears the contents (pixels) of the viewport. If `true` clears color, depth, and stencil buffers. Behavior is controlled with the `clearColor`, `clearDepth`, and `clearStencil` properties.
8787

88-
* `color` (boolean or Array) - if not `false`, clears all active color buffers with either the provided color or the currently set clear color.
89-
* `depth` (boolean) - if `true`, clears the depth buffer.
90-
* `stencil` (boolean) - if `true` clears the stencil buffer.
91-
92-
Note that deck.gl always clears the screen before each render, and clearing, while cheap, is not totally free. This means that viewports should only specify the `clear` property if they need additional clearing, e.g. because they are rendering on top of another viewport, or want to have a different background color etc.
88+
Note that deck.gl always clears the screen before each render, and clearing, while cheap, is not totally free. This means that viewports should only clear the viewport if they need additional clearing, e.g. because they are rendering on top of another viewport, or want to have a different background color etc.
9389

9490
Default `false`.
9591

92+
#### `clearColor` (number[] | false, optional) {#clearcolor}
93+
94+
Specifies the color to clear the viewport with, as an array of four numbers `[r, g, b, a?]`. Each channel should be an integer between 0 and 255. For example, `[255, 0, 0, 255]` for opaque red. If `clearColor` is `false`, the depth buffer will not be cleared. If `clear` is set to `false`, this property will be ignored.
95+
96+
Default `[0, 0, 0, 0]` (transparent).
97+
98+
#### `clearDepth` (number | false, optional) {#cleardepth}
99+
100+
Specifies the depth buffer value to clear the viewport with, as number between `0.0` and `1.0`. If `clearDepth` is `false`, the depth buffer will not be cleared. If `clear` is set to `false`, this property will be ignored.
101+
102+
Default `1.0` (far plane).
103+
104+
#### `clearStencil` (number | false, optional) {#clearstencil}
105+
106+
Specifies the stencil buffer value to clear the viewport with, as number between `0` and `255`. If `clearStencil` is `false`, the depth buffer will not be cleared. If `clear` is set to `false`, this property will be ignored.
107+
108+
Default `0` (clear).
109+
110+
**Examples:**
111+
112+
* Clearing to a solid color: `new View({clear: true, clearColor: [80, 120, 200, 255]})`
113+
* Clearing color and stencil but not depth: `new View({clear: true, clearColor: [50, 50, 50, 255], clearDepth: false})`
114+
* No clearing at all: `new View({})` or `new View({clear: false})`
96115

97116

98117
## Methods

modules/core/src/passes/layers-pass.ts

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import type {Device, Parameters, RenderPassParameters} from '@luma.gl/core';
66
import type {Framebuffer, RenderPass} from '@luma.gl/core';
7+
import type {NumberArray4} from '@math.gl/core';
78

89
import Pass from './pass';
910
import type Viewport from '../viewports/viewport';
@@ -80,13 +81,13 @@ export default class LayersPass extends Pass {
8081
parameters.colorMask = colorMask;
8182
}
8283
if (options.scissorRect) {
83-
parameters.scissorRect = options.scissorRect as [number, number, number, number];
84+
parameters.scissorRect = options.scissorRect as NumberArray4;
8485
}
8586

8687
const renderPass = this.device.beginRenderPass({
8788
framebuffer: options.target,
8889
parameters,
89-
clearColor: clearColor as [number, number, number, number],
90+
clearColor: clearColor as NumberArray4,
9091
clearDepth,
9192
clearStencil
9293
});
@@ -217,7 +218,21 @@ export default class LayersPass extends Pass {
217218
/* eslint-disable max-depth, max-statements, complexity */
218219
private _drawLayersInViewport(
219220
renderPass: RenderPass,
220-
{layers, shaderModuleProps: globalModuleParameters, pass, target, viewport, view},
221+
{
222+
layers,
223+
shaderModuleProps: globalModuleParameters,
224+
pass,
225+
target,
226+
viewport,
227+
view
228+
}: {
229+
layers: Layer[];
230+
shaderModuleProps: Record<string, any>;
231+
pass: string;
232+
target?: Framebuffer | null;
233+
viewport: Viewport;
234+
view?: View;
235+
},
221236
drawLayerParams: DrawLayerParameters[]
222237
): RenderStats {
223238
const glViewport = getGLViewport(this.device, {
@@ -226,18 +241,42 @@ export default class LayersPass extends Pass {
226241
viewport
227242
});
228243

229-
if (view && view.props.clear) {
230-
const clearOpts = view.props.clear === true ? {color: true, depth: true} : view.props.clear;
231-
const clearRenderPass = this.device.beginRenderPass({
232-
framebuffer: target,
233-
parameters: {
234-
viewport: glViewport,
235-
scissorRect: glViewport
236-
},
237-
clearColor: clearOpts.color ? [0, 0, 0, 0] : false,
238-
clearDepth: clearOpts.depth ? 1 : false
239-
});
240-
clearRenderPass.end();
244+
if (view) {
245+
const {clear, clearColor, clearDepth, clearStencil} = view.props;
246+
if (clear) {
247+
// If clear option is set, clear all buffers by default.
248+
let colorToUse: NumberArray4 | false = [0, 0, 0, 0];
249+
let depthToUse: number | false = 1.0;
250+
let stencilToUse: number | false = 0;
251+
252+
if (Array.isArray(clearColor)) {
253+
colorToUse = [...clearColor.slice(0, 3), clearColor[3] || 255].map(
254+
c => c / 255
255+
) as NumberArray4;
256+
} else if (clearColor === false) {
257+
colorToUse = false;
258+
}
259+
260+
if (clearDepth !== undefined) {
261+
depthToUse = clearDepth;
262+
}
263+
264+
if (clearStencil !== undefined) {
265+
stencilToUse = clearStencil;
266+
}
267+
268+
const clearRenderPass = this.device.beginRenderPass({
269+
framebuffer: target,
270+
parameters: {
271+
viewport: glViewport,
272+
scissorRect: glViewport
273+
},
274+
clearColor: colorToUse,
275+
clearDepth: depthToUse,
276+
clearStencil: stencilToUse
277+
});
278+
clearRenderPass.end();
279+
}
241280
}
242281

243282
// render layers in normal colors
@@ -252,7 +291,7 @@ export default class LayersPass extends Pass {
252291

253292
// render layers in normal colors
254293
for (let layerIndex = 0; layerIndex < layers.length; layerIndex++) {
255-
const layer = layers[layerIndex] as Layer;
294+
const layer = layers[layerIndex];
256295
const drawLayerParameters = drawLayerParams[layerIndex];
257296
const {shouldDrawLayer} = drawLayerParameters;
258297

@@ -454,7 +493,7 @@ function getGLViewport(
454493
viewport
455494
}: {
456495
shaderModuleProps: any;
457-
target?: Framebuffer;
496+
target?: Framebuffer | null;
458497
viewport: Viewport;
459498
}
460499
): [number, number, number, number] {

modules/core/src/views/view.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@ export type CommonViewProps<ViewState> = {
3131
top?: number | string;
3232
bottom?: number | string;
3333
} | null;
34-
/** When using multiple views, set this flag to wipe the pixels drawn by other overlaping views */
34+
/** When using multiple views, set this flag to wipe the pixels drawn by other overlapping views. Default `false` */
3535
clear?: boolean;
36+
/** Color to clear the viewport with, in RGBA format [r, g, b, a?]. Values are 0-255. Default `[0, 0, 0, 0]` (transparent). */
37+
clearColor?: number[] | false;
38+
/** Depth buffer value to clear the viewport with, between 0.0 - 1.0. Default `1.0` (far plane). */
39+
clearDepth?: number | false;
40+
/** Stencil buffer Value to clear the viewport with, between 0 - 255. Default `0` (clear). */
41+
clearStencil?: number | false;
3642
/** State of the view */
3743
viewState?:
3844
| string
38 KB
Loading

test/render/test-cases/views.js

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,5 +133,54 @@ export default [
133133
],
134134
goldenImage: `./test/render/golden-images/globe-mvt.png`
135135
};
136-
})
136+
}),
137+
{
138+
name: 'multi-view',
139+
views: [
140+
new MapView({id: 'background', clear: true, clearColor: [0, 0, 255, 128]}),
141+
new MapView({
142+
id: 'transparent',
143+
x: 0,
144+
y: 0,
145+
width: '50%',
146+
height: '50%',
147+
clear: true
148+
}),
149+
new MapView({
150+
id: 'green',
151+
x: '50%',
152+
y: 0,
153+
width: '50%',
154+
height: '50%',
155+
clear: true,
156+
clearColor: [0, 255, 0]
157+
}),
158+
new MapView({
159+
id: 'clearing-color-disabled',
160+
x: 0,
161+
y: '50%',
162+
width: '50%',
163+
height: '50%',
164+
clear: true,
165+
clearColor: false
166+
}),
167+
new MapView({id: 'default', x: '50%', y: '50%', width: '50%', height: '50%'})
168+
],
169+
viewState: {
170+
latitude: 0,
171+
longitude: 0,
172+
zoom: 0,
173+
pitch: 0,
174+
bearing: 0
175+
},
176+
layers: [
177+
new ScatterplotLayer({
178+
data: getRes0Cells(),
179+
getPosition: d => cellToLatLng(d).reverse(),
180+
radiusMinPixels: 4,
181+
getFillColor: [0, 0, 0]
182+
})
183+
],
184+
goldenImage: './test/render/golden-images/multi-view.png'
185+
}
137186
];

0 commit comments

Comments
 (0)