【问题标题】:Setting WebGL vertexAttribPointer after loading mesh: why is a delay required?加载网格后设置 WebGL vertexAttribPointer:为什么需要延迟?
【发布时间】:2014-07-15 09:31:16
【问题描述】:

我正在编写一个网页,它使用 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 );

为什么需要延迟?

【问题讨论】:

    标签: javascript ajax


    【解决方案1】:

    让 ajax 请求有时间完成。与其使用任意时间延迟,不如在请求完成后继续执行。如果请求的完成时间超过 10 毫秒怎么办?很简单,你的代码崩溃了。即 K3D 的 request.onload K3D 完成后触发。

    乍一看,修复代码以消除延迟应该很简单,只需将以下功能放入 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 将调用 K3D.load,这将启动 ajax 请求。当请求完成时,meshFromObj.loader 将触发。就在它返回之前,setupVertAttribPointer 将运行。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      相关资源
      最近更新 更多