Webgl renderer / fix existing examples
The shaders were rewritten manually for those, althoughj eventually they should use the shader builder utilities as well.
This commit is contained in:
@@ -7,8 +7,9 @@ import VectorLayer from '../src/ol/layer/Vector.js';
|
|||||||
import {Vector} from '../src/ol/source.js';
|
import {Vector} from '../src/ol/source.js';
|
||||||
import {fromLonLat} from '../src/ol/proj.js';
|
import {fromLonLat} from '../src/ol/proj.js';
|
||||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
||||||
import {clamp, lerp} from '../src/ol/math.js';
|
import {clamp} from '../src/ol/math.js';
|
||||||
import Stamen from '../src/ol/source/Stamen.js';
|
import Stamen from '../src/ol/source/Stamen.js';
|
||||||
|
import {formatColor} from '../src/ol/webgl/ShaderBuilder.js';
|
||||||
|
|
||||||
const vectorSource = new Vector({
|
const vectorSource = new Vector({
|
||||||
attributions: 'NASA'
|
attributions: 'NASA'
|
||||||
@@ -36,36 +37,58 @@ updateStatusText();
|
|||||||
class WebglPointsLayer extends VectorLayer {
|
class WebglPointsLayer extends VectorLayer {
|
||||||
createRenderer() {
|
createRenderer() {
|
||||||
return new WebGLPointsLayerRenderer(this, {
|
return new WebGLPointsLayerRenderer(this, {
|
||||||
colorCallback: function(feature, color) {
|
attributes: [
|
||||||
// color is interpolated based on year
|
{
|
||||||
const ratio = clamp((feature.get('year') - 1800) / (2013 - 1800), 0, 1);
|
name: 'size',
|
||||||
|
callback: function(feature) {
|
||||||
color[0] = lerp(oldColor[0], newColor[0], ratio) / 255;
|
|
||||||
color[1] = lerp(oldColor[1], newColor[1], ratio) / 255;
|
|
||||||
color[2] = lerp(oldColor[2], newColor[2], ratio) / 255;
|
|
||||||
color[3] = 1;
|
|
||||||
|
|
||||||
return color;
|
|
||||||
},
|
|
||||||
sizeCallback: function(feature) {
|
|
||||||
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
|
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'year',
|
||||||
|
callback: function(feature) {
|
||||||
|
return feature.get('year');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
vertexShader: [
|
||||||
|
'precision mediump float;',
|
||||||
|
|
||||||
|
'uniform mat4 u_projectionMatrix;',
|
||||||
|
'uniform mat4 u_offsetScaleMatrix;',
|
||||||
|
'uniform mat4 u_offsetRotateMatrix;',
|
||||||
|
'attribute vec2 a_position;',
|
||||||
|
'attribute float a_index;',
|
||||||
|
'attribute float a_size;',
|
||||||
|
'attribute float a_year;',
|
||||||
|
'varying vec2 v_texCoord;',
|
||||||
|
'varying float v_year;',
|
||||||
|
|
||||||
|
'void main(void) {',
|
||||||
|
' mat4 offsetMatrix = u_offsetScaleMatrix;',
|
||||||
|
' float offsetX = a_index == 0.0 || a_index == 3.0 ? -a_size / 2.0 : a_size / 2.0;',
|
||||||
|
' float offsetY = a_index == 0.0 || a_index == 1.0 ? -a_size / 2.0 : a_size / 2.0;',
|
||||||
|
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
|
||||||
|
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
|
||||||
|
' float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;',
|
||||||
|
' float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;',
|
||||||
|
' v_texCoord = vec2(u, v);',
|
||||||
|
' v_year = a_year;',
|
||||||
|
'}'
|
||||||
|
].join(' '),
|
||||||
fragmentShader: [
|
fragmentShader: [
|
||||||
'precision mediump float;',
|
'precision mediump float;',
|
||||||
|
|
||||||
'uniform float u_time;',
|
'uniform float u_time;',
|
||||||
'uniform float u_minYear;',
|
'uniform float u_minYear;',
|
||||||
'uniform float u_maxYear;',
|
'uniform float u_maxYear;',
|
||||||
|
|
||||||
'varying vec2 v_texCoord;',
|
'varying vec2 v_texCoord;',
|
||||||
'varying float v_opacity;',
|
'varying float v_year;',
|
||||||
'varying vec4 v_color;',
|
|
||||||
|
|
||||||
'void main(void) {',
|
'void main(void) {',
|
||||||
' float impactYear = v_opacity;',
|
|
||||||
|
|
||||||
// filter out pixels if the year is outside of the given range
|
// filter out pixels if the year is outside of the given range
|
||||||
' if (impactYear < u_minYear || v_opacity > u_maxYear) {',
|
' if (v_year < u_minYear || v_year > u_maxYear) {',
|
||||||
' discard;',
|
' discard;',
|
||||||
' }',
|
' }',
|
||||||
|
|
||||||
@@ -74,19 +97,19 @@ class WebglPointsLayer extends VectorLayer {
|
|||||||
' float value = 2.0 * (1.0 - sqRadius);',
|
' float value = 2.0 * (1.0 - sqRadius);',
|
||||||
' float alpha = smoothstep(0.0, 1.0, value);',
|
' float alpha = smoothstep(0.0, 1.0, value);',
|
||||||
|
|
||||||
' vec3 color = v_color.rgb;',
|
// color is interpolated based on year
|
||||||
' float period = 8.0;',
|
' float ratio = clamp((v_year - 1800.0) / (2013.0 - 1800.0), 0.0, 1.1);',
|
||||||
' color.g *= 2.0 * (1.0 - sqrt(mod(u_time + impactYear * 0.025, period) / period));',
|
' vec3 color = mix(vec3(' + formatColor(oldColor) + '),',
|
||||||
|
' vec3(' + formatColor(newColor) + '), ratio);',
|
||||||
|
|
||||||
' gl_FragColor = vec4(color, v_color.a);',
|
' float period = 8.0;',
|
||||||
|
' color.g *= 2.0 * (1.0 - sqrt(mod(u_time + v_year * 0.025, period) / period));',
|
||||||
|
|
||||||
|
' gl_FragColor = vec4(color, 1.0);',
|
||||||
' gl_FragColor.a *= alpha;',
|
' gl_FragColor.a *= alpha;',
|
||||||
' gl_FragColor.rgb *= gl_FragColor.a;',
|
' gl_FragColor.rgb *= gl_FragColor.a;',
|
||||||
'}'
|
'}'
|
||||||
].join(' '),
|
].join(' '),
|
||||||
opacityCallback: function(feature) {
|
|
||||||
// here the opacity channel of the vertices is used to store the year of impact
|
|
||||||
return feature.get('year');
|
|
||||||
},
|
|
||||||
uniforms: {
|
uniforms: {
|
||||||
u_time: function() {
|
u_time: function() {
|
||||||
return Date.now() * 0.001 - startTime;
|
return Date.now() * 0.001 - startTime;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import VectorLayer from '../src/ol/layer/Vector.js';
|
|||||||
import {Vector} from '../src/ol/source.js';
|
import {Vector} from '../src/ol/source.js';
|
||||||
import {fromLonLat} from '../src/ol/proj.js';
|
import {fromLonLat} from '../src/ol/proj.js';
|
||||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
||||||
import {lerp} from '../src/ol/math.js';
|
import {formatColor, formatNumber} from '../src/ol/webgl/ShaderBuilder.js';
|
||||||
|
|
||||||
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
|
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
|
||||||
|
|
||||||
@@ -35,33 +35,60 @@ const shapeTextureCoords = {
|
|||||||
|
|
||||||
const oldColor = [255, 160, 110];
|
const oldColor = [255, 160, 110];
|
||||||
const newColor = [180, 255, 200];
|
const newColor = [180, 255, 200];
|
||||||
|
const size = 16;
|
||||||
|
|
||||||
class WebglPointsLayer extends VectorLayer {
|
class WebglPointsLayer extends VectorLayer {
|
||||||
createRenderer() {
|
createRenderer() {
|
||||||
return new WebGLPointsLayerRenderer(this, {
|
return new WebGLPointsLayerRenderer(this, {
|
||||||
texture: texture,
|
attributes: [
|
||||||
colorCallback: function(feature, color) {
|
{
|
||||||
// color is interpolated based on year (min is 1910, max is 2013)
|
name: 'year',
|
||||||
// please note: most values are between 2000-2013
|
callback: function(feature) {
|
||||||
const ratio = (feature.get('year') - 1950) / (2013 - 1950);
|
return feature.get('year');
|
||||||
|
|
||||||
color[0] = lerp(oldColor[0], newColor[0], ratio * ratio) / 255;
|
|
||||||
color[1] = lerp(oldColor[1], newColor[1], ratio * ratio) / 255;
|
|
||||||
color[2] = lerp(oldColor[2], newColor[2], ratio * ratio) / 255;
|
|
||||||
color[3] = 1;
|
|
||||||
|
|
||||||
return color;
|
|
||||||
},
|
|
||||||
texCoordCallback: function(feature, component) {
|
|
||||||
let coords = shapeTextureCoords[feature.get('shape')];
|
|
||||||
if (!coords) {
|
|
||||||
coords = shapeTextureCoords['default'];
|
|
||||||
}
|
}
|
||||||
return coords[component];
|
|
||||||
},
|
|
||||||
sizeCallback: function() {
|
|
||||||
return 16;
|
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
vertexShader: [
|
||||||
|
'precision mediump float;',
|
||||||
|
|
||||||
|
'uniform mat4 u_projectionMatrix;',
|
||||||
|
'uniform mat4 u_offsetScaleMatrix;',
|
||||||
|
'uniform mat4 u_offsetRotateMatrix;',
|
||||||
|
'attribute vec2 a_position;',
|
||||||
|
'attribute float a_index;',
|
||||||
|
'attribute float a_year;',
|
||||||
|
'varying float v_year;',
|
||||||
|
|
||||||
|
'void main(void) {',
|
||||||
|
' mat4 offsetMatrix = u_offsetScaleMatrix;',
|
||||||
|
' float offsetX = a_index == 0.0 || a_index == 3.0 ? ',
|
||||||
|
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
|
||||||
|
' float offsetY = a_index == 0.0 || a_index == 1.0 ? ',
|
||||||
|
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
|
||||||
|
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
|
||||||
|
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
|
||||||
|
' v_year = a_year;',
|
||||||
|
'}'
|
||||||
|
].join(' '),
|
||||||
|
fragmentShader: [
|
||||||
|
'precision mediump float;',
|
||||||
|
|
||||||
|
'uniform float u_time;',
|
||||||
|
'uniform float u_minYear;',
|
||||||
|
'uniform float u_maxYear;',
|
||||||
|
'varying float v_year;',
|
||||||
|
|
||||||
|
'void main(void) {',
|
||||||
|
// color is interpolated based on year
|
||||||
|
' float ratio = clamp((v_year - 1950.0) / (2013.0 - 1950.0), 0.0, 1.1);',
|
||||||
|
' vec3 color = mix(vec3(' + formatColor(oldColor) + '),',
|
||||||
|
' vec3(' + formatColor(newColor) + '), ratio);',
|
||||||
|
|
||||||
|
' gl_FragColor = vec4(color, 1.0);',
|
||||||
|
' gl_FragColor.rgb *= gl_FragColor.a;',
|
||||||
|
'}'
|
||||||
|
].join(' '),
|
||||||
|
texture: texture // FIXME: this doesn't work yet
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,38 +177,47 @@ class Heatmap extends VectorLayer {
|
|||||||
*/
|
*/
|
||||||
createRenderer() {
|
createRenderer() {
|
||||||
return new WebGLPointsLayerRenderer(this, {
|
return new WebGLPointsLayerRenderer(this, {
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
name: 'weight',
|
||||||
|
callback: this.weightFunction_
|
||||||
|
}
|
||||||
|
],
|
||||||
vertexShader: `
|
vertexShader: `
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
attribute vec2 a_position;
|
|
||||||
attribute vec2 a_texCoord;
|
|
||||||
attribute vec2 a_offsets;
|
|
||||||
attribute float a_opacity;
|
|
||||||
|
|
||||||
uniform mat4 u_projectionMatrix;
|
uniform mat4 u_projectionMatrix;
|
||||||
uniform mat4 u_offsetScaleMatrix;
|
uniform mat4 u_offsetScaleMatrix;
|
||||||
uniform float u_size;
|
uniform float u_size;
|
||||||
|
attribute vec2 a_position;
|
||||||
|
attribute float a_index;
|
||||||
|
attribute float a_weight;
|
||||||
|
|
||||||
varying vec2 v_texCoord;
|
varying vec2 v_texCoord;
|
||||||
varying float v_opacity;
|
varying float v_weight;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec4 offsets = u_offsetScaleMatrix * vec4(a_offsets, 0.0, 0.0);
|
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||||
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets * u_size;
|
float offsetX = a_index == 0.0 || a_index == 3.0 ? -u_size / 2.0 : u_size / 2.0;
|
||||||
v_texCoord = a_texCoord;
|
float offsetY = a_index == 0.0 || a_index == 1.0 ? -u_size / 2.0 : u_size / 2.0;
|
||||||
v_opacity = a_opacity;
|
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
|
||||||
|
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
|
||||||
|
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
|
||||||
|
float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;
|
||||||
|
v_texCoord = vec2(u, v);
|
||||||
|
v_weight = a_weight;
|
||||||
}`,
|
}`,
|
||||||
fragmentShader: `
|
fragmentShader: `
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
uniform float u_blurSlope;
|
uniform float u_blurSlope;
|
||||||
|
|
||||||
varying vec2 v_texCoord;
|
varying vec2 v_texCoord;
|
||||||
varying float v_opacity;
|
varying float v_weight;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);
|
vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);
|
||||||
float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
|
float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
|
||||||
float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;
|
float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;
|
||||||
float alpha = smoothstep(0.0, 1.0, value) * v_opacity;
|
float alpha = smoothstep(0.0, 1.0, value) * v_weight;
|
||||||
gl_FragColor = vec4(alpha, alpha, alpha, alpha);
|
gl_FragColor = vec4(alpha, alpha, alpha, alpha);
|
||||||
}`,
|
}`,
|
||||||
uniforms: {
|
uniforms: {
|
||||||
@@ -239,8 +248,7 @@ class Heatmap extends VectorLayer {
|
|||||||
u_gradientTexture: this.gradient_
|
u_gradientTexture: this.gradient_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
opacityCallback: this.weightFunction_
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {asArray} from '../color.js';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will return the number as a float with a dit separator, which is required by GLSL.
|
* Will return the number as a float with a dot separator, which is required by GLSL.
|
||||||
* @param {number} v Numerical value.
|
* @param {number} v Numerical value.
|
||||||
* @returns {string} The value as string.
|
* @returns {string} The value as string.
|
||||||
*/
|
*/
|
||||||
@@ -15,6 +15,19 @@ export function formatNumber(v) {
|
|||||||
return s.indexOf('.') === -1 ? s + '.0' : s;
|
return s.indexOf('.') === -1 ? s + '.0' : s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will normalize and converts to string a color array compatible with GLSL.
|
||||||
|
* @param {Array<number>} colorArray Color in [r, g, b, a] array form, with RGB components in the
|
||||||
|
* 0..255 range and the alpha component in the 0..1 range. Note that if the A component is
|
||||||
|
* missing, only 3 values will be output.
|
||||||
|
* @returns {string} The color components concatenated in `1.0, 1.0, 1.0, 1.0` form.
|
||||||
|
*/
|
||||||
|
export function formatColor(colorArray) {
|
||||||
|
return colorArray.map(function (c, i) {
|
||||||
|
return i < 3 ? c / 255 : c;
|
||||||
|
}).map(formatNumber).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a symbol vertex shader from a literal style,
|
* Generates a symbol vertex shader from a literal style,
|
||||||
* intended to be used on point geometries.
|
* intended to be used on point geometries.
|
||||||
@@ -40,9 +53,6 @@ export function getSymbolVertexShader(parameters) {
|
|||||||
const color = parameters.color !== undefined ?
|
const color = parameters.color !== undefined ?
|
||||||
(typeof parameters.color === 'string' ? asArray(parameters.color) : parameters.color) :
|
(typeof parameters.color === 'string' ? asArray(parameters.color) : parameters.color) :
|
||||||
[255, 255, 255, 1];
|
[255, 255, 255, 1];
|
||||||
function normalizeColor(c, i) {
|
|
||||||
return i < 3 ? c / 255 : c;
|
|
||||||
}
|
|
||||||
|
|
||||||
const f = formatNumber;
|
const f = formatNumber;
|
||||||
|
|
||||||
@@ -66,7 +76,7 @@ void main(void) {
|
|||||||
float v = a_index == 0.0 || a_index == 1.0 ? ${f(texCoord[1])} : ${f(texCoord[3])};
|
float v = a_index == 0.0 || a_index == 1.0 ? ${f(texCoord[1])} : ${f(texCoord[3])};
|
||||||
v_texCoord = vec2(u, v);
|
v_texCoord = vec2(u, v);
|
||||||
v_opacity = ${f(opacity)};
|
v_opacity = ${f(opacity)};
|
||||||
v_color = vec4(${color.map(normalizeColor).map(f).join(', ')});
|
v_color = vec4(${formatColor(color)});
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
|
|||||||
Reference in New Issue
Block a user