Ускорение записи новых значений в массив?

Рейтинг: 0Ответов: 0Опубликовано: 06.07.2023

Я пополняю массив большим количеством новых значений, для отрисовки объектов на canvas'е, это занимает не мало времени. Собственно вопрос: можно ли ускорить этот процесс/другой способ сохранения данных? Код:

index.html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>-</title>
    </head>
    <body style="margin: 0px;">
        <canvas id="canvas" width="5000" height="5000">HTML5 Canvas is not supported by your browser</canvas>

        <script src="./engine.js"></script>
        <script id="main"></script>
        <script>
            window.onload = function() {
                document.querySelector('#main').src = "./main.js";
            }
        </script>
    </body>
</html>

main.js:

'use strict';

function draw() {
    console.time('execution time');

    console.time('write time');
    for(let y = 0; y < mapY; y++) {
        for(let x = 0; x < mapX; x++) {
            addCell(x, y, 1, 0, 0, 1, 0, 0); // add cell to draw list (positionX, positionY, color0, color1, color2, color3, rotateAngle)
        }
    }
    console.timeEnd('write time');

    console.time('render time');
    render(); // draw all from draw list
    console.timeEnd('render time');

    console.timeEnd('execution time');
}

const atlas = new Image();

const scale = 5;
const lineWidth = 0;

const mapX = Math.floor(canvas.width / scale);
const mapY = Math.floor(canvas.height / scale);

setupGL(scale, lineWidth, [0, 0, 0, 1]);

console.log('Map size: ' + mapX + 'x' + mapY);

atlas.src = './atlas.png';
atlas.onload = function() {
    addTexture(gl, atlas);

    draw();
}

window.onmousedown = function(e) {
    if (e.button == 2) {
        clearList(); // clear draw list

        draw(); // draw
    }
}

engine.js:

'use strict';

// ========== shaders ==========
const vsSource =
`#version 300 es

layout(location=0) in vec2 aPosition;
layout(location=1) in vec2 aTexCoord;
layout(location=2) in vec2 aOffset;
layout(location=3) in float aTexID;
layout(location=4) in vec4 aColor;
layout(location=5) in float aAngle;
layout(location=6) in float aTexTransperent;
layout(location=7) in float aSize;
layout(location=8) in float aLineWidth;
layout(location=9) in vec2 aResolution;

out vec4 vColor;
out vec2 vTexCoord;
out float vTexID;
out float vTexTransperent;

vec2 rotate(float angle) {
    float c = cos(angle);
    float s = sin(angle);

    return vec2(aPosition.x * c - aPosition.y * s + 0.5, aPosition.x * s + aPosition.y * c + 0.5);
}

void main() {
    gl_Position = vec4((((rotate(radians(aAngle)) + aOffset) * aSize + aOffset * aLineWidth) / aResolution * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);

    vColor = aColor;
    vTexCoord = aTexCoord;
    vTexID = aTexID;
    vTexTransperent = aTexTransperent;
}`;

const fsSource =
`#version 300 es

precision lowp float;

in vec4 vColor;
in vec2 vTexCoord;
in float vTexID;
in float vTexTransperent;

uniform sampler2D uTexture;

out vec4 fragColor;

void main() {
    if (vTexTransperent > 0.0) {
        fragColor = texture(uTexture, (vTexCoord + vec2(mod(vTexID, 6.0), floor(vTexID / 6.0))) * 32.0 / 128.0) * vec4(1.0, 1.0, 1.0, vTexTransperent);
    }
    else {
        fragColor = vColor;
    }
}`;
// =========================

// ========== functions ==========
function createShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
    console.log(type == gl.VERTEX_SHADER? 'VERTEX SHADER' : 'FRAGMENT SHADER', gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
}

function createProgram(gl, vsSource, fsSource) {
    const program = gl.createProgram();
    gl.attachShader(program, createShader(gl, gl.VERTEX_SHADER, vsSource));
    gl.attachShader(program, createShader(gl, gl.FRAGMENT_SHADER, fsSource));
    gl.linkProgram(program);
    if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
        gl.useProgram(program);
        return program
    };
    console.log(gl.getProgramInfoLog(program));
    gl.deleteProgram(program);
}

function addTexture(gl, image) {
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    return texture;
}

function setupGL(size, lineWidth, color) {
    gl.viewport(0, 0, canvas.width, canvas.height);

    gl.clearColor(color[0], color[1], color[2], color[3]);
    gl.clear(gl.COLOR_BUFFER_BIT);

    clearList();

    gl.vertexAttrib1f(7, size); // set size
    gl.vertexAttrib1f(8, lineWidth); // set line width
    gl.vertexAttrib2f(9, canvas.width, canvas.height); // set canvas resolution in WebGL
}

function clearList() { // clear draw list
    transformData.length = 0;
}

function addCell(offsetX, offsetY, color0, color1, color2, color3, angle, id) { // add cell to draw list
    transformData.push(offsetX, offsetY, id, color0, color1, color2, color3, angle, 0, offsetX, offsetY, id, color0, color1, color2, color3, angle, 1);
}

function render() { // draw all form draw list
    gl.bindBuffer(gl.ARRAY_BUFFER, transformBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(transformData), gl.STATIC_DRAW); // upload data to buffer

    // set data to attributes
    gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 36, 0);
    gl.vertexAttribPointer(3, 1, gl.FLOAT, false, 36, 8);
    gl.vertexAttribPointer(4, 4, gl.FLOAT, false, 36, 12);
    gl.vertexAttribPointer(5, 1, gl.FLOAT, false, 36, 28);
    gl.vertexAttribPointer(6, 1, gl.FLOAT, false, 36, 32);

    gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, transformData.length / 9);
}
// =========================

// ========== init ==========
const canvas = document.querySelector('#canvas');
const gl = canvas.getContext('webgl2', { preserveDrawingBuffer: true }) || canvas.getContext('experimental-webgl2', { preserveDrawingBuffer: true }); // get GL context
if (!gl) alert('WebGL Context init failed');
const program = createProgram(gl, vsSource, fsSource); // create shader program

const modelData = new Float32Array([
//  position        texCoord
    -0.5, -0.5,     0, 0,
     0.5, -0.5,     1, 0,
    -0.5,  0.5,     0, 1,
    -0.5,  0.5,     0, 1,
     0.5, -0.5,     1, 0,
     0.5,  0.5,     1, 1,
]);
const transformData = []; // offset; color; angle; texTransperent; texOffset

const modelBuffer = gl.createBuffer();
const transformBuffer = gl.createBuffer();

gl.enable(gl.BLEND); // enable transperency
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
//gl.enable(gl.DEPTH_TEST);
//gl.depthFunc(gl.LESS);

gl.bindBuffer(gl.ARRAY_BUFFER, modelBuffer); 
gl.bufferData(gl.ARRAY_BUFFER, modelData, gl.STATIC_DRAW);
// set primitives vertecies
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 16, 0); 
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 16, 8);

// say webgl, that this attributes must change 1 per instance
gl.vertexAttribDivisor(2, 1);
gl.vertexAttribDivisor(3, 1);
gl.vertexAttribDivisor(4, 1);
gl.vertexAttribDivisor(5, 1);
gl.vertexAttribDivisor(6, 1);

gl.enableVertexAttribArray(0);
gl.enableVertexAttribArray(1);
gl.enableVertexAttribArray(2);
gl.enableVertexAttribArray(3);
gl.enableVertexAttribArray(4);
gl.enableVertexAttribArray(5);
gl.enableVertexAttribArray(6);
// =========================

Запись в массив в main.js => draw() & engine.js => addCell()

Ответы

Ответов пока нет.