Threejs与多种材料合并仅适用于一种材料

时间:2015-08-13 16:59:46

标签: three.js

我已经搜索了这个并在stackoverflow上找到了几个例子,但答案并没有解决我的问题。

我尝试了什么:

首先,我创建要用于组的几何桶和用于存储材料的数组。

var totalGeom = new THREE.Geometry();
var materials = [];

然后我使用for循环遍历我的数据(strData)并调用addMapMarker3d。

  for(var i=0; i<strData.length;i++){
     addMapMarker3d([strData[i].lat,strData[i].lon], strData[i].time, measureColors[i]);
  }

addMapMarker3d函数如下:

addMapMarker3d = function(latLng, height, color){
  var max = 600;
  var dist = 25;
  var opacity = (height/max);

  var geometry = new THREE.BoxGeometry( Math.floor(dist), height, Math.floor(dist));

  //create the material and add it to the materials array
  var material = new THREE.MeshBasicMaterial({ transparent:true, color: Number(color), opacity:opacity});
  this.materials.push(material);

  //create a mesh from the geometry and material.
  var cube = new THREE.Mesh( geometry, material);

  //leaf is a simple lat/lng to pixel position converter
  var actualMarkerPos = leaf.getPoint(latLng);
  //apply the position on a 5000x5000 cartesian plane
  var extent = 5000;
  cube.position.setZ((actualMarkerPos[1] * extent) - extent/2);
  cube.position.setX(-((actualMarkerPos[0] * extent) - extent/2));
  cube.position.setY(height/2);

  //update the matrix and add the cube to the totalGeom bucket
  cube.updateMatrix();
  totalGeom.merge( cube.geometry, cube.matrix);
}

在for循环运行并创建所有多维数据集之后:

  var mats = new THREE.MeshFaceMaterial(materials)
  var total = new THREE.Mesh(totalGeom, mats);

  world.scene.add(total);

问题

虽然几何合并功能,并且我的视口正在以大大改进的FPS运行,但所有立方体都具有完全相同的颜色和不透明度。似乎合并使用的是我提供的10k的单一材料。 是否有某种方法可以确保几何图形使用数组中提供的材料?我做错了吗?

如果我在addMapMarker3d中尝试这个:

totalGeom.merge( cube.geometry, cube.matrix, materials.length-1);

我得到“Uncaught TypeError:无法读取属性'透明'未定义”并且没有渲染,我不明白,因为通过示例,每个几何应该索引到材质数组中的材质。

three.js r.70

3 个答案:

答案 0 :(得分:4)

以下技术仅使用一种材质,但允许您保留每个合并对象的单独颜色。我不知道是否可以保留每个合并对象的单个alpha。

http://jsfiddle.net/looshi/nsknn53p/61/

对于每个网格,设置其每个geometry.faces颜色:

function makeCube(size, color) {
    var geom = new THREE.BoxGeometry(size, size, size);

    for (var i = 0; i < geom.faces.length; i++) {
        face = geom.faces[i];
        face.color.setHex(color);
    }
    var cube = new THREE.Mesh(geom);
    return cube;
}

然后,在要嵌入的父几何体中,设置其材质vertexColors属性。

var parentGeometry = new THREE.Geometry();
var parentMatrial = new THREE.MeshLambertMaterial({
    color: 0xffffff,
    shading: THREE.SmoothShading,
    vertexColors: THREE.VertexColors
});


   // in a loop you could create many objects and merge them
for (var i = 0; i < 1000; i++) {
      cube = makeCube(size, color);
      cube.position.set(x, y, z);
      cube.rotation.set(rotation,rotation,rotation);
      cube.updateMatrix()
      parentGeometry.merge(cube.geometry, cube.matrix);
}
// after you're done creating objects and merging them, add the parent to the scene 
parentMesh = new THREE.Mesh(parentGeometry, parentMatrial);
scene.add(parentMesh);

答案 1 :(得分:4)

我的原始问题没有得到解答:是否有某种方法可以确保几何图形使用数组中提供的材料?

答案是肯定的。合并期间可以将多种材质应用于单个网格。将材质推入材质阵列后,合并将使用几何面材质索引。当一个数组被提供给新的THREE.MeshFaceMaterial([materialsArray])时,合并将应用多个材质,因为创建了总网格。这解决了语法之谜。仅仅因为您提供了一系列材料并不意味着合并将以迭代的方式使用每种材质,因为对象是从r71开始合并的。面必须通知合并材料数组中要使用的材料。

我将它用于非渲染场景,并导出最终的obj。如果需要渲染性能,请参阅某些选项的其他答案之一。

几何体上的面数组上的简单for循环通知合并要应用的材质:

  addMapMarker3d = function(latLng, height, color){
  var max = 600;
  var dist = 25;
  var opacity = (height/max);

  var geometry = new THREE.BoxGeometry( Math.floor(dist), height, Math.floor(dist));

  //create the material and add it to the materials array
  var material = new THREE.MeshBasicMaterial({ transparent:true, color: Number(color), opacity:opacity});
  this.materials.push(material);

  //set the material index of each face so a merge knows which material to apply
  for ( var i = 0; i < geometry.faces.length; i ++ ) {
    geometry.faces[i].materialIndex = this.materials.length-1;
  }

  //create a mesh from the geometry and material.
  var cube = new THREE.Mesh( geometry, material);

  //leaf is a simple lat/lng to pixel position converter
  var actualMarkerPos = leaf.getPoint(latLng);
  //apply the position on a 5000x5000 cartesian plane
  var extent = 5000;
  cube.position.setZ((actualMarkerPos[1] * extent) - extent/2);
  cube.position.setX(-((actualMarkerPos[0] * extent) - extent/2));
  cube.position.setY(height/2);

  //update the matrix and add the cube to the totalGeom bucket
  cube.updateMatrix();
  totalGeom.merge( cube.geometry, cube.matrix);
}

答案 2 :(得分:2)

您看到改进性能的唯一原因是,在合并之后,只有一种材料。如果您希望场景包含多种材质,则不应合并。

添加到同一组:

var group = new THREE.Object3D();
group.add (object1);
group.add (object2);
group.add (object3);