0

I have a grid that contains boxes, very similar to http://threejs.org/examples/#canvas_interactive_voxelpainter. Now I initiated a hover state when a box on the scene is mouseover it turns the background gray. Which is great! Except when I multiple "box" on the grid and I go to change the material background color of the hovered item, it renders all of the "box's" with a gray background.

Heres what I am doing:

var voxel = new THREE.Mesh( this.cubeGeometry, this.cubeMaterial );
voxel.position.copy( intersect.point ).add( intersect.face.normal );
voxel.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );
this.scene.add( voxel );
this.blocks.push( voxel );
var domEvents   = new THREEx.DomEvents(this.camera, this.renderer.domElement)
// DOM events for inside 3d rendering
domEvents.addEventListener(voxel, 'mouseover', this.onDocumentMouseOverCube.bind(this),false);
domEvents.addEventListener(voxel, 'mouseout', this.onDocumentMouseOutCube.bind(this),false);

Here we create our box - we than give it eventListeners for that specific mesh. Once this mesh is hovered over, our mouseover is executed:

this.mouse.x = ( event.origDomEvent.clientX / this.renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( event.origDomEvent.clientY / this.renderer.domElement.height ) * 2 + 1;

this.raycaster.setFromCamera( this.mouse, this.camera );
var intersects = this.raycaster.intersectObjects( this.blocks );
if ( intersects.length > 0 ) {

    var intersect = intersects[ 0 ];

    if ( intersect.object != this.plane ) {
        console.log(intersect.object);


        // update color on hover
        intersect.object.material.color.setHex(this.colorHover);
        console.log("hover color");
        this.render();
    }
}

Now this works great, the only issue is - this.render() is called (this.renderer.render( this.scene, this.camera )) like it should be. But when I have multiple box's on it goes ahead and changes every single background color of each box I have even logged all my objects to confirm object.material.color is the gray hex for only one box and that not all of the box's are being set, which proves to be true. I am sending the correct data over. So I am assuming it has to do with the rendering of the actual engine?

Suggestions?

WestLangley
  • 102,557
  • 10
  • 276
  • 276
David Biga
  • 2,763
  • 8
  • 38
  • 61

1 Answers1

0

There is only one instance of the material, which is shared among the meshes. The easy solution is to clone the material for each mesh:

var voxel = new THREE.Mesh( this.cubeGeometry, this.cubeMaterial.clone() );

Now every box accepts its own color.


I dont know if this still applies but thinking about performance you would want to go with a custom shader material, because the attributes and vertex/fragment programs are copied by reference then. See this post Three.js, sharing ShaderMaterial between meshes but with different uniform sets.

Example code:

var phongShader = THREE.ShaderLib.phong;
this.shaderMaterial = new THREE.ShaderMaterial({
    uniforms: phongShader.uniforms,
    vertexShader: phongShader.vertexShader,
    fragmentShader: phongShader.fragmentShader,
    lights:true
});
var voxel = new THREE.Mesh( this.cubeGeometry, this.shaderMaterial.clone() );

And then you change the color via uniforms like so:

intersect.object.material.uniforms.diffuse.value.setHex( this.colorHover );

Three.js r.71

PS: cloning the default Phong material in r.71 also shows only one programm in the renderer info for me, so maybe Three.js is optimizing this internally.

Community
  • 1
  • 1
Falk Thiele
  • 4,424
  • 2
  • 17
  • 44