加载网格后设置WebGL vertexAttribPointer:为什么需要延迟?

时间:2014-07-15 09:31:17

标签: javascript ajax

我正在编写一个使用WebGL在视口中渲染3d模型的网页,我很困惑为什么在加载3d模型后需要延迟。 3d模型是一个.OBJ文件,我使用一个库(K3D.js)来加载&解析.OBJ文件。

我意识到必须将文件异步加载到浏览器中。但据我所知,图书馆处理这部分。这是K3D加载函数的样子:

K3D.load = function(path, resp)
{
    var request = new XMLHttpRequest();
    request.open("GET", path, true);
    request.responseType = "arraybuffer";
    request.onload = function(e){resp(e.target.response);};
    request.send();
}

因此,当K3D完成加载文件时,它可能会执行存储在request.onload中的函数,我在我的Mesh类中提供了函数(在meshFromOBJ方法中):

Mesh.prototype.meshFromArray = function( vertexArray, normalArray ) {
    this.vbo = this.gl.createBuffer();
            //normals are left out for now
    this.numVertices = vertexArray.length / 3.0;
    this.gl.bindBuffer( this.gl.ARRAY_BUFFER, this.vbo );
    this.gl.bufferData( this.gl.ARRAY_BUFFER, 
        new Float32Array( vertexArray ), 
        this.gl.STATIC_DRAW 
    );
    this.gl.bindBuffer( this.gl.ARRAY_BUFFER, null );
};

Mesh.prototype.meshFromOBJ = function( file ) {

    var that = this;

    var loader = function( data ) {
        var model = K3D.parse.fromOBJ( data );
        var array = K3D.edit.unwrap( model.i_verts, model.c_verts, 3 );
        var norms = K3D.edit.unwrap( model.i_norms, model.c_norms, 3 );
        that.meshFromArray( array, model.c_norms );
    }

    K3D.load( file, loader );
};

在我的主脚本中,我加载网格,并设置顶点属性指针。我注意到我必须在加载网格和设置指针之间发出警报,否则浏览器会抛出vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding错误。我脚本的相关部分:

        mesh = new ngl.Mesh( webgl );
        mesh.meshFromOBJ( "cow.obj" );
        //set the vertex attribute pointer with a delay
        //otherwise, the mesh doesn't seem to exist yet :S
        setTimeout( function() {
            mesh.bind();
            webgl.vertexAttribPointer( program.attribute( "vert" ), 
                3, webgl.FLOAT, false, 12, 0 
            );
            mesh.unbind();
        }, 10 );

为什么需要延迟?

1 个答案:

答案 0 :(得分:0)

留出时间让ajax请求完成。而不是使用一些任意的时间延迟,您应该在请求完成后继续执行。如果请求的完成时间超过10毫秒怎么办?很简单,你的代码爆炸了。即K3D的request.onload在 K3D完成后触发

一目了然,修复代码以消除延迟应该就像在<{1}}函数中放置以下 功能一样简单。

loader

由于您可能希望在每个网格加载后对它们执行不同的操作,因此在mesh.bind(); webgl.vertexAttribPointer( program.attribute( "vert" ),3, webgl.FLOAT, false, 12, 0); mesh.unbind(); 完成后指定要调用的函数可能更有意义。

that.meshFromArray

//最后,用法

Mesh.prototype.meshFromOBJ = function( file, whatToDoWhenMeshMade ) {

    var that = this;

    var loader = function( data ) {
        var model = K3D.parse.fromOBJ( data );
        var array = K3D.edit.unwrap( model.i_verts, model.c_verts, 3 );
        var norms = K3D.edit.unwrap( model.i_norms, model.c_norms, 3 );
        that.meshFromArray( array, model.c_norms );
        if (whatToDoWhenMeshMade != undefined)
            whatToDoWhenMeshMade(that);
    }

    K3D.load( file, loader );
};

function setupVertAttribPointer(meshObj)
{
    mesh.bind();
    webgl.vertexAttribPointer( program.attribute( "vert" ), 3, webgl.FLOAT, false, 12, 0);
    mesh.unbind();
}

因此,mesh = new ngl.Mesh( webgl ); mesh.meshFromOBJ( "cow.obj", setupVertAttribPointer); 将调用meshFromObj,这将启动ajax请求。请求完成后,K3D.load将会触发。就在返回之前,meshFromObj.loader将会运行。

如果您在setupVertAttribPointer和(2)之后立即添加一些代码打印到控制台(1)作为mesh.meshFromObj("cow.obj", setupVertAttribPointer);的最后一行,您现在认为哪一个会首先打印?如果您回答(1)那么我在解释ajax中的A所代表的工作就完成了。如果您回答(2),您应该找到一个好的ajax教程。