Интерполяция вершин WebGL в шейдере с индексированными элементами рисования, как это сделать в GPU?

#javascript #interpolation #linear-interpolation #webgl2

Вопрос:

У меня есть некоторые потоковые данные, я хочу нарисовать интерполированные вершины с помощью gl.ОЧКИ с помощью WebGL2. У меня есть функция сглаживания для создания кругов, и это действительно то, что мне нужно (я могу захотеть интерполировать дважды или трижды):
Чтобы проиллюстрировать проблему:

Чтобы интерполировать между вершинами, здесь, в JavaScript, дважды:

     var array = new Float32Array([-0.9, -0.9, 0.9, -0.9, 0.9, 0.9, -0.9, 0.9]);
    var array2 = new Float32Array(array.length * 2 - 2);

/* init canvas */
    var gl = document.getElementById('plot2').getContext('webgl2');
    gl.canvas.width = gl.canvas.height = 128;
    gl.viewportWidth = gl.canvas.width;
    gl.viewportHeight = gl.canvas.height;
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    
    const fs_point = `#version 300 es
    precision mediump float;
    out vec4 color;
    void main() {
        color = vec4(0.5, 0., 0.5, 0.8);
    }`;

    const vs_points = `#version 300 es
    precision mediump float;
    in vec2 vPos;

    void main() {
        gl_Position = vec4(vPos.x, vPos.y, 0, 1.0);
        gl_PointSize = 10.0;
    }`;

    const shaderProgram = gl.createProgram();

    let shader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(shader, fs_point);
    gl.compileShader(shader);
    gl.attachShader(shaderProgram, shader);

    shader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(shader, vs_points);
    gl.compileShader(shader);
    gl.attachShader(shaderProgram, shader);

    gl.linkProgram(shaderProgram);
    gl.useProgram(shaderProgram);

    gl.clearColor(0.0, 0.0, 0.0, 0.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.enable(gl.BLEND);
    gl.disable(gl.DEPTH_TEST);


    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vPos");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    const pointPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pointPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, array2, gl.DYNAMIC_DRAW);

    pointPosBuffer.itemSize = 2;

    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pointPosBuffer.itemSize, gl.FLOAT, false, 0, 0);
    /* /init canvas */
    
    /* loop */
    gl.clear(gl.COLOR_BUFFER_BIT);
    //array changes, manual interpolation
    for(var i = 0; i < array.length; i  = 2) {
        array2[2 * i] = array[i];
        array2[2 * i   1] = array[i   1];
    }

    //here starts interpolation
    for(var i = 2; i < array2.length - 2; i  = 4) {
        array2[i] = (array2[i - 2]   array2[i   2]) * 0.5;
        array2[i   1] = (array2[i - 1]   array2[i   3]) * 0.5;
    }
    
    gl.bufferData(gl.ARRAY_BUFFER, array2, gl.DYNAMIC_DRAW); //array values changes
    gl.drawArrays(gl.GL_POINTS, 0, 7);
    /* /loop */ 
 <canvas id="plot2"></canvas> 

Это действительно очень неудобно делать вручную, поэтому переключитесь на шейдер:

     var array = new Float32Array([-0.9, -0.9, 0.9, -0.9, 0.9, 0.9, -0.9, 0.9]),
    gl = document.getElementById('plot3').getContext('webgl2');
    gl.canvas.width = gl.canvas.height = 128;
    gl.viewportWidth = gl.canvas.width;
    gl.viewportHeight = gl.canvas.height;
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);

    const fs_point = `#version 300 es
    precision mediump float;
    out vec4 color;
    void main() {
        color = vec4(0.5, 0., 0.5, 0.8);
    }`;

    const vs_points = `#version 300 es
    precision mediump float;
    in vec4 vPos;

    void main() {
        switch (gl_VertexID % 3) {
            case 0:
                gl_Position = vec4(vPos.x, vPos.y, 0, 1.0);
                break;
            case 1:
                gl_Position = vec4(0.5 * (vPos.x   vPos.z), 0.5 * (vPos.y   vPos.w), 0, 1.0);
                break;
            case 2:
                gl_Position = vec4(vPos.z, vPos.w, 0, 1.0);
                break;

            }
        gl_PointSize = 12.0;
    }`;

    const shaderProgram = gl.createProgram();

    let shader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(shader, fs_point);
    gl.compileShader(shader);
    gl.attachShader(shaderProgram, shader);

    shader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(shader, vs_points);
    gl.compileShader(shader);
    gl.attachShader(shaderProgram, shader);

    gl.linkProgram(shaderProgram);
    gl.useProgram(shaderProgram);

    gl.clearColor(0.0, 0.0, 0.0, 0.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.enable(gl.BLEND);
    gl.disable(gl.DEPTH_TEST);


    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vPos");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    const pointPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pointPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW);

    pointPosBuffer.itemSize = 4;
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, pointPosBuffer.itemSize, gl.FLOAT, false, 8, 0);

    const indexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);

    const indices = new Uint8Array([
        0, 0, 0,
        1, 1, 1,
        2, 2, 2
    ]);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    /* /init canvas */

    /* loop */
    gl.clear(gl.COLOR_BUFFER_BIT);
    //array changes, manual interpolation

    gl.bufferData(gl.ARRAY_BUFFER, array, gl.DYNAMIC_DRAW); //array values changes
    gl.drawElements(gl.GL_POINTS, 9, gl.UNSIGNED_BYTE, 0);
    /* /loop */ 
 <canvas id="plot3"></canvas> 

Here, I want to use indices and supply two pairs of x, y coordinates to shader. I see only three dots. I think the code tells the indices, calls three times the same quad of vertices interpolating them according to index (which seems to fail), advances 8 bytes (2 Float coordinates) and draws again.

Is there easier way to interpolate between vertices?
Aren’t gl_VertexID or gl_InstanceID (tried the same at instanced version) suppose to advance every index / vertex?
Is this due to index reuse?