Tutee United
Tutee United

Reputation: 21

Color based on .obj model

I want to set colors according to the height of my model, which is a .obj file. I want the colors to go from green to red, depending on the height, green for the minimum point, red for the maximum. This is my code currently:

loader.load(nombreMapa, function (object) {
    loader.setMaterials(material);
    escena.add(object);
    object.position.y = -10;
    if (object instanceof THREE.Object3D)
    {
    object.traverse (function (mesh)
    {
        if (! (mesh instanceof THREE.Mesh)) return;
        mesh.material = new THREE.MeshNormalMaterial();
        mesh.material.side = THREE.DoubleSide;
        var geometry = new THREE.EdgesGeometry( mesh.geometry );
        var material1 = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1000 } );
        var edges = new THREE.LineSegments( geometry, material1 );
        mesh.add( edges );
    });
}});

Upvotes: 2

Views: 384

Answers (1)

prisoner849
prisoner849

Reputation: 17586

You can do this trick, using THREE.Box3() and .lerp() method of THREE.Color() for setting colors of each vertex in each child's mesh's geometry.

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 60, 250);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x404040);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 60, 0);
controls.update();

var mat = new THREE.MeshBasicMaterial({
  wireframe: true,
  vertexColors: THREE.VertexColors
}); // the same material for all the children of the object

var loader = new THREE.OBJLoader();
loader.load('https://threejs.org/examples/models/obj/male02/male02.obj', function(obj) {

  var size = new THREE.Vector3();
  var box3 = new THREE.Box3().setFromObject(obj);
  box3.getSize(size);
  console.log(size);

  var v3 = new THREE.Vector3(); // for re-use
  
  var c = [
    new THREE.Color(0x00ff00),
    new THREE.Color(0xff0000)
  ];
  var cTemp = new THREE.Color(); // for re-use

  obj.traverse(child => {
    if (child.isMesh) {
      
      let colors = []; // array for color values of the current mesh's geometry
      
      let pos = child.geometry.attributes.position;
      
      for(let i = 0; i < pos.count; i++){
        
        v3.fromBufferAttribute(pos, i);
        
        obj.localToWorld(v3); // box3 is in world coords so we have to convert coortinates of the vertex from local to world
        
        let a = (v3.y - box3.min.y) / size.y; // find the value in range 0..1
        
        cTemp.copy(c[0]).lerp(c[1], a); // lerp the colors
        
        colors.push(cTemp.r, cTemp.g, cTemp.b); // save values in the array
        
        child.geometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3)); // add a buffer attribute for colors
        
        child.material = mat;
      }
    }
  });
  scene.add(obj);
})

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera)
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/loaders/OBJLoader.js"></script>

Also, take a look at this SO answer about other options of how to apply gradient.

Upvotes: 2

Related Questions