question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Warning when trying to create a CustomLayer with webgl PointsLayer

See original GitHub issue

I’m currently following the workshop but I’m now stuck on the WebGL rendering part.

The following code should be similar to what the workshop propose to render meteorites:

import 'ol/ol.css';
import {Map, View, Feature} from 'ol';

import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';

import VectorSource from 'ol/source/Vector';
import XYZSource from 'ol/source/XYZ';

import Point from 'ol/geom/Point';

import {fromLonLat} from 'ol/proj';

import Renderer from 'ol/renderer/webgl/PointsLayer';
import {clamp} from 'ol/math';

const stamenLayer = new TileLayer({
    source: new XYZSource({
        url: 'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
    })
});

const meteoriteSource = new VectorSource();
const client = new XMLHttpRequest();
client.open('GET', 'data/meteorites.csv');
client.onload = function() {
    const csv = client.responseText;
    const features = [];

    let prevIndex = csv.indexOf('\n')+1;
    let curIndex;
    while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
        const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
        prevIndex = curIndex +1;

        const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
        if (isNaN(coords[0]) || isNaN(coords[1])) {
            continue;
        }

        features.push(new Feature({
            mass: parseFloat(line[1]) || 0,
            year: parseInt(line[2]) || 0,
            geometry: new Point(coords)
        }));
    }
    meteoriteSource.addFeatures(features);
}
client.send();

const color = [1, 0, 0, 0.5];

class CustomLayer extends VectorLayer {
    createRenderer() {
        return new Renderer(this, {
            colorCallback: function(feature, vertex, component) {
                return color[component];
            },
            sizeCallback: function(feature) {
                return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
            }
        });
    }
}
const webglLayer = new CustomLayer({
    source: meteoriteSource,
});

const map = new Map({
    target: 'map-container',
    layers: [
        stamenLayer,
        webglLayer,
        // dynamicLayer,
        // aisLayer,
    ],
    view: new View({
        center: fromLonLat([0, 0]),
        zoom: 2
    })
});

Unfortunately, at this point, nothing happens and I am having a series of warning:

33 WebGL: INVALID_OPERATION: useProgram: program not valid
6 WebGL: INVALID_OPERATION: getUniformLocation: program not linked
2 Helper.js:642 WebGL: INVALID_OPERATION: getAttribLocation: program not linked
./node_modules/ol/webgl/Helper.js.WebGLHelper.getAttributeLocation @ Helper.js:642
./node_modules/ol/webgl/Helper.js.WebGLHelper.enableAttributeArray_ @ Helper.js:692
./node_modules/ol/webgl/Helper.js.WebGLHelper.enableAttributes @ Helper.js:712
./node_modules/ol/renderer/webgl/PointsLayer.js.WebGLPointsLayerRenderer.prepareFrame @ PointsLayer.js:374
./node_modules/ol/layer/Layer.js.Layer.render @ Layer.js:209
./node_modules/ol/renderer/Composite.js.CompositeMapRenderer.renderFrame @ Composite.js:111
./node_modules/ol/PluggableMap.js.PluggableMap.renderFrame_ @ PluggableMap.js:1120
(anonymous) @ PluggableMap.js:175
requestAnimationFrame (async)
./node_modules/ol/PluggableMap.js.PluggableMap.render @ PluggableMap.js:1042
./node_modules/ol/PluggableMap.js.PluggableMap.handleSizeChanged_ @ PluggableMap.js:901
./node_modules/ol/events/Target.js.Target.dispatchEvent @ Target.js:115
./node_modules/ol/Object.js.BaseObject.notify @ Object.js:154
./node_modules/ol/Object.js.BaseObject.set @ Object.js:173
./node_modules/ol/PluggableMap.js.PluggableMap.setSize @ PluggableMap.js:1163
./node_modules/ol/PluggableMap.js.PluggableMap.updateSize @ PluggableMap.js:1196
./node_modules/ol/PluggableMap.js.PluggableMap.handleTargetChanged_ @ PluggableMap.js:954
./node_modules/ol/events/Target.js.Target.dispatchEvent @ Target.js:115
./node_modules/ol/Object.js.BaseObject.notify @ Object.js:154
./node_modules/ol/Object.js.BaseObject.set @ Object.js:173
./node_modules/ol/Object.js.BaseObject.setProperties @ Object.js:186
PluggableMap @ PluggableMap.js:319
Map @ Map.js:83
./main.js @ main.js:69
__webpack_require__ @ bootstrap:19
0 @ log.js:47
__webpack_require__ @ bootstrap:19
(anonymous) @ bootstrap:83
(anonymous) @ bootstrap:83
Helper.js:450 WebGL: INVALID_OPERATION: drawElements: no valid shader program in use
./node_modules/ol/webgl/Helper.js.WebGLHelper.drawElements @ Helper.js:450
./node_modules/ol/renderer/webgl/PointsLayer.js.WebGLPointsLayerRenderer.renderFrame @ PointsLayer.js:330
./node_modules/ol/layer/Layer.js.Layer.render @ Layer.js:210
./node_modules/ol/renderer/Composite.js.CompositeMapRenderer.renderFrame @ Composite.js:111
./node_modules/ol/PluggableMap.js.PluggableMap.renderFrame_ @ PluggableMap.js:1120
(anonymous) @ PluggableMap.js:175
requestAnimationFrame (async)
./node_modules/ol/PluggableMap.js.PluggableMap.render @ PluggableMap.js:1042
./node_modules/ol/PluggableMap.js.PluggableMap.handleSizeChanged_ @ PluggableMap.js:901
./node_modules/ol/events/Target.js.Target.dispatchEvent @ Target.js:115
./node_modules/ol/Object.js.BaseObject.notify @ Object.js:154
./node_modules/ol/Object.js.BaseObject.set @ Object.js:173
./node_modules/ol/PluggableMap.js.PluggableMap.setSize @ PluggableMap.js:1163
./node_modules/ol/PluggableMap.js.PluggableMap.updateSize @ PluggableMap.js:1196
./node_modules/ol/PluggableMap.js.PluggableMap.handleTargetChanged_ @ PluggableMap.js:954
./node_modules/ol/events/Target.js.Target.dispatchEvent @ Target.js:115
./node_modules/ol/Object.js.BaseObject.notify @ Object.js:154
./node_modules/ol/Object.js.BaseObject.set @ Object.js:173
./node_modules/ol/Object.js.BaseObject.setProperties @ Object.js:186
PluggableMap @ PluggableMap.js:319
Map @ Map.js:83
./main.js @ main.js:69
__webpack_require__ @ bootstrap:19
0 @ log.js:47
__webpack_require__ @ bootstrap:19
(anonymous) @ bootstrap:83
(anonymous) @ bootstrap:83
12 [.WebGL-0x5628f92342e0]RENDER WARNING: there is no texture bound to the unit 0

