Merge pull request #13547 from mike-000/render-gutter
Handle gutter in WebGL tile renderer
This commit is contained in:
@@ -420,6 +420,7 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
|
|||||||
const tileLayer = this.getLayer();
|
const tileLayer = this.getLayer();
|
||||||
const tileSource = tileLayer.getRenderSource();
|
const tileSource = tileLayer.getRenderSource();
|
||||||
const tileGrid = tileSource.getTileGridForProjection(viewState.projection);
|
const tileGrid = tileSource.getTileGridForProjection(viewState.projection);
|
||||||
|
const gutter = tileSource.getGutterForProjection(viewState.projection);
|
||||||
const extent = getRenderExtent(frameState, frameState.extent);
|
const extent = getRenderExtent(frameState, frameState.extent);
|
||||||
const z = tileGrid.getZForResolution(
|
const z = tileGrid.getZForResolution(
|
||||||
viewState.resolution,
|
viewState.resolution,
|
||||||
@@ -543,11 +544,13 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
|
|||||||
this.tileTransform_,
|
this.tileTransform_,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
2 / ((frameState.size[0] * tileScale) / tileSize[0]),
|
2 / ((frameState.size[0] * tileScale) / (tileSize[0] + 2 * gutter)),
|
||||||
-2 / ((frameState.size[1] * tileScale) / tileSize[1]),
|
-2 / ((frameState.size[1] * tileScale) / (tileSize[1] + 2 * gutter)),
|
||||||
viewState.rotation,
|
viewState.rotation,
|
||||||
-(centerI - tileCenterI),
|
((tileCenterI - centerI - gutter / tileSize[0]) * tileSize[0]) /
|
||||||
-(centerJ - tileCenterJ)
|
(tileSize[0] + 2 * gutter),
|
||||||
|
((tileCenterJ - centerJ - gutter / tileSize[1]) * tileSize[1]) /
|
||||||
|
(tileSize[1] + 2 * gutter)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.helper.setUniformMatrixValue(
|
this.helper.setUniformMatrixValue(
|
||||||
@@ -599,11 +602,11 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
|
|||||||
this.helper.setUniformFloatValue(Uniforms.DEPTH, depth);
|
this.helper.setUniformFloatValue(Uniforms.DEPTH, depth);
|
||||||
this.helper.setUniformFloatValue(
|
this.helper.setUniformFloatValue(
|
||||||
Uniforms.TEXTURE_PIXEL_WIDTH,
|
Uniforms.TEXTURE_PIXEL_WIDTH,
|
||||||
tileSize[0]
|
tileSize[0] + 2 * gutter
|
||||||
);
|
);
|
||||||
this.helper.setUniformFloatValue(
|
this.helper.setUniformFloatValue(
|
||||||
Uniforms.TEXTURE_PIXEL_HEIGHT,
|
Uniforms.TEXTURE_PIXEL_HEIGHT,
|
||||||
tileSize[1]
|
tileSize[1] + 2 * gutter
|
||||||
);
|
);
|
||||||
this.helper.setUniformFloatValue(
|
this.helper.setUniformFloatValue(
|
||||||
Uniforms.TEXTURE_RESOLUTION,
|
Uniforms.TEXTURE_RESOLUTION,
|
||||||
@@ -611,13 +614,22 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
|
|||||||
);
|
);
|
||||||
this.helper.setUniformFloatValue(
|
this.helper.setUniformFloatValue(
|
||||||
Uniforms.TEXTURE_ORIGIN_X,
|
Uniforms.TEXTURE_ORIGIN_X,
|
||||||
tileOrigin[0] + tileCenterI * tileSize[0] * tileResolution
|
tileOrigin[0] +
|
||||||
|
tileCenterI * tileSize[0] * tileResolution -
|
||||||
|
gutter * tileResolution
|
||||||
);
|
);
|
||||||
this.helper.setUniformFloatValue(
|
this.helper.setUniformFloatValue(
|
||||||
Uniforms.TEXTURE_ORIGIN_Y,
|
Uniforms.TEXTURE_ORIGIN_Y,
|
||||||
tileOrigin[1] - tileCenterJ * tileSize[1] * tileResolution
|
tileOrigin[1] -
|
||||||
|
tileCenterJ * tileSize[1] * tileResolution +
|
||||||
|
gutter * tileResolution
|
||||||
);
|
);
|
||||||
this.helper.setUniformFloatVec4(Uniforms.RENDER_EXTENT, extent);
|
let gutterExtent = extent;
|
||||||
|
if (gutter > 0) {
|
||||||
|
gutterExtent = tileGrid.getTileCoordExtent(tileCoord);
|
||||||
|
getIntersection(gutterExtent, extent, gutterExtent);
|
||||||
|
}
|
||||||
|
this.helper.setUniformFloatVec4(Uniforms.RENDER_EXTENT, gutterExtent);
|
||||||
this.helper.setUniformFloatValue(
|
this.helper.setUniformFloatValue(
|
||||||
Uniforms.RESOLUTION,
|
Uniforms.RESOLUTION,
|
||||||
viewState.resolution
|
viewState.resolution
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ import {toPromise} from '../functions.js';
|
|||||||
* @property {number} [maxZoom=42] Optional max zoom level. Not used if `tileGrid` is provided.
|
* @property {number} [maxZoom=42] Optional max zoom level. Not used if `tileGrid` is provided.
|
||||||
* @property {number} [minZoom=0] Optional min zoom level. Not used if `tileGrid` is provided.
|
* @property {number} [minZoom=0] Optional min zoom level. Not used if `tileGrid` is provided.
|
||||||
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The pixel width and height of the tiles.
|
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The pixel width and height of the tiles.
|
||||||
|
* @property {number} [gutter=0] The size in pixels of the gutter around data tiles to ignore.
|
||||||
|
* This allows artifacts of rendering at tile edges to be ignored.
|
||||||
|
* Supported data should be wider and taller than the tile size by a value of `2 x gutter`.
|
||||||
* @property {number} [maxResolution] Optional tile grid resolution at level zero. Not used if `tileGrid` is provided.
|
* @property {number} [maxResolution] Optional tile grid resolution at level zero. Not used if `tileGrid` is provided.
|
||||||
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Tile projection.
|
* @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Tile projection.
|
||||||
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
* @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid.
|
||||||
@@ -80,6 +83,12 @@ class DataTileSource extends TileSource {
|
|||||||
interpolate: options.interpolate,
|
interpolate: options.interpolate,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {!Object<string, boolean>}
|
* @type {!Object<string, boolean>}
|
||||||
@@ -99,6 +108,14 @@ class DataTileSource extends TileSource {
|
|||||||
this.bandCount = options.bandCount === undefined ? 4 : options.bandCount; // assume RGBA if undefined
|
this.bandCount = options.bandCount === undefined ? 4 : options.bandCount; // assume RGBA if undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../proj/Projection.js").default} projection Projection.
|
||||||
|
* @return {number} Gutter.
|
||||||
|
*/
|
||||||
|
getGutterForProjection(projection) {
|
||||||
|
return this.gutter_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Loader} loader The data loader.
|
* @param {Loader} loader The data loader.
|
||||||
* @protected
|
* @protected
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ import {createXYZ, extentFromProjection} from '../tilegrid.js';
|
|||||||
* should be set to `2`.
|
* should be set to `2`.
|
||||||
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The tile size used by the tile service.
|
* @property {number|import("../size.js").Size} [tileSize=[256, 256]] The tile size used by the tile service.
|
||||||
* Not used if `tileGrid` is provided.
|
* Not used if `tileGrid` is provided.
|
||||||
|
* @property {number} [gutter=0] The size in pixels of the gutter around image tiles to ignore.
|
||||||
|
* This allows artifacts of rendering at tile edges to be ignored.
|
||||||
|
* Supported images should be wider and taller than the tile size by a value of `2 x gutter`.
|
||||||
* @property {import("../Tile.js").UrlFunction} [tileUrlFunction] Optional function to get
|
* @property {import("../Tile.js").UrlFunction} [tileUrlFunction] Optional function to get
|
||||||
* tile URL given a tile coordinate and the projection.
|
* tile URL given a tile coordinate and the projection.
|
||||||
* Required if `url` or `urls` are not provided.
|
* Required if `url` or `urls` are not provided.
|
||||||
@@ -114,6 +117,19 @@ class XYZ extends TileImage {
|
|||||||
attributionsCollapsible: options.attributionsCollapsible,
|
attributionsCollapsible: options.attributionsCollapsible,
|
||||||
zDirection: options.zDirection,
|
zDirection: options.zDirection,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number} Gutter.
|
||||||
|
*/
|
||||||
|
getGutter() {
|
||||||
|
return this.gutter_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-44
@@ -10,9 +10,6 @@ import ReprojTile from '../reproj/Tile.js';
|
|||||||
import TileState from '../TileState.js';
|
import TileState from '../TileState.js';
|
||||||
import WebGLArrayBuffer from './Buffer.js';
|
import WebGLArrayBuffer from './Buffer.js';
|
||||||
import {ARRAY_BUFFER, STATIC_DRAW} from '../webgl.js';
|
import {ARRAY_BUFFER, STATIC_DRAW} from '../webgl.js';
|
||||||
import {IMAGE_SMOOTHING_DISABLED} from '../renderer/canvas/common.js';
|
|
||||||
import {assign} from '../obj.js';
|
|
||||||
import {createCanvasContext2D} from '../dom.js';
|
|
||||||
import {toSize} from '../size.js';
|
import {toSize} from '../size.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,38 +240,16 @@ class TileTexture extends EventTarget {
|
|||||||
const tile = this.tile;
|
const tile = this.tile;
|
||||||
|
|
||||||
if (tile instanceof ImageTile || tile instanceof ReprojTile) {
|
if (tile instanceof ImageTile || tile instanceof ReprojTile) {
|
||||||
let image = tile.getImage();
|
|
||||||
if (this.gutter_ !== 0) {
|
|
||||||
const gutter = this.tilePixelRatio_ * this.gutter_;
|
|
||||||
const width = Math.round(image.width - 2 * gutter);
|
|
||||||
const height = Math.round(image.height - 2 * gutter);
|
|
||||||
const context = createCanvasContext2D(width, height);
|
|
||||||
if (!tile.interpolate) {
|
|
||||||
assign(context, IMAGE_SMOOTHING_DISABLED);
|
|
||||||
}
|
|
||||||
context.drawImage(
|
|
||||||
image,
|
|
||||||
gutter,
|
|
||||||
gutter,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
width,
|
|
||||||
height
|
|
||||||
);
|
|
||||||
image = context.canvas;
|
|
||||||
}
|
|
||||||
const texture = gl.createTexture();
|
const texture = gl.createTexture();
|
||||||
this.textures.push(texture);
|
this.textures.push(texture);
|
||||||
this.bandCount = 4;
|
this.bandCount = 4;
|
||||||
uploadImageTexture(gl, texture, image, tile.interpolate);
|
uploadImageTexture(gl, texture, tile.getImage(), tile.interpolate);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pixelSize = [
|
const pixelSize = [
|
||||||
this.size[0] * this.tilePixelRatio_,
|
(this.size[0] + 2 * this.gutter_) * this.tilePixelRatio_,
|
||||||
this.size[1] * this.tilePixelRatio_,
|
(this.size[1] + 2 * this.gutter_) * this.tilePixelRatio_,
|
||||||
];
|
];
|
||||||
const data = tile.getData();
|
const data = tile.getData();
|
||||||
const isFloat = data instanceof Float32Array;
|
const isFloat = data instanceof Float32Array;
|
||||||
@@ -373,14 +348,19 @@ class TileTexture extends EventTarget {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
col = Math.floor(this.tilePixelRatio_ * col);
|
const gutter = Math.round(this.tilePixelRatio_ * this.gutter_);
|
||||||
row = Math.floor(this.tilePixelRatio_ * row);
|
col = Math.floor(this.tilePixelRatio_ * col) + gutter;
|
||||||
|
row = Math.floor(this.tilePixelRatio_ * row) + gutter;
|
||||||
|
|
||||||
if (this.tile instanceof DataTile) {
|
if (this.tile instanceof DataTile) {
|
||||||
const data = this.tile.getData();
|
const data = this.tile.getData();
|
||||||
const pixelsPerRow = Math.floor(this.tilePixelRatio_ * this.size[0]);
|
let size = this.size;
|
||||||
|
if (gutter > 0) {
|
||||||
|
size = [size[0] + 2 * this.gutter_, size[1] + 2 * this.gutter_];
|
||||||
|
}
|
||||||
|
const pixelsPerRow = Math.floor(this.tilePixelRatio_ * size[0]);
|
||||||
if (data instanceof DataView) {
|
if (data instanceof DataView) {
|
||||||
const bytesPerPixel = data.byteLength / (this.size[0] * this.size[1]);
|
const bytesPerPixel = data.byteLength / (size[0] * size[1]);
|
||||||
const offset = row * pixelsPerRow * bytesPerPixel + col * bytesPerPixel;
|
const offset = row * pixelsPerRow * bytesPerPixel + col * bytesPerPixel;
|
||||||
const buffer = data.buffer.slice(offset, offset + bytesPerPixel);
|
const buffer = data.buffer.slice(offset, offset + bytesPerPixel);
|
||||||
return new DataView(buffer);
|
return new DataView(buffer);
|
||||||
@@ -397,19 +377,8 @@ class TileTexture extends EventTarget {
|
|||||||
|
|
||||||
let data;
|
let data;
|
||||||
const image = this.tile.getImage();
|
const image = this.tile.getImage();
|
||||||
const gutter = Math.round(this.tilePixelRatio_ * this.gutter_);
|
|
||||||
try {
|
try {
|
||||||
pixelContext.drawImage(
|
pixelContext.drawImage(image, col, row, 1, 1, 0, 0, 1, 1);
|
||||||
image,
|
|
||||||
col + gutter,
|
|
||||||
row + gutter,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
data = pixelContext.getImageData(0, 0, 1, 1).data;
|
data = pixelContext.getImageData(0, 0, 1, 1).data;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
pixelContext = null;
|
pixelContext = null;
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,33 @@
|
|||||||
|
import DataTile from '../../../../src/ol/source/DataTile.js';
|
||||||
|
import Map from '../../../../src/ol/Map.js';
|
||||||
|
import TileLayer from '../../../../src/ol/layer/WebGLTile.js';
|
||||||
|
import View from '../../../../src/ol/View.js';
|
||||||
|
|
||||||
|
const size = 260;
|
||||||
|
|
||||||
|
const data = new Uint8Array(size * size);
|
||||||
|
for (let row = 0; row < size; ++row) {
|
||||||
|
for (let col = 0; col < size; ++col) {
|
||||||
|
data[row * size + col] = (row + col) % 2 === 0 ? 255 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new Map({
|
||||||
|
target: 'map',
|
||||||
|
layers: [
|
||||||
|
new TileLayer({
|
||||||
|
source: new DataTile({
|
||||||
|
maxZoom: 1,
|
||||||
|
interpolate: true,
|
||||||
|
loader: () => data,
|
||||||
|
gutter: 2,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 5,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
render();
|
||||||
Reference in New Issue
Block a user