Skip to content

Commit

Permalink
GPU GridLayer PART-4: Add supporting for picking
Browse files Browse the repository at this point in the history
  • Loading branch information
1chandu committed May 19, 2019
1 parent 44b6993 commit 6fc7ba2
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 56 deletions.
Expand Up @@ -30,5 +30,6 @@ out vec4 fragColor;
void main(void) {
fragColor = vColor;
fragColor = picking_filterColor(fragColor);
}
`;
Expand Up @@ -30,6 +30,7 @@ in vec3 normals;
in vec4 colors;
in vec4 elevations;
in vec3 instancePickingColors;
// Custom uniforms
uniform vec2 offset;
Expand Down Expand Up @@ -114,6 +115,9 @@ void main(void) {
vec2 centroidPosition64xyLow = vec2(instancePositionXFP64[1], instancePositionYFP64[1]);
vec3 pos = vec3(project_size(positions.xy + offset) * dotRadius, 0.);
// Set color to be rendered to picking fbo (also used to check for selection highlight).
picking_setPickingColor(instancePickingColors);
vec4 position_commonspace;
gl_Position = project_position_to_clipspace(centroidPosition, centroidPosition64xyLow, pos, position_commonspace);
Expand Down
Expand Up @@ -39,7 +39,7 @@ const defaultProps = {
elevationScale: {type: 'number', min: 0, value: 1},
extruded: true,
fp64: false,
pickable: false, // TODO: add picking support (read from aggregated texture)
pickable: true,

minColor: {type: 'color', value: DEFAULT_MINCOLOR},
maxColor: {type: 'color', value: DEFAULT_MAXCOLOR},
Expand Down Expand Up @@ -87,6 +87,9 @@ export default class GPUGridCellLayer extends Layer {
if (props.elevationBuffer !== oldProps.elevationBuffer) {
this.state.attributeManager.invalidate('elevations');
}
if (props.numInstances !== oldProps.numInstances) {
this.state.attributeManager.invalidate('instancePickingColors');
}
}

_getModel(gl) {
Expand Down
79 changes: 72 additions & 7 deletions modules/aggregation-layers/src/gpu-grid-layer/gpu-grid-layer.js
Expand Up @@ -25,6 +25,7 @@ import GPUGridAggregator from '../utils/gpu-grid-aggregation/gpu-grid-aggregator
import {pointToDensityGridData} from '../utils/gpu-grid-aggregation/grid-aggregation-utils';
import {defaultColorRange, colorRangeToFlatArray} from '../utils/color-utils';
import GPUGridCellLayer from './gpu-grid-cell-layer';
import {pointToDensityGridDataCPU} from './../grid-layer/grid-aggregator';

const MINCOLOR = [0, 0, 0, 255];
const MAXCOLOR = [0, 255, 0, 255];
Expand All @@ -49,7 +50,7 @@ const defaultProps = {
getPosition: {type: 'accessor', value: x => x.position},
extruded: false,
fp64: false,
pickable: false, // TODO: Enable picking with GPU Aggregation
pickable: true,

// Optional material for 'lighting' shader module
material: defaultMaterial,
Expand All @@ -73,8 +74,10 @@ export default class GPUGridLayer extends CompositeLayer {
updateState(opts) {
const aggregationFlags = this.getAggregationFlags(opts);
if (aggregationFlags) {
// project data into grid cells
// aggregate points into grid cells
this.getLayerData(aggregationFlags);
// reset cached CPU Aggregation results (used for picking)
this.setState({gridHash: null});
}
}

Expand Down Expand Up @@ -162,10 +165,73 @@ export default class GPUGridLayer extends CompositeLayer {
this.setState({weights, gridSize, gridOrigin, cellSize, boundingBox});
}

getPickingInfo({info}) {
// TODO: perform picking
return info;
getHashKeyForIndex(index) {
const {gridSize, gridOrigin, cellSize} = this.state;
const yIndex = Math.floor(index / gridSize[0]);
const xIndex = index - yIndex * gridSize[0];
// This will match the index to the hash-key to access aggregation data from CPU aggregation results.
const latIdx = Math.floor(
(yIndex * cellSize[1] + gridOrigin[1] + 90 + cellSize[1] / 2) / cellSize[1]
);
const lonIdx = Math.floor(
(xIndex * cellSize[0] + gridOrigin[0] + 180 + cellSize[0] / 2) / cellSize[0]
);
return `${latIdx}-${lonIdx}`;
}

getPositionForIndex(index) {
const {gridSize, gridOrigin, cellSize} = this.state;
const yIndex = Math.floor(index / gridSize[0]);
const xIndex = index - yIndex * gridSize[0];
const yPos = yIndex * cellSize[1] + gridOrigin[1];
const xPos = xIndex * cellSize[0] + gridOrigin[0];
return [xPos, yPos];
}

getPickingInfo({info, mode}) {
const {index} = info;
const isPicked = info.picked && index > -1;
let object = null;
if (isPicked) {
const {gpuGridAggregator} = this.state;
const position = this.getPositionForIndex(index);
const aggregationResults = gpuGridAggregator.getData();
const colorInfo = GPUGridAggregator.getAggregationData(
Object.assign({pixelIndex: index}, aggregationResults.color)
);
const elevationInfo = GPUGridAggregator.getAggregationData(
Object.assign({pixelIndex: index}, aggregationResults.color)
);

object = {
colorValue: colorInfo.cellWeight,
elevationValue: elevationInfo.cellWeight,
count: colorInfo.cellCount || elevationInfo.cellCount,
position,
totalCount: colorInfo.totalCount || elevationInfo.totalCount
};
if (mode !== 'hover') {
// perform CPU aggregation for full list of points for each cell
const {data, getPosition} = this.props;
let {gridHash} = this.state;
if (!gridHash) {
const cpuAggregation = pointToDensityGridDataCPU(data, this.props.cellSize, getPosition);
gridHash = cpuAggregation.gridHash;
this.setState({gridHash});
}
const key = this.getHashKeyForIndex(index);
const cpuAggregationData = gridHash[key];
Object.assign(object, cpuAggregationData);
}
}

return Object.assign(info, {
picked: Boolean(object),
// override object with picked cell
object
});
}

// for subclassing, override this method to return
// customized sub layer props
getSubLayerProps() {
Expand Down Expand Up @@ -207,8 +273,7 @@ export default class GPUGridLayer extends CompositeLayer {
coverage,
material,
elevationScale,
extruded,
pickable: false
extruded
});
}

Expand Down
3 changes: 2 additions & 1 deletion modules/aggregation-layers/src/grid-layer/grid-aggregator.js
Expand Up @@ -29,11 +29,12 @@ const R_EARTH = 6378000;
* @param {function} getPosition - position accessor
* @returns {object} - grid data, cell dimension
*/
export function pointToDensityGridData(points, cellSize, getPosition) {
export function pointToDensityGridDataCPU(points, cellSize, getPosition) {
const {gridHash, gridOffset} = _pointsToGridHashing(points, cellSize, getPosition);
const layerData = _getGridLayerDataFromGridHash(gridHash, gridOffset);

return {
gridHash,
gridOffset,
layerData
};
Expand Down
4 changes: 2 additions & 2 deletions modules/aggregation-layers/src/grid-layer/grid-layer.js
Expand Up @@ -26,7 +26,7 @@ import BinSorter from '../utils/bin-sorter';
import {defaultColorRange} from '../utils/color-utils';
import {getQuantizeScale, getLinearScale} from '../utils/scale-utils';

import {pointToDensityGridData} from './grid-aggregator';
import {pointToDensityGridDataCPU} from './grid-aggregator';

function nop() {}

Expand Down Expand Up @@ -211,7 +211,7 @@ export default class GridLayer extends CompositeLayer {

getLayerData() {
const {data, cellSize, getPosition} = this.props;
const {layerData} = pointToDensityGridData(data, cellSize, getPosition);
const {layerData} = pointToDensityGridDataCPU(data, cellSize, getPosition);

this.setState({layerData});
this.getSortedBins();
Expand Down
15 changes: 6 additions & 9 deletions modules/aggregation-layers/src/new-grid-layer/new-grid-layer.js
Expand Up @@ -4,7 +4,9 @@ import GPUGridAggregator from '../utils/gpu-grid-aggregation/gpu-grid-aggregator
import GPUGridLayer from '../gpu-grid-layer/gpu-grid-layer';
import GridLayer from '../grid-layer/grid-layer';

const defaultProps = Object.assign({}, GPUGridLayer.defaultProps, GridLayer.defaultProps);
const defaultProps = Object.assign({}, GPUGridLayer.defaultProps, GridLayer.defaultProps, {
pickable: false
});

function sumReducer(accu, cur) {
return accu + cur;
Expand Down Expand Up @@ -58,18 +60,13 @@ function getValueFunc(aggregation, accessor) {
}
}

export default class NewGPULayer extends CompositeLayer {
export default class NewGridLayer extends CompositeLayer {
initializeState() {
this.state = {
useGPUAggregation: true
};
}

getPickingInfo(opts) {
// TODO: implement picking.
return Object.assign({}, opts.info, {picked: false, object: null});
}

updateState({oldProps, props, changeFlags}) {
const newState = {};
newState.useGPUAggregation = this.canUseGPUAggregation(props);
Expand Down Expand Up @@ -161,5 +158,5 @@ export default class NewGPULayer extends CompositeLayer {
}
}

NewGPULayer.layerName = 'NewGPULayer';
NewGPULayer.defaultProps = defaultProps;
NewGridLayer.layerName = 'NewGridLayer';
NewGridLayer.defaultProps = defaultProps;
Expand Up @@ -586,7 +586,7 @@ export default class GPUGridAggregator {
const resourceName = `cpu-result-${id}-${bufferName}`;
result[bufferName] = result[bufferName] || resources[resourceName];
if (result[bufferName]) {
result[bufferName].subData({data});
result[bufferName].setData({data});
} else {
// save resource for garbage collection
resources[resourceName] = new Buffer(gl, data);
Expand Down
Expand Up @@ -226,18 +226,17 @@ function getGPUAggregationParams({boundingBox, cellSize, worldOrigin}) {
// Setup transformation matrix so that every point is in +ve range
const gridTransformMatrix = new Matrix4().translate([-1 * originX, -1 * originY, 0]);

// const cellSize = [gridOffset.xOffset, gridOffset.yOffset];
const gridOrigin = [originX, originY];
const width = xMax - xMin + cellSize[0];
const height = yMax - yMin + cellSize[1];
const width = xMax - originX;
const height = yMax - originY;

const gridSize = [Math.ceil(width / cellSize[0]), Math.ceil(height / cellSize[1])];

return {
gridOrigin,
gridSize,
width,
height,
width: gridSize[0] * cellSize[0],
height: gridSize[1] * cellSize[1],
gridTransformMatrix
};
}
8 changes: 7 additions & 1 deletion modules/main/src/index.js
Expand Up @@ -124,7 +124,13 @@ export {
TextLayer
} from '@deck.gl/layers';

export {ScreenGridLayer, GridLayer, HexagonLayer, ContourLayer} from '@deck.gl/aggregation-layers';
export {
ScreenGridLayer,
GridLayer,
HexagonLayer,
ContourLayer,
_NewGridLayer
} from '@deck.gl/aggregation-layers';

export {
GreatCircleLayer,
Expand Down
6 changes: 3 additions & 3 deletions test/modules/aggregation-layers/grid-aggregator.spec.js
Expand Up @@ -22,15 +22,15 @@ import test from 'tape-catch';

import * as FIXTURES from 'deck.gl-test/data';

import {pointToDensityGridData} from '@deck.gl/aggregation-layers/grid-layer/grid-aggregator';
import {pointToDensityGridDataCPU} from '@deck.gl/aggregation-layers/grid-layer/grid-aggregator';

const getPosition = d => d.COORDINATES;
const iterableData = new Set(FIXTURES.points);
const cellSize = 500;

test('pointToDensityGridData', t => {
test('pointToDensityGridDataCPU', t => {
t.ok(
typeof pointToDensityGridData(iterableData, cellSize, getPosition) === 'object',
typeof pointToDensityGridDataCPU(iterableData, cellSize, getPosition) === 'object',
'should work with iterables'
);
t.end();
Expand Down

0 comments on commit 6fc7ba2

Please sign in to comment.