Add a new WebGLPointsLayer type using the shader builder utilities
This required adding a `a_index` attribute in the points layer renderer to be able to make the precomputed shaders to work.
This commit is contained in:
@@ -240,3 +240,7 @@ Support for the `OES_element_index_uint` WebGL extension is mandatory for WebGL
|
||||
### 64
|
||||
|
||||
Layer opacity must be a number.
|
||||
|
||||
### 65
|
||||
|
||||
A symbol literal representation must be defined on the style supplied to a `WebGLPointsLayer` instance.
|
||||
|
||||
69
src/ol/layer/WebGLPoints.js
Normal file
69
src/ol/layer/WebGLPoints.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @module ol/layer/WebGLPoints
|
||||
*/
|
||||
import VectorLayer from './Vector.js';
|
||||
import {assign} from '../obj.js';
|
||||
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
|
||||
import {getSymbolFragmentShader, getSymbolVertexShader} from '../webgl/ShaderBuilder.js';
|
||||
import {assert} from '../asserts.js';
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import('../style/LiteralStyle.js').LiteralStyle} literalStyle Literal style to apply to the layer features.
|
||||
* @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
|
||||
* @property {number} [opacity=1] Opacity (0, 1).
|
||||
* @property {boolean} [visible=true] Visibility.
|
||||
* @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering. The layer will not be
|
||||
* rendered outside of this extent.
|
||||
* @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers
|
||||
* will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed
|
||||
* for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()`
|
||||
* method was used.
|
||||
* @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {import("../source/Vector.js").default} [source] Source.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer optimized for rendering large point datasets.
|
||||
* Note that any property set in the options is set as a {@link module:ol/Object~BaseObject}
|
||||
* property on the layer object; for example, setting `title: 'My Title'` in the
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
*
|
||||
* @fires import("../render/Event.js").RenderEvent
|
||||
* @api
|
||||
*/
|
||||
class WebGLPointsLayer extends VectorLayer {
|
||||
/**
|
||||
* @param {Options} options Options.
|
||||
*/
|
||||
constructor(options) {
|
||||
const baseOptions = assign({}, options);
|
||||
|
||||
super(baseOptions);
|
||||
|
||||
/**
|
||||
* @type {import('../style/LiteralStyle.js').LiteralStyle}
|
||||
*/
|
||||
this.literalStyle = options.literalStyle;
|
||||
|
||||
assert(this.literalStyle.symbol !== undefined, 65);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
createRenderer() {
|
||||
return new WebGLPointsLayerRenderer(this, {
|
||||
vertexShader: getSymbolVertexShader(this.literalStyle.symbol),
|
||||
fragmentShader: getSymbolFragmentShader()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default WebGLPointsLayer;
|
||||
@@ -123,9 +123,9 @@ const tmpArray_ = [];
|
||||
const bufferPositions_ = {vertexPosition: 0, indexPosition: 0};
|
||||
|
||||
export const POINT_INSTRUCTIONS_COUNT = 13;
|
||||
export const POINT_VERTEX_STRIDE = 12;
|
||||
export const POINT_VERTEX_STRIDE = 13;
|
||||
|
||||
function writePointVertex(buffer, pos, x, y, offsetX, offsetY, u, v, opacity, rotateWithView, red, green, blue, alpha) {
|
||||
function writePointVertex(buffer, pos, x, y, offsetX, offsetY, u, v, opacity, rotateWithView, red, green, blue, alpha, index) {
|
||||
buffer[pos + 0] = x;
|
||||
buffer[pos + 1] = y;
|
||||
buffer[pos + 2] = offsetX;
|
||||
@@ -138,6 +138,7 @@ function writePointVertex(buffer, pos, x, y, offsetX, offsetY, u, v, opacity, ro
|
||||
buffer[pos + 9] = green;
|
||||
buffer[pos + 10] = blue;
|
||||
buffer[pos + 11] = alpha;
|
||||
buffer[pos + 12] = index;
|
||||
}
|
||||
|
||||
function writeCustomAttrs(buffer, pos, customAttrs) {
|
||||
@@ -202,19 +203,19 @@ export function writePointFeatureToBuffers(instructions, elementIndex, vertexBuf
|
||||
const baseIndex = vPos / stride;
|
||||
|
||||
// push vertices for each of the four quad corners (first standard then custom attributes)
|
||||
writePointVertex(vertexBuffer, vPos, x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha);
|
||||
writePointVertex(vertexBuffer, vPos, x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, red, green, blue, alpha, 0);
|
||||
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
|
||||
vPos += stride;
|
||||
|
||||
writePointVertex(vertexBuffer, vPos, x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha);
|
||||
writePointVertex(vertexBuffer, vPos, x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, red, green, blue, alpha, 1);
|
||||
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
|
||||
vPos += stride;
|
||||
|
||||
writePointVertex(vertexBuffer, vPos, x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha);
|
||||
writePointVertex(vertexBuffer, vPos, x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, red, green, blue, alpha, 2);
|
||||
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
|
||||
vPos += stride;
|
||||
|
||||
writePointVertex(vertexBuffer, vPos, x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha);
|
||||
writePointVertex(vertexBuffer, vPos, x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, red, green, blue, alpha, 3);
|
||||
writeCustomAttrs(vertexBuffer, vPos + baseStride, customAttrs);
|
||||
vPos += stride;
|
||||
|
||||
|
||||
@@ -408,6 +408,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.helper.enableAttributeArray(DefaultAttrib.OPACITY, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 6);
|
||||
this.helper.enableAttributeArray(DefaultAttrib.ROTATE_WITH_VIEW, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 7);
|
||||
this.helper.enableAttributeArray(DefaultAttrib.COLOR, 4, FLOAT, bytesPerFloat * stride, bytesPerFloat * 8);
|
||||
this.helper.enableAttributeArray('a_index', 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 12);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -568,6 +569,7 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.helper.enableAttributeArray(DefaultAttrib.OPACITY, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 6);
|
||||
this.helper.enableAttributeArray(DefaultAttrib.ROTATE_WITH_VIEW, 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 7);
|
||||
this.helper.enableAttributeArray(DefaultAttrib.COLOR, 4, FLOAT, bytesPerFloat * stride, bytesPerFloat * 8);
|
||||
this.helper.enableAttributeArray('a_index', 1, FLOAT, bytesPerFloat * stride, bytesPerFloat * 12);
|
||||
|
||||
const renderCount = this.indicesBuffer_.getSize();
|
||||
this.helper.drawElements(0, renderCount);
|
||||
|
||||
56
src/ol/style/LiteralStyle.js
Normal file
56
src/ol/style/LiteralStyle.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Literal Style objects differ from standard styles in that they cannot
|
||||
* be functions and are made up of simple objects instead of classes.
|
||||
* @module ol/style/LiteralStyle
|
||||
*/
|
||||
|
||||
/**
|
||||
* Here are a few samples of literal style objects:
|
||||
* ```js
|
||||
* const style = {
|
||||
* symbol: {
|
||||
* symbolType: 'circle',
|
||||
* size: 8,
|
||||
* color: '#33AAFF',
|
||||
* opacity: 0.9
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* const style = {
|
||||
* symbol: {
|
||||
* symbolType: 'image',
|
||||
* offset: [0, 12],
|
||||
* size: [4, 8],
|
||||
* src: '../static/exclamation-mark.png'
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @typedef {Object} LiteralStyle
|
||||
* @property {LiteralSymbolStyle} [symbol] Symbol representation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
export const SymbolType = {
|
||||
CIRCLE: 'circle',
|
||||
SQUARE: 'square',
|
||||
TRIANGLE: 'triangle',
|
||||
IMAGE: 'image'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} LiteralSymbolStyle
|
||||
* @property {number|Array.<number, number>} size Size, mandatory.
|
||||
* @property {SymbolType} symbolType Symbol type to use, either a regular shape or an image.
|
||||
* @property {string} [src] Path to the image to be used for the symbol. Only required with `symbolType: 'image'`.
|
||||
* @property {import("../color.js").Color|string} [color='#FFFFFF'] Color used for the representation (either fill, line or symbol).
|
||||
* @property {number} [opacity=0] Opacity.
|
||||
* @property {Array.<number, number>} [offset] Offset on X and Y axis for symbols. If not specified, the symbol will be centered.
|
||||
* @property {Array.<number, number, number, number>} [textureCoord] Texture coordinates. If not specified, the whole texture will be used (range for 0 to 1 on both axes).
|
||||
* @property {boolean} [rotateWithView=false] Specify whether the symbol must rotate with the view or stay upwards.
|
||||
*/
|
||||
@@ -16,17 +16,8 @@ export function formatNumber(v) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SymbolShaderParameters
|
||||
* @property {number|Array.<number, number>} size Size.
|
||||
* @property {boolean} [rotateWithView] Rotate with view.
|
||||
* @property {Array.<number, number>} [offset] Offset.
|
||||
* @property {Array.<number, number, number, number>} [textureCoord] Texture coordinates: u0, v0, u1, v1.
|
||||
* @property {number} [opacity] Opacity.
|
||||
* @property {import("../color.js").Color|string} [color] Color.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates a symbol vertex shader, i.e. a shader intended to be used on point geometries.
|
||||
* Generates a symbol vertex shader from a literal style,
|
||||
* intended to be used on point geometries.
|
||||
*
|
||||
* Expected the following attributes to be present in the attribute array:
|
||||
* `vec2 a_position`, `float a_index` (being the index of the vertex in the quad, 0 to 3).
|
||||
@@ -34,7 +25,7 @@ export function formatNumber(v) {
|
||||
* Transmits the following varyings to the fragment shader:
|
||||
* `vec2 v_texCoord`, `float v_opacity`, `vec4 v_color`
|
||||
*
|
||||
* @param {SymbolShaderParameters} parameters Parameters for the shader.
|
||||
* @param {import('../style/LiteralStyle.js').LiteralSymbolStyle} parameters Parameters for the shader.
|
||||
* @returns {string} The full shader as a string.
|
||||
*/
|
||||
export function getSymbolVertexShader(parameters) {
|
||||
@@ -82,7 +73,7 @@ void main(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a symbol fragment shader, i.e. a shader intended to be used on point geometries.
|
||||
* Generates a symbol fragment shader intended to be used on point geometries.
|
||||
*
|
||||
* Expected the following varyings to be transmitted by the vertex shader:
|
||||
* `vec2 v_texCoord`, `float v_opacity`, `vec4 v_color`
|
||||
|
||||
Reference in New Issue
Block a user