如何在mapbox GL JS自定义样式层中使用u_time

How to use u_time in mapbox GL JS custom style layer

我想在 fragmentSource 中添加时间到 mapbox 着色器,但是当我添加 uniform float u_time; 三角形不渲染。这里有一个fiddlehttps://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);
    }`

OpenGL ES Shading Language 1.00 Specification - 4.5.3 Default Precision Qualifiers:

The fragment language has no default precision qualifier for floating point types. Hence for float, floating point vector and matrix variable declarations, either the declaration must include a precision qualifier or the default float precision must have been previously declared.

由于统一变量具有浮点类型,因此您必须向片段着色器添加精度限定符。如果您未指定精度限定符,则会导致编译错误(例如,_No precision qualifier for (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>