WebGLPointsLayer wrapX support - partially addressing #11131
WebGLPointsLayer renderFrame and renderHitDetection will now draw multiple worlds if the source and projection support wrapX. Hit detection needs additional improvement. It stops working after more than one wrap around the world. If 0 is the middle world, then the hit detection works for worlds -1, 0, and -1, but not for worlds > 2 or < -2. The example has hit detection enabled, demonstrated with a colour change on hover for the circle styles. When moving the mouse, the hit detection is unreliable and flickers on/off. This needs improvement. The webgl-points renderer test has been updated.
This commit is contained in:
@@ -9,6 +9,7 @@ import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js';
|
||||
const vectorSource = new Vector({
|
||||
url: 'data/geojson/world-cities.geojson',
|
||||
format: new GeoJSON(),
|
||||
wrapX: true,
|
||||
});
|
||||
|
||||
const predefinedStyles = {
|
||||
@@ -79,7 +80,7 @@ const predefinedStyles = {
|
||||
2000000,
|
||||
28,
|
||||
],
|
||||
color: '#006688',
|
||||
color: ['match', ['get', 'hover'], 1, '#ff3f3f', '#006688'],
|
||||
rotateWithView: false,
|
||||
offset: [0, 0],
|
||||
opacity: [
|
||||
@@ -97,7 +98,7 @@ const predefinedStyles = {
|
||||
symbol: {
|
||||
symbolType: 'circle',
|
||||
size: ['interpolate', ['exponential', 2.5], ['zoom'], 2, 1, 14, 32],
|
||||
color: '#240572',
|
||||
color: ['match', ['get', 'hover'], 1, '#ff3f3f', '#006688'],
|
||||
offset: [0, 0],
|
||||
opacity: 0.95,
|
||||
},
|
||||
@@ -160,12 +161,27 @@ const map = new Map({
|
||||
|
||||
let literalStyle;
|
||||
let pointsLayer;
|
||||
|
||||
let selected = null;
|
||||
|
||||
map.on('pointermove', function (ev) {
|
||||
if (selected !== null) {
|
||||
selected.set('hover', 0);
|
||||
selected = null;
|
||||
}
|
||||
|
||||
map.forEachFeatureAtPixel(ev.pixel, function (feature) {
|
||||
feature.set('hover', 1);
|
||||
selected = feature;
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
function refreshLayer(newStyle) {
|
||||
const previousLayer = pointsLayer;
|
||||
pointsLayer = new WebGLPointsLayer({
|
||||
source: vectorSource,
|
||||
style: newStyle,
|
||||
disableHitDetection: true,
|
||||
});
|
||||
map.addLayer(pointsLayer);
|
||||
|
||||
|
||||
@@ -19,9 +19,10 @@ import {
|
||||
create as createTransform,
|
||||
makeInverse as makeInverseTransform,
|
||||
multiply as multiplyTransform,
|
||||
translate as translateTransform,
|
||||
} from '../../transform.js';
|
||||
import {assert} from '../../asserts.js';
|
||||
import {buffer, createEmpty, equals} from '../../extent.js';
|
||||
import {buffer, createEmpty, equals, getWidth} from '../../extent.js';
|
||||
import {create as createWebGLWorker} from '../../worker/webgl.js';
|
||||
import {getUid} from '../../util.js';
|
||||
import {listen, unlistenByKey} from '../../events.js';
|
||||
@@ -461,8 +462,36 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
const gl = this.helper.getGL();
|
||||
this.preRender(gl, frameState);
|
||||
|
||||
const projection = frameState.viewState.projection;
|
||||
const layer = this.getLayer();
|
||||
const vectorSource = layer.getSource();
|
||||
// FIXME fix hit detection isn't reliable when rendering multiple worlds
|
||||
const multiWorld = vectorSource.getWrapX() && projection.canWrapX();
|
||||
const projectionExtent = projection.getExtent();
|
||||
|
||||
const extent = frameState.extent;
|
||||
const worldWidth = multiWorld ? getWidth(projectionExtent) : null;
|
||||
const endWorld = multiWorld
|
||||
? Math.ceil((extent[2] - projectionExtent[2]) / worldWidth) + 1
|
||||
: 1;
|
||||
|
||||
const startWorld = multiWorld
|
||||
? Math.floor((extent[0] - projectionExtent[0]) / worldWidth)
|
||||
: 0;
|
||||
|
||||
let world = startWorld;
|
||||
const renderCount = this.indicesBuffer_.getSize();
|
||||
this.helper.drawElements(0, renderCount);
|
||||
|
||||
do {
|
||||
// apply the current projection transform with the invert of the one used to fill buffers
|
||||
this.helper.makeProjectionTransform(frameState, this.currentTransform_);
|
||||
translateTransform(this.currentTransform_, world * worldWidth, 0);
|
||||
multiplyTransform(this.currentTransform_, this.invertRenderTransform_);
|
||||
this.helper.applyUniforms(frameState);
|
||||
|
||||
this.helper.drawElements(0, renderCount);
|
||||
} while (++world < endWorld);
|
||||
|
||||
this.helper.finalizeDraw(
|
||||
frameState,
|
||||
this.dispatchPreComposeEvent,
|
||||
@@ -471,7 +500,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
const canvas = this.helper.getCanvas();
|
||||
|
||||
if (this.hitDetectionEnabled_) {
|
||||
this.renderHitDetection(frameState);
|
||||
this.renderHitDetection(frameState, startWorld, endWorld, worldWidth);
|
||||
this.hitRenderTarget_.clearCachedData();
|
||||
}
|
||||
|
||||
@@ -512,17 +541,12 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.previousExtent_ = frameState.extent.slice();
|
||||
}
|
||||
|
||||
// apply the current projection transform with the invert of the one used to fill buffers
|
||||
this.helper.makeProjectionTransform(frameState, this.currentTransform_);
|
||||
multiplyTransform(this.currentTransform_, this.invertRenderTransform_);
|
||||
|
||||
this.helper.useProgram(this.program_);
|
||||
this.helper.prepareDraw(frameState);
|
||||
|
||||
// write new data
|
||||
this.helper.bindBuffer(this.verticesBuffer_);
|
||||
this.helper.bindBuffer(this.indicesBuffer_);
|
||||
|
||||
this.helper.enableAttributes(this.attributes);
|
||||
|
||||
return true;
|
||||
@@ -686,13 +710,18 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
/**
|
||||
* Render the hit detection data to the corresponding render target
|
||||
* @param {import("../../PluggableMap.js").FrameState} frameState current frame state
|
||||
* @param {number} startWorld the world to render in the first iteration
|
||||
* @param {number} endWorld the last world to render
|
||||
* @param {number} worldWidth the width of the worlds being rendered
|
||||
*/
|
||||
renderHitDetection(frameState) {
|
||||
renderHitDetection(frameState, startWorld, endWorld, worldWidth) {
|
||||
// skip render entirely if vertex buffers not ready/generated yet
|
||||
if (!this.hitVerticesBuffer_.getSize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let world = startWorld;
|
||||
|
||||
this.hitRenderTarget_.setSize([
|
||||
Math.floor(frameState.size[0] / 2),
|
||||
Math.floor(frameState.size[1] / 2),
|
||||
@@ -707,11 +736,17 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
|
||||
this.helper.bindBuffer(this.hitVerticesBuffer_);
|
||||
this.helper.bindBuffer(this.indicesBuffer_);
|
||||
|
||||
this.helper.enableAttributes(this.hitDetectionAttributes);
|
||||
|
||||
const renderCount = this.indicesBuffer_.getSize();
|
||||
this.helper.drawElements(0, renderCount);
|
||||
do {
|
||||
this.helper.makeProjectionTransform(frameState, this.currentTransform_);
|
||||
translateTransform(this.currentTransform_, world * worldWidth, 0);
|
||||
multiplyTransform(this.currentTransform_, this.invertRenderTransform_);
|
||||
this.helper.applyUniforms(frameState);
|
||||
|
||||
const renderCount = this.indicesBuffer_.getSize();
|
||||
this.helper.drawElements(0, renderCount);
|
||||
} while (++world < endWorld);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -678,7 +678,6 @@ class WebGLHelper extends Disposable {
|
||||
/**
|
||||
* Sets the default matrix uniforms for a given frame state. This is called internally in `prepareDraw`.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @private
|
||||
*/
|
||||
applyFrameState(frameState) {
|
||||
const size = frameState.size;
|
||||
@@ -715,7 +714,6 @@ class WebGLHelper extends Disposable {
|
||||
/**
|
||||
* Sets the custom uniforms based on what was given in the constructor. This is called internally in `prepareDraw`.
|
||||
* @param {import("../PluggableMap.js").FrameState} frameState Frame state.
|
||||
* @private
|
||||
*/
|
||||
applyUniforms(frameState) {
|
||||
const gl = this.getGL();
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 98 KiB |
Reference in New Issue
Block a user