three.js中合并多个BufferGeometry类型的模型

时间:2021-10-23 05:28:53

在three.js中,合并模型可以通过它的扩展库ThreeBsp.js来办到。不过当模型稍微较复杂时,操作时间会延长,且浏览器容易崩溃。其实three.js自己也提供了这个功能,那就是通过THREE.GeometryUtils.merge来实现。

 

具体实现:

  假如要合并模型A、B、C。

var mesh = new THREE.Geometry();

THREE.GeometryUtils.merge(mesh,A);
THREE.GeometryUtils.merge(mesh,B);
THREE.GeometryUtils.merge(mesh,C);
var material = new THREE.MeshLambertMaterial({ color: '0xff074f' });
var result = new THREE.Mesh(mesh, material);

此时的result便是合并后的模型了。

但是,存在一个问题,对于类型为BufferGeometry的模型来说,此方法是无效的。

幸运的是,在THREE.BufferGeometry中也存在着merge方法,因此试着将代码改为了

var mesh = new THREE.BufferGeometry();

mesh.merge(A.geometry);
mesh.merge(B.geometry);
mesh.merge(C.geometry);

var material = new THREE.MeshLambertMaterial({ 
  color: '0xff074f'
});

var result = new THREE.Mesh(mesh, material);

 

结果报了错

three.js中合并多个BufferGeometry类型的模型

试了几种方法,都失败了,然后在网上找到了一种解决方法:

var model = [A, B, C];
var mesh = new THREE.BufferGeometry();    
var posLen = 0;
var normLen = 0;
var sumPosCursor = 0;
var sumNormCursor = 0;

for (var i=0;i<model.length;i++)
{
    posLen += model[i].geometry.getAttribute('position').array.length;
    normLen += model[i].geometry.getAttribute('normal').array.length;
}
                
var sumPosArr = new Float32Array(posLen);
var sumNormArr = new Float32Array(normLen);
                
for (var i=0;i<model.length;i++)
{
    var posAttArr = model[i].geometry.getAttribute('position').array;
    for (var j=0;j<posAttArr.length;j++)
    {
        sumPosArr[j+sumPosCursor] = posAttArr[j];
    }
    sumPosCursor += posAttArr.length;
                
    var numAttArr = model[i].geometry.getAttribute('normal').array;
    for (var j=0;j<numAttArr.length;j++)
    {
        sumNormArr[j+sumNormCursor] = numAttArr[j];
    }
    sumNormCursor += numAttArr.length;
}
    
mesh.addAttribute('position', new THREE.BufferAttribute(sumPosArr, 3 ));
mesh.addAttribute('normal', new THREE.BufferAttribute(sumNormArr, 3 ));

var material = new THREE.MeshLambertMaterial({
  color: '0xff074f'
});
var result = new THREE.Mesh(mesh, material);

 3个BufferGeometry类型的模型成功合并,但是,存在一个问题,合并后的模型丢失了之前3个模型的独自的位置信息,导致合并之后3个模型重合到了一起。

因此,选择了另外一种方案:首先将这三个模型都转换为Geometry类型的模型,然后进行合并。

var model = [A, B, C];

for(var i=0;i<model.length;i++){
    model[i].geometry = new THREE.Geometry().fromBufferGeometry(model[i].geometry);
}

var mesh = new THREE.Geometry();
for(var i=0;i<model.length;i++){
    THREE.GeometryUtils.merge(mesh,model[i]);
}

var material = new THREE.MeshLambertMaterial({ 
  color: '0xff074f'
});

var result = new THREE.Mesh(mesh, material);

测试发现,成功合并了3个模型,且保留了各自之前所在的位置,旋转等信息。