游戏循环中的动态WebGL绘制

时间:2016-10-08 19:54:21

标签: javascript dynamic webgl

我是WebGL的新手,我正在开发一款动态生成播放器周围土地的3D游戏。所以,我正在尝试添加顶点以在游戏中绘制。事情很好,直到我开始添加这个功能,每帧进行数百次gl.drawArrays()次呼叫,这使得它超级滞后。在完成一些研究之后,我发现更好的方法是制作一个包含所有顶点的巨大数组(每个形状由简并三角形分隔),然后每帧进行一次gl.drawArray()调用。

以下是我在加载时运行的代码部分:

function loadGraphics() {
    // ground
    // buffers
    quadVertexPositionBuffer = gl.createBuffer();

    vertices = [];
    verticesItemCount = 0;

    quadVertexColorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, quadVertexColorBuffer);
    var colors = [
        0.0, 0.4, 0.0, 1.0,
        0.0, 0.4, 0.0, 1.0,
        0.0, 0.4, 0.0, 1.0,
        0.0, 0.4, 0.0, 1.0,
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.DYNAMIC_DRAW);
    quadVertexColorBuffer.itemSize = 4;
    quadVertexColorBuffer.numItems = 4;
}

以下是每帧运行的部分:

function drawGraphics() {
    // draw code for graphics
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clearColor(0.35, 0.4, 1.0, 1.0 );

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
    mat4.identity(mvMatrix);

    // perspective
    var cameraX = camera.x, cameraY = camera.y, cameraZ = camera.z;
    mat4.rotate(mvMatrix, rotMatrix[1], [1, 0, 0]);
    mat4.rotate(mvMatrix, rotMatrix[0], [0, 1, 0]);
    mat4.translate(mvMatrix, [-cameraX/33, -cameraY/33, -cameraZ/33]);

    debug.add("{camera} x:"+camera.x+",y:"+camera.y+",z:"+camera.z+";");
    debug.add("\n{mouse delta} x:"+mouse.x-mouse.prevX+",y:"+mouse.y-mouse.prevY+";");
    debug.add("\n{rm}[0]:"+rotMatrix[0]+",[1]:"+rotMatrix[1]);
    // ground

    gl.bindBuffer(gl.ARRAY_BUFFER, quadVertexColorBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, quadVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);


    // land plots
    vertices = [];
    verticesItemCount = 0;

    for (var i = 0; i < landPlots.length; i++) {
        var oX = landPlots[i].x*3;
        var oZ = landPlots[i].z*3;

        var plotVertices = [
            -1.5+oX,  0.0,  1.5+oZ,  1.0,
             1.5+oX,  0.0,  1.5+oZ,  1.0,
            -1.5+oX,  0.0, -1.5+oZ,  1.0,
             1.5+oX,  0.0, -1.5+oZ,  1.0
        ];

        pushDrawArray(plotVertices, 4);

        for(var j = 1; j <= 2; j++) {
            debug.add(" " + renderLandPlotIntersection(landPlots[i], j));
        }           

    }
    gl.bindBuffer(gl.ARRAY_BUFFER, quadVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 4, gl.FLOAT, false, 0, 0);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW);

    gl.drawArrays(gl.TRIANGLE_STRIP, 0, verticesItemCount);
}
function renderLandPlotIntersection(landPlot, side) {
    var x = landPlot.x;
    var z = landPlot.z;

    var lvl = landPlot.level;
    var olvl = null;
    var plot;

    switch (side) {
        case 0: plot =getLandPlot(x-1, z  ); if (plot !== null) olvl = plot.level/66; else return 0; break;
        case 1: plot =getLandPlot(x,   z+1); if (plot !== null) olvl = plot.level/66; else return 0; break;
        case 2: plot =getLandPlot(x+1, z  ); if (plot !== null) olvl = plot.level/66; else return 0; break;
        case 3: plot =getLandPlot(x,   z-1); if (plot !== null) olvl = plot.level/66; else return 0; break;
        default: throw "Land plot intersection drawing: side out of range."; return -1;
    }

    var intersectionVertices = [
        x*3,  lvl,  z*3,
        x*3,  lvl,  z*3,
        x*3,  olvl, z*3, 
        x*3,  olvl, z*3
    ];

    pushDrawArray(intersectionVertices, 4);

    return +1;
}
function pushDrawArray(array, itemCount) {
    if (vertices.length > 0) {
        // degenerate 

        vertices.push(vertices[vertices.length-3]);
        vertices.push(vertices[vertices.length-2]);
        vertices.push(vertices[vertices.length-1]);

        vertices.push(array[0]);
        vertices.push(array[1]);
        vertices.push(array[2]);

        verticesItemCount += 2 ; 
    }

    gl.bufferSubData(gl.ARRAY_BUFFER, verticesItemCount*4, array);
    verticesItemCount += itemCount;
}

我开始使用DYNAMIC_DRAW,但我真的不知道如何使用它。 verticesItemCount标记vertices数组中有多少个顶点。

gl.drawArrays()会返回此错误:

  

[.Offscreen-For-WebGL-060B7ED8] GL错误:GL_INVALID_OPERATION:glDrawArrays:尝试访问属性1中的范围顶点localhost /:1 WebGL:错误太多,不会再向控制台报告错误这个背景。

如何修复此代码以避免错误?

1 个答案:

答案 0 :(得分:1)

我知道我做了什么。我使顶点位置数组比我的顶点颜色数组长,所以它试图访问超出界限的东西。修复方法是保持顶点颜色数组与顶点位置数组的长度相同。