Как использовать u_time в слое пользовательского стиля mapbox GL JS - PullRequest
6 голосов
/ 19 июня 2020

Я хочу добавить время в шейдер mapbox в fragmentSource, но когда я добавляю uniform float u_time;, треугольник не отображается. Вот скрипка https://jsfiddle.net/benderlio/o4xc5hw7/33/

var fragmentSource =`
    uniform float u_time;
    void main() {
        gl_FragColor = vec4(sin(1.0*u_time),0.0,1.0,1);
    }`

1 Ответ

6 голосов
/ 21 июня 2020

См. OpenGL ES Shading Language 1.00 Specification - 4.5.3 Квалификаторы точности по умолчанию :

Язык фрагментов не имеет квалификатора точности по умолчанию для типов с плавающей запятой. Следовательно, для объявлений переменных с плавающей запятой, векторов с плавающей запятой и матричных переменных либо объявление должно включать квалификатор точности, либо ранее должна быть объявлена ​​точность с плавающей запятой по умолчанию.

Поскольку универсальная переменная имеет тип с плавающей запятой, вы необходимо добавить квалификатор точности к фрагментному шейдеру. Если вы не укажете квалификатор точности, это вызовет ошибку компиляции (например, _Нет квалификатора точности для (float)).

Либо добавьте квалификатор точности по умолчанию:

precision mediump float;
            
uniform float u_time;

Или добавить к универсальной переменной явный квалификатор точности:

uniform mediump float u_time;

Я рекомендую проверить, были ли шейдеры успешно скомпилированы (gl.getShaderParameter / gl.getShaderInfoLog) и была ли связана программа (gl.getProgramParameter / gl.getProgramInfoLog). Например:

// create a vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) 
    alert(gl.getShaderInfoLog(vertexShader));

// create a fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) 
    alert(gl.getShaderInfoLog(fragmentShader));

// link the two shaders into a WebGL program
this.program = gl.createProgram();
gl.attachShader(this.program, vertexShader);
gl.attachShader(this.program, fragmentShader);
gl.linkProgram(this.program);
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))
    alert(gl.getProgramInfoLog(this.program));

mapboxgl.accessToken = 'pk.eyJ1IjoiYmVuZGVybGlkemUiLCJhIjoiY2pud3c0MnN1MDdraTN4cXBraDR3MHdyaCJ9.OsQLWGIWOutuIXCHgT8coQ';
var map = (window.map = new mapboxgl.Map({
    container: 'map',
    zoom: 3,
    center: [7.5, 58],
    style: 'mapbox://styles/mapbox/light-v10',
    antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));

// create a custom style layer to implement the WebGL content
var highlightLayer = {
    id: 'highlight',
    type: 'custom',

    // method called when the layer is added to the map
    // https://docs.mapbox.com/mapbox-gl-js/api/#styleimageinterface#onadd
    onAdd: function(map, gl) {
        // create GLSL source for vertex shader
        var vertexSource =
            `
            uniform mat4 u_matrix;
            attribute vec2 a_pos;
            void main() {
                gl_Position = u_matrix * vec4(a_pos, 0.0, 1);
            }`;

        // create GLSL source for fragment shader
        var fragmentSource =
            `
            precision mediump float;
            uniform float u_time;
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
            }`;

        // create a vertex shader
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, vertexSource);
        gl.compileShader(vertexShader);
        if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) 
            alert(gl.getShaderInfoLog(vertexShader));

        // create a fragment shader
        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, fragmentSource);
        gl.compileShader(fragmentShader);
        if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) 
            alert(gl.getShaderInfoLog(fragmentShader));

        // link the two shaders into a WebGL program
        this.program = gl.createProgram();
        gl.attachShader(this.program, vertexShader);
        gl.attachShader(this.program, fragmentShader);
        gl.linkProgram(this.program);
        if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))
            alert(gl.getProgramInfoLog(this.program));

        this.aPos = gl.getAttribLocation(this.program, 'a_pos');

        // define vertices of the triangle to be rendered in the custom style layer
        var helsinki = mapboxgl.MercatorCoordinate.fromLngLat({
            lng: 25.004,
            lat: 60.239
        });
        var berlin = mapboxgl.MercatorCoordinate.fromLngLat({
            lng: 13.403,
            lat: 52.562
        });
        var kyiv = mapboxgl.MercatorCoordinate.fromLngLat({
            lng: 30.498,
            lat: 50.541
        });

        // create and initialize a WebGLBuffer to store vertex and color data
        this.buffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
        gl.bufferData(
            gl.ARRAY_BUFFER,
            new Float32Array([
                helsinki.x,
                helsinki.y,
                berlin.x,
                berlin.y,
                kyiv.x,
                kyiv.y
            ]),
            gl.STATIC_DRAW
        );
    },

    // method fired on each animation frame
    // https://docs.mapbox.com/mapbox-gl-js/api/#map.event:render
    render: function(gl, matrix) {
    
        gl.useProgram(this.program);
        gl.uniformMatrix4fv(
            gl.getUniformLocation(this.program, 'u_matrix'),
            false,
            matrix
        );
        gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
        gl.enableVertexAttribArray(this.aPos);
        gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
        gl.enable(gl.BLEND);
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
    }
};

// add the custom style layer to the map
map.on('load', function() {
    map.addLayer(highlightLayer);
});
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.4.0/mapbox-gl.js'></script>
<div id='map'></div>
...