diff --git a/modules/layers/src/scatterplot-layer/scatterplot-layer-fragment.glsl.ts b/modules/layers/src/scatterplot-layer/scatterplot-layer-fragment.glsl.ts index edf09ef7e2f..e21016f5fb8 100644 --- a/modules/layers/src/scatterplot-layer/scatterplot-layer-fragment.glsl.ts +++ b/modules/layers/src/scatterplot-layer/scatterplot-layer-fragment.glsl.ts @@ -18,14 +18,14 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -export default `\ +import {glsl} from '@luma.gl/core'; + +export default glsl`\ +#version 300 es #define SHADER_NAME scatterplot-layer-fragment-shader precision highp float; - -uniform bool filled; -uniform float stroked; -uniform bool antialiasing; +precision highp int; varying vec4 vFillColor; varying vec4 vLineColor; @@ -33,11 +33,30 @@ varying vec2 unitPosition; varying float innerUnitRadius; varying float outerRadiusPixels; +// Needs to be identical to vertex shader uniforms +uniform scatterplotUniforms { + // float opacity; + float radiusScale; + float radiusMinPixels; + float radiusMaxPixels; + float lineWidthScale; + float lineWidthMinPixels; + float lineWidthMaxPixels; + float stroked; + bool filled; + bool antialiasing; + bool billboard; + int radiusUnits; + int lineWidthUnits; +} scatterplot; + + uniform float opacity; + void main(void) { geometry.uv = unitPosition; float distToCenter = length(unitPosition) * outerRadiusPixels; - float inCircle = antialiasing ? + float inCircle = scatterplot.antialiasing ? smoothedge(distToCenter, outerRadiusPixels) : step(distToCenter, outerRadiusPixels); @@ -45,12 +64,12 @@ void main(void) { discard; } - if (stroked > 0.5) { - float isLine = antialiasing ? + if (scatterplot.stroked > 0.5) { + float isLine = scatterplot.antialiasing ? smoothedge(innerUnitRadius * outerRadiusPixels, distToCenter) : step(innerUnitRadius * outerRadiusPixels, distToCenter); - if (filled) { + if (scatterplot.filled) { gl_FragColor = mix(vFillColor, vLineColor, isLine); } else { if (isLine == 0.0) { @@ -58,7 +77,7 @@ void main(void) { } gl_FragColor = vec4(vLineColor.rgb, vLineColor.a * isLine); } - } else if (filled) { + } else if (scatterplot.filled) { gl_FragColor = vFillColor; } else { discard; diff --git a/modules/layers/src/scatterplot-layer/scatterplot-layer-vertex.glsl.ts b/modules/layers/src/scatterplot-layer/scatterplot-layer-vertex.glsl.ts index 121c18f1d27..dc564e9278d 100644 --- a/modules/layers/src/scatterplot-layer/scatterplot-layer-vertex.glsl.ts +++ b/modules/layers/src/scatterplot-layer/scatterplot-layer-vertex.glsl.ts @@ -18,7 +18,46 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -export default `\ +import {ShaderUniformType, glsl} from '@luma.gl/core'; + +export type ScatterplotLayerUniforms = { + // opacity: number; + radiusScale: number; + radiusMinPixels: number; + radiusMaxPixels: number; + lineWidthScale: number; + lineWidthMinPixels: number; + lineWidthMaxPixels: number; + stroked: number; + filled: boolean; + antialiasing: boolean; + billboard: boolean; + radiusUnits: number; + lineWidthUnits: number; +}; + +export const scatterplot: {uniformTypes: Record} = { + uniformTypes: { + // opacity: 'f32', + radiusScale: 'f32', + radiusMinPixels: 'f32', + radiusMaxPixels: 'f32', + lineWidthScale: 'f32', + lineWidthMinPixels: 'f32', + lineWidthMaxPixels: 'f32', + stroked: 'f32', + filled: 'f32', + antialiasing: 'f32', + billboard: 'f32', + radiusUnits: 'i32', + lineWidthUnits: 'i32' + } +}; + +const SMOOTH_EDGE_RADIUS = 0.5; + +export default glsl`\ +#version 300 es #define SHADER_NAME scatterplot-layer-vertex-shader attribute vec3 positions; @@ -31,56 +70,60 @@ attribute vec4 instanceFillColors; attribute vec4 instanceLineColors; attribute vec3 instancePickingColors; -uniform float opacity; -uniform float radiusScale; -uniform float radiusMinPixels; -uniform float radiusMaxPixels; -uniform float lineWidthScale; -uniform float lineWidthMinPixels; -uniform float lineWidthMaxPixels; -uniform float stroked; -uniform bool filled; -uniform bool antialiasing; -uniform bool billboard; -uniform int radiusUnits; -uniform int lineWidthUnits; - varying vec4 vFillColor; varying vec4 vLineColor; varying vec2 unitPosition; varying float innerUnitRadius; varying float outerRadiusPixels; +// Needs to be identical to fragment shader uniforms +uniform scatterplotUniforms { + // float opacity; + float radiusScale; + float radiusMinPixels; + float radiusMaxPixels; + float lineWidthScale; + float lineWidthMinPixels; + float lineWidthMaxPixels; + float stroked; + bool filled; + bool antialiasing; + bool billboard; + int radiusUnits; + int lineWidthUnits; +} scatterplot; + + uniform float opacity; void main(void) { geometry.worldPosition = instancePositions; // Multiply out radius and clamp to limits outerRadiusPixels = clamp( - project_size_to_pixel(radiusScale * instanceRadius, radiusUnits), - radiusMinPixels, radiusMaxPixels + project_size_to_pixel(scatterplot.radiusScale * instanceRadius, scatterplot.radiusUnits), + scatterplot.radiusMinPixels, scatterplot.radiusMaxPixels ); // Multiply out line width and clamp to limits float lineWidthPixels = clamp( - project_size_to_pixel(lineWidthScale * instanceLineWidths, lineWidthUnits), - lineWidthMinPixels, lineWidthMaxPixels + project_size_to_pixel(scatterplot.lineWidthScale * instanceLineWidths, scatterplot.lineWidthUnits), + scatterplot.lineWidthMinPixels, scatterplot.lineWidthMaxPixels ); // outer radius needs to offset by half stroke width - outerRadiusPixels += stroked * lineWidthPixels / 2.0; + outerRadiusPixels += scatterplot.stroked * lineWidthPixels / 2.0; - // Expand geometry to accomodate edge smoothing - float edgePadding = antialiasing ? (outerRadiusPixels + SMOOTH_EDGE_RADIUS) / outerRadiusPixels : 1.0; + // Expand geometry to accommodate edge smoothing + float edgePadding = scatterplot.antialiasing ? (outerRadiusPixels + SMOOTH_EDGE_RADIUS) / outerRadiusPixels : 1.0; // position on the containing square in [-1, 1] space unitPosition = edgePadding * positions.xy; geometry.uv = unitPosition; geometry.pickingColor = instancePickingColors; - innerUnitRadius = 1.0 - stroked * lineWidthPixels / outerRadiusPixels; + innerUnitRadius = 1.0 - scatterplot.stroked * lineWidthPixels / outerRadiusPixels; - if (billboard) { + if (scatterplot.billboard) { gl_Position = project_position_to_clipspace(instancePositions, instancePositions64Low, vec3(0.0), geometry.position); DECKGL_FILTER_GL_POSITION(gl_Position, geometry); vec3 offset = edgePadding * positions * outerRadiusPixels; diff --git a/modules/layers/src/scatterplot-layer/scatterplot-layer.ts b/modules/layers/src/scatterplot-layer/scatterplot-layer.ts index fc1bb6e01f3..765d054c00e 100644 --- a/modules/layers/src/scatterplot-layer/scatterplot-layer.ts +++ b/modules/layers/src/scatterplot-layer/scatterplot-layer.ts @@ -19,13 +19,11 @@ // THE SOFTWARE. import {Layer, project32, picking, UNIT} from '@deck.gl/core'; +import {UniformStore} from '@luma.gl/core'; import {Geometry} from '@luma.gl/engine'; import {Model} from '@luma.gl/engine'; import {GL} from '@luma.gl/constants'; -import vs from './scatterplot-layer-vertex.glsl'; -import fs from './scatterplot-layer-fragment.glsl'; - import type { LayerProps, LayerDataSource, @@ -37,6 +35,9 @@ import type { DefaultProps } from '@deck.gl/core'; +import vs, {ScatterplotLayerUniforms, scatterplot} from './scatterplot-layer-vertex.glsl'; +import fs from './scatterplot-layer-fragment.glsl'; + const DEFAULT_COLOR: [number, number, number, number] = [0, 0, 0, 255]; /** All props supported by the ScatterplotLayer */ @@ -181,11 +182,19 @@ export default class ScatterplotLayer static defaultProps = defaultProps; static layerName: string = 'ScatterplotLayer'; + state!: Layer['state'] & { + uniformStore: UniformStore<{scatterplot: ScatterplotLayerUniforms}>; + }; + getShaders() { return super.getShaders({vs, fs, modules: [project32, picking]}); } initializeState() { + this.state.uniformStore = new UniformStore<{scatterplot: ScatterplotLayerUniforms}>({ + scatterplot + }); + this.getAttributeManager()!.addInstanced({ instancePositions: { size: 3, @@ -251,20 +260,25 @@ export default class ScatterplotLayer lineWidthMaxPixels } = this.props; + // opacity etc this.state.model.setUniforms(uniforms); - this.state.model.setUniforms({ - stroked: stroked ? 1 : 0, - filled, - billboard, - antialiasing, - radiusUnits: UNIT[radiusUnits], - radiusScale, - radiusMinPixels, - radiusMaxPixels, - lineWidthUnits: UNIT[lineWidthUnits], - lineWidthScale, - lineWidthMinPixels, - lineWidthMaxPixels + + // scatterplot uniform block + this.state.uniformStore.setUniforms({ + scatterplot: { + stroked: stroked ? 1 : 0, + filled, + billboard, + antialiasing, + radiusUnits: UNIT[radiusUnits], + radiusScale, + radiusMinPixels, + radiusMaxPixels, + lineWidthUnits: UNIT[lineWidthUnits], + lineWidthScale, + lineWidthMinPixels, + lineWidthMaxPixels + } }); this.state.model.draw(this.context.renderPass); } @@ -282,6 +296,12 @@ export default class ScatterplotLayer positions: {size: 3, value: new Float32Array(positions)} } }), + bindings: { + scatterplotUniforms: this.state.uniformStore.getManagedUniformBuffer( + this.context.device, + 'scatterplot' + ) + }, isInstanced: true }); } diff --git a/modules/mapbox/package.json b/modules/mapbox/package.json index d49a1615f5a..7ffe2aa3440 100644 --- a/modules/mapbox/package.json +++ b/modules/mapbox/package.json @@ -30,6 +30,7 @@ "prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env=dev" }, "dependencies": { + "@luma.gl/constants": "9.0.0-alpha.36", "@luma.gl/core": "9.0.0-alpha.36", "@math.gl/web-mercator": "4.0.0-alpha.4", "@types/mapbox-gl": "^2.6.3" diff --git a/modules/test-utils/src/generate-layer-tests.ts b/modules/test-utils/src/generate-layer-tests.ts index 7febf6b58fa..8a8c19173ab 100644 --- a/modules/test-utils/src/generate-layer-tests.ts +++ b/modules/test-utils/src/generate-layer-tests.ts @@ -19,7 +19,7 @@ // THE SOFTWARE. import {_count as count} from '@deck.gl/core'; -function noop() {} +function noop() {} // eslint-disable-line @typescript-eslint/no-empty-function function defaultAssert(condition, comment) { if (!condition) {