Is there something missing in the workshop or is this a bug ?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:13 (7 by maintainers)

github_iconTop GitHub Comments

3reactions
jahowcommented, May 25, 2020

Ok so the hosted workshop is not up to date, which is why you get these errors. You can take a look at the source of the workshop which contains working code (albeit not in a very readable way): https://github.com/openlayers/workshop/blob/master/src/en/examples/webgl/animated.js

2reactions
FractalWirecommented, May 25, 2020

@flors I’ve got a similar use case.

For a working non-animated solution of the workshop example:

class CustomLayer extends VectorLayer {
    createRenderer() {
        return new Renderer(this, {
            attributes: [{
                name: 'size',
                callback: function (feature) {
                    return 32 * clamp(feature.get('mass') / 200000, 0, 1) + 16;
                }
            },
                {
                    name: 'year',
                    callback: function (feature) {
                        return feature.get('year');
                    },
                }],
            uniforms: {
            },
            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;
        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);
        }`,
            fragmentShader: `
        precision mediump float;
        varying vec2 v_texCoord;
        void main(void) {
          vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);
          float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
          float value = 2.0 * (1.0 - sqRadius);
          float alpha = smoothstep(0.0, 1.0, value);
          gl_FragColor = vec4(1.0, 0.0, 0.0, 0.3);
          gl_FragColor.a *= alpha;
          gl_FragColor.rgb *= gl_FragColor.a;
        }`
        });
    }
}

You need both vertexShader and fragmentShader for it to work, as mentionned in the doc. Also, note that vertexShader is setting the position with gl_Position while fragmentShader is setting color with gl_FragColor. So here, both are mandatory it seems. Also, not sure to understand how the piping work behind the scene, but it seems like vertexShader is setting variable that fragmentShader will later use.

I’ll be curious to have more clarifications or documentation link to understand a bit better how those two shaders work together and why you set the position and color in two distinct shaders instead of one.

If you want to understand a bit more how this is working, you should check out the link mentionned in the workshop. It looks like a pretty good introduction to shaders.

Also, as an alternative to WebGL, you might consider using VectorImage for fast rendering of vectors. Didn’t tried that yet…

Read more comments on GitHub >

github_iconTop Results From Across the Web

WebGL points layer - OpenLayers
The layer is given a style in JSON format which allows a certain level of customization of the final reprensentation.
Read more >
OpenLayers WebGLPointsLayer conditional symbol source
WebGL -0x12b2a1000]RENDER WARNING: texture bound to texture unit 0 is not renderable. It might be non-power-of-2 or have incompatible texture ...
Read more >
Custom WebGL layer view | Sample Code - ArcGIS Developers
This sample demonstrates how to add a custom WebGL object to a map. We will create a pulsating marker inspired by telecommunications iconography....
Read more >
Debug and troubleshoot WebGL builds - Unity - Manual
In Safari, go to Preferences > Advanced > Develop, and press Command-Option-C. In Microsoft Edge or Internet Explorer, press F12. Development builds. For ......
Read more >
Guide - LayerCake
Layer Cake comes with layout components that provide HTML, Svg, ScaledSvg, Canvas and WebGL containers for your custom components. You must wrap your...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found