【问题标题】:webgl how to draw many cubeswebgl如何绘制许多立方体
【发布时间】:2014-11-06 03:01:58
【问题描述】:

我正在尝试使用 webGL 绘制 5161 个立方体。问题不在于绘制所有立方体。经过一番搜索,我认为这是因为我在一次 VBO 调用中传递了太多顶点。您可以在这里查看 jsfiddle:http://jsfiddle.net/n5fjhe21/。您可以使用 QWERASDF 和箭头键四处移动,但目前还没有很好地实现。

我的绘图调用过去是这样的:

function render(){
    gl.uniformMatrix4fv(u_matrixLoc, false, new Float32Array(pMatrix));
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawElements(gl.TRIANGLES, data.triangles.length, gl.UNSIGNED_SHORT, 0);
}

所以我会做一次 data.pushData() 并根据需要进行渲染;它很快。 glObject 是一个立方体数组。

data.pushData = function(){
// pushData once then call drawElements on every render call doesnt work as I hit some kind of limit;
// not all cubes are drawn; I think the draw calls must be split up;
data.vertices = [];
data.uv = [];
data.triangles = [];
var vertexOffset = 0;

glObjects.forEach(function pushingObject(o){
    data.vertices.push.apply(data.vertices,o.vertices);
    data.uv.push.apply(data.uv,o.uv);
    o.triangles.forEach(function pushingTriangles(index){
        data.triangles.push(index+vertexOffset);
    });

    vertexOffset += o.vertices.length/3; // change to component length later
});

    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.vertices),gl.DYNAMIC_DRAW );
    gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.uv),gl.STATIC_DRAW);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(data.triangles), gl.DYNAMIC_DRAW );
};

但问题(我认为)是我一次传递了太多顶点。所以我尝试将 pushData 和 render 合并在一起:

data.render = function(){
    data.vertices = [];
    data.uv = [];
    data.triangles = [];
    var vertexOffset = 0;

    glObjects.forEach(function pushingObject(o){
        if (vertexOffset + o.vertices.length > 65536){
            vertexOffset = 0;
            glDraw();
            data.vertices.length = 0;
            data.uv.length = 0;
            data.triangles.length = 0;
        }

        data.vertices.push.apply(data.vertices,o.vertices);
        data.uv.push.apply(data.uv,o.uv);
        o.triangles.forEach(function pushingTriangles(index){
            data.triangles.push(index+vertexOffset);
        });

        vertexOffset += o.vertices.length/3; // change to component length later
    });

    glDraw();

    function glDraw(){
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.vertices),gl.STATIC_DRAW);
        gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data.uv),gl.STATIC_DRAW);
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(data.triangles), gl.STATIC_DRAW);
        gl.drawElements(gl.TRIANGLES, data.triangles.length, gl.UNSIGNED_SHORT, 0);
    }
};

但这还不够快,因为据我所知,传入新的 bufferData 很慢。所以我的问题是,在这种情况下人们会做什么?我无法找到任何处理此问题的 webgl 资源。我的感觉倾向于创建多个 VBO 对象,但我想确保我首先朝着正确的方向前进。作为一个后续问题,假设如果需要绘制许多具有唯一位置 (x,y,z) 和方向 (rX,rY,rZ) 的立方体,如何实现它?提前致谢。

【问题讨论】:

    标签: javascript webgl


    【解决方案1】:

    好的,我解决了我的问题,我将把这个留给掉队的人:

    基本上,我的想法是正确的,因为我需要使用多个绘图调用,因为每个索引绘图 (drawElements) 只能引用 VBO 中的 2^16 个元素。我的第一个实现中的缺陷是,我实际上试图在每次渲染调用中重建一个由多个立方体顶点组成的新的大 typedArray。不用说,这很慢。因此,我真的应该只创建一次 typedArray/buffer。为了克服 2^16 元素引用的限制,我所要做的就是将一个 bigass typedArray 分成可管理的大小,而这正是新版本的 pushData 所做的:

    data.pushData = function(){
        // ensure each vertex attribute has less than 2^16 vertices because that is how many that be be referenced each time
        // with gl.drawElements call
    
        function newChunk(){
            return {
                vertices: [],
                uv: [],
                triangles: []
            }
        }
        var chunk = newChunk();
    
        var vertexOffset = 0;
    
        glObjects.forEach(function pushingVerts(o){
            if (vertexOffset + o.vertices.length > 65536){
                vertexOffset = 0;
                data.chunks.push(chunk);
                chunk = newChunk();
            }
    
            chunk.vertices.push.apply(chunk.vertices,o.vertices);
            chunk.uv.push.apply(chunk.uv,o.uv);
            o.triangles.forEach(function pushingTriangles(index){
                chunk.triangles.push(index+vertexOffset);
            });
    
            vertexOffset += o.vertices.length/3; // change to component length later
        });
    
        data.chunks.push(chunk);
    
        data.chunks.forEach(function toTypeArray(c){
            c.vertices = new Float32Array(c.vertices);
            c.uv = new Float32Array(c.uv);
            c.triangles = new Uint16Array(c.triangles);
        });
    
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, sizeofFloat * 65536*3,gl.DYNAMIC_DRAW);
        gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, sizeofFloat * 65536*2,gl.DYNAMIC_DRAW);
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, sizeofFloat * 65536, gl.DYNAMIC_DRAW);
        // for some reason only allocating sizeofUnsignedShort * 65536 is not enough.
    
        return data.chunks;
    }; 
    

    然后进行简单的渲染:

    data.renderChunks = function(){
    
        data.chunks.forEach(function renderChunk(c){
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
            gl.bufferSubData(gl.ARRAY_BUFFER,  0, c.vertices);
            gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
            gl.bufferSubData(gl.ARRAY_BUFFER,  0, c.uv);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleBuffer);
            gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, c.triangles);
            gl.drawElements(gl.TRIANGLES, c.triangles.length, gl.UNSIGNED_SHORT, 0);
        });
    };
    

    我也从使用 gl.bufferData 改为 gl.bufferSubData 以避免构造新缓冲区的开销。

    有了这个,我现在可以画出 60,000 个立方体(至少): http://jsfiddle.net/n5fjhe21/1/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-10
      • 2019-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      • 2020-04-15
      • 1970-01-01
      相关资源
      最近更新 更多