Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Threejs merge with multiple materials applies only one material

Tags:

three.js

I have searched on this and found several examples on stackoverflow, but the answers have not solved my problem.

What I have tried:

First I create the geometry bucket to be used for the group and an array to store my materials.

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

I then run through my data (strData) with a for loop and call addMapMarker3d.

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

The addMapMarker3d function is as follows:

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);
}

After the for loop runs and all the cubes are created:

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

  world.scene.add(total);

The question

While the geometry merge functions, and my view port is running at a much improved FPS, all the cubes have exactly the same color and opacity. It appears the merge is using a single material of the 10k I supplied. Is there some way to ensure that the geometry uses the material supplied in the array? Am I doing something incorrect?

If I try this in addMapMarker3d:

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

I get "Uncaught TypeError: Cannot read property 'transparent' of undefined" and nothing renders, which I don't understand, because by the examples, each geometry should index to a material in the materials array.

three.js r.70

like image 925
Radio Avatar asked Dec 25 '22 15:12

Radio


1 Answers

The following technique uses just one material, but allows you to retain the individual color of each merged object. I don't know if it's possible to retain the individual alpha of each merged object.

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

For each mesh, set each of its geometry.faces color :

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;
}

Then, in the parent geometry you are going to mesh into, set its material vertexColors property.

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);
like image 103
looshi Avatar answered Feb 16 '23 00:02

looshi