我正在编写一个使用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 );
为什么需要延迟?
答案 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教程。