From 0acfd7ab59367de7300dc125449baa623892f8af Mon Sep 17 00:00:00 2001 From: Olivier Guyot Date: Thu, 27 Dec 2018 21:39:00 +0100 Subject: [PATCH] WebGL points / Added a color attribute --- src/ol/renderer/webgl/PointsLayer.js | 61 +++++++++++++++++++++------- src/ol/webgl/Helper.js | 3 +- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/ol/renderer/webgl/PointsLayer.js b/src/ol/renderer/webgl/PointsLayer.js index 02a69798c3..18e1e8af00 100644 --- a/src/ol/renderer/webgl/PointsLayer.js +++ b/src/ol/renderer/webgl/PointsLayer.js @@ -14,6 +14,7 @@ const VERTEX_SHADER = ` attribute float a_rotateWithView; attribute vec2 a_offsets; attribute float a_opacity; + attribute vec4 a_color; uniform mat4 u_projectionMatrix; uniform mat4 u_offsetScaleMatrix; @@ -21,6 +22,7 @@ const VERTEX_SHADER = ` varying vec2 v_texCoord; varying float v_opacity; + varying vec4 v_color; void main(void) { mat4 offsetMatrix = u_offsetScaleMatrix; @@ -31,6 +33,7 @@ const VERTEX_SHADER = ` gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; v_texCoord = a_texCoord; v_opacity = a_opacity; + v_color = a_color; }`; const FRAGMENT_SHADER = ` @@ -38,14 +41,15 @@ const FRAGMENT_SHADER = ` varying vec2 v_texCoord; varying float v_opacity; + varying vec4 v_color; void main(void) { - gl_FragColor.rgb = vec3(1.0, 1.0, 1.0); - float alpha = v_opacity; - if (alpha == 0.0) { + if (v_opacity == 0.0) { discard; } - gl_FragColor.a = alpha; + gl_FragColor = v_color; + gl_FragColor.a *= v_opacity; + gl_FragColor.rgb *= gl_FragColor.a; }`; /** @@ -66,9 +70,15 @@ const FRAGMENT_SHADER = ` * The second argument is 0 for `x` component and 1 for `y`. * @property {function(import("../../Feature").default, number):number} [texCoordCallback] Will be called on every feature in the * source to compute the texture coordinates of each corner of the quad. This is only done on source change. - * The second argument is 0 for `u0` component, 1 or `v0`, 2 for `u1`, and 3 for `v1`. + * The second argument is 0 for `u0` component, 1 for `v0`, 2 for `u1`, and 3 for `v1`. + * @property {function(import("../../Feature").default, number, number):number} [colorCallback] Will be called on every feature in the + * source to compute the color of each corner of the quad. This is only done on source change. + * The second argument is 0 for bottom left, 1 for bottom right, 2 for top right and 3 for top left + * The third argument is 0 for red, 1 for green, 2 for blue and 3 for alpha + * The return value should be between 0 and 1. * @property {function(import("../../Feature").default):number} [opacityCallback] Will be called on every feature in the * source to compute the opacity of the quad on screen (from 0 to 1). This is only done on source change. + * Note: this is multiplied with the color of the point which can also have an alpha value < 1. * @property {function(import("../../Feature").default):boolean} [rotateWithViewCallback] Will be called on every feature in the * source to compute whether the quad on screen must stay upwards (`false`) or follow the view rotation (`true`). * This is only done on source change. @@ -183,6 +193,9 @@ class WebGLPointsLayerRenderer extends LayerRenderer { this.texCoordCallback_ = options.texCoordCallback || function(feature, index) { return index < 2 ? 0 : 1; }; + this.colorCallback_ = options.colorCallback || function(feature, index, component) { + return 1; + }; this.rotateWithViewCallback_ = options.rotateWithViewCallback || function() { return false; }; @@ -218,6 +231,8 @@ class WebGLPointsLayerRenderer extends LayerRenderer { const vectorLayer = /** @type {import("../../layer/Vector.js").default} */ (this.getLayer()); const vectorSource = /** @type {import("../../source/Vector.js").default} */ (vectorLayer.getSource()); + const stride = 12; + this.helper_.prepareDraw(frameState); if (this.sourceRevision_ < vectorSource.getRevision()) { @@ -242,14 +257,29 @@ class WebGLPointsLayerRenderer extends LayerRenderer { const size = this.sizeCallback_(feature); const opacity = this.opacityCallback_(feature); const rotateWithView = this.rotateWithViewCallback_(feature) ? 1 : 0; - const stride = 8; + const v0_r = this.colorCallback_(feature, 0, 0); + const v0_g = this.colorCallback_(feature, 0, 1); + const v0_b = this.colorCallback_(feature, 0, 2); + const v0_a = this.colorCallback_(feature, 0, 3); + const v1_r = this.colorCallback_(feature, 1, 0); + const v1_g = this.colorCallback_(feature, 1, 1); + const v1_b = this.colorCallback_(feature, 1, 2); + const v1_a = this.colorCallback_(feature, 1, 3); + const v2_r = this.colorCallback_(feature, 2, 0); + const v2_g = this.colorCallback_(feature, 2, 1); + const v2_b = this.colorCallback_(feature, 2, 2); + const v2_a = this.colorCallback_(feature, 2, 3); + const v3_r = this.colorCallback_(feature, 3, 0); + const v3_g = this.colorCallback_(feature, 3, 1); + const v3_b = this.colorCallback_(feature, 3, 2); + const v3_a = this.colorCallback_(feature, 3, 3); const baseIndex = this.verticesBuffer_.getArray().length / stride; this.verticesBuffer_.getArray().push( - x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, - x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, - x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, - x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView + x, y, -size / 2, -size / 2, u0, v0, opacity, rotateWithView, v0_r, v0_g, v0_b, v0_a, + x, y, +size / 2, -size / 2, u1, v0, opacity, rotateWithView, v1_r, v1_g, v1_b, v1_a, + x, y, +size / 2, +size / 2, u1, v1, opacity, rotateWithView, v2_r, v2_g, v2_b, v2_a, + x, y, -size / 2, +size / 2, u0, v1, opacity, rotateWithView, v3_r, v3_g, v3_b, v3_a ); this.indicesBuffer_.getArray().push( baseIndex, baseIndex + 1, baseIndex + 3, @@ -263,11 +293,12 @@ class WebGLPointsLayerRenderer extends LayerRenderer { this.helper_.bindBuffer(ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); const bytesPerFloat = Float32Array.BYTES_PER_ELEMENT; - this.helper_.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * 8, 0); - this.helper_.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * 8, bytesPerFloat * 2); - this.helper_.enableAttributeArray(DefaultAttrib.TEX_COORD, 2, FLOAT, bytesPerFloat * 8, bytesPerFloat * 4); - this.helper_.enableAttributeArray(DefaultAttrib.OPACITY, 1, FLOAT, bytesPerFloat * 8, bytesPerFloat * 6); - this.helper_.enableAttributeArray(DefaultAttrib.ROTATE_WITH_VIEW, 1, FLOAT, bytesPerFloat * 8, bytesPerFloat * 7); + this.helper_.enableAttributeArray(DefaultAttrib.POSITION, 2, FLOAT, bytesPerFloat * stride, 0); + this.helper_.enableAttributeArray(DefaultAttrib.OFFSETS, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 2); + this.helper_.enableAttributeArray(DefaultAttrib.TEX_COORD, 2, FLOAT, bytesPerFloat * stride, bytesPerFloat * 4); + 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); return true; } diff --git a/src/ol/webgl/Helper.js b/src/ol/webgl/Helper.js index af5daa0fe7..14d19d5e3f 100644 --- a/src/ol/webgl/Helper.js +++ b/src/ol/webgl/Helper.js @@ -56,7 +56,8 @@ export const DefaultAttrib = { TEX_COORD: 'a_texCoord', OPACITY: 'a_opacity', ROTATE_WITH_VIEW: 'a_rotateWithView', - OFFSETS: 'a_offsets' + OFFSETS: 'a_offsets', + COLOR: 'a_color' }; /**