Set color to object

Hi guys I have major problem please help me.
I have object and clicking on it I need to set new style,
I tried to set color by this approach:

if(intersects[0]){
	for ( var i = 0; i < intersects.length; i++ ) {
		intersects[0].object.material.color.setHex( 0xff0000 )
	}
}

But unfortunatly main object gets color

If it’s a complex model (with more than one mesh etc.) you have to traverse it’s children and set color to every one of them.

model.traverse((child) => {
  if (child.material) {
    child.material.color.setHex(0xff0000);
  }
});
2 Likes

Do you wanna color the whole model? Because when raycasting, its possible that you receive a child of your model in intersects. Then you would need to search for the parent container first.

// When loading your model, set a bool on the model container
loader.load('PATH', (model)=> {

    model.userData.isContainer = true
})

// When searching, look for isContainer == true
// Recursive function that checks if is container else does the same for its parent and parents parent and so on
function getContainer(childObj) {

  if(childObj.userData.isContainer == true) return childObj

  if(childObj.parent != null) return getContainer(childObj.parent)

  return null
}

// Get container by child
let container = getContainer(intersects[0].object])
// Go through all childs of container and color all
container.traverse((child) => {
  if (child.material) {
    child.material.color.setHex(0xff0000);
  }
})


On click event I am getting this object and I want to change color only for this part.But you can see that after changing color it changes main object

Also You can see that I have all children.how Can I change only one children color?
Thanks a lot

I add more details , please hav a look

Yep - but it would be easier if you shown us your code for clicking.

here it is , my all codes

Code, my man, not a screenshot of code :’) (can be just the part with raycasting and changing material color.)

threejs - models #floor{ position: absolute; width: 350px; bottom: 50%; }
import * as THREE from '../build/three.module.js';
		import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
		import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';
		import { OrbitControls } from './jsm/controls/OrbitControls.js';
		var camera, scene, renderer;

		let floorInfos = {
			floor1: {
			desc: `FLOOR 1 PLAN
				Scale: 1/4 "= 1' or larger
				Show each floor.
				State square footage of residence, garage, decks covered & decks not covered.
				Location of plumbing fixtures, appliances, fireplace, type and location of heating system.
				Window size and type, floor size and type, door size and type, direction of door swing.`
			},
			floor2: {
			desc: `FLOOR 2 PLAN
				Scale: 2/3 "= 1' or larger
				Show each floor.
				In this new interface the experience is as follows: the user approaches 
				the mouse to any room, automatically a blinking message appears over the
				 room and it shows the information about required performance for the selected
				  room. When the mouse is removed from the room, the information disappears and information about
				 other rooms can be inquired by only approaching the mouse without clicking the room..`
			},
			floor3: {
			desc: `FLOOR  3 PLAN
				Scale: 3/4 "= 1' or larger
				Show each floor.
				The main advantage of this framework is that designers can
				 decide crucial aspects of the project (orientation, size, room distribution) using 
				real information from existing standards or norms in an integrated digital environment. .`
			},
			floor4: {
			desc: `FLOOR 4 PLAN
				Scale: 4/1 " = 1' or larger
				Show each floor.
				State square footage of residence, garage, decks covered & decks not covered.`
			},
		}

		// Instantiate a loader
		var loader = new GLTFLoader();
		var renderer;

		var scene = new THREE.Scene();
		var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
		let floor = document.getElementById("floor");
		floor.style.display = 'none';
		let model;

			renderer = new THREE.WebGLRenderer( { alpha: true } );
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( renderer.domElement );

			var controls = new OrbitControls( camera, renderer.domElement );
			controls.addEventListener( 'change', render );
			controls.target.set( 0, 1.2, 2 );
			// controls.minDistance = 100;
			// controls.maxDistance = 10;
			controls.update();

			window.addEventListener( 'resize', onWindowResize, false );
			function render() {

				renderer.render( scene, camera );

				}

			function onWindowResize() {
						camera.aspect = window.innerWidth / window.innerHeight;
						camera.updateProjectionMatrix();
						renderer.setSize( window.innerWidth, window.innerHeight );
							render();
			}

				//LIGHTING START
					renderer.setClearColor(0xEEEEEE);
					renderer.setSize(window.innerWidth, window.innerHeight);
					renderer.shadowMapEnabled = true;
					var ambientLight = new THREE.AmbientLight(0x0c0c0c);
					scene.add(ambientLight);
					var spotLight = new THREE.SpotLight(0xfffffffff);
					spotLight.position.set(-40, 60, -10);
					spotLight.castShadow = false;
					scene.add(spotLight);
					camera.position.x = -30;
					camera.position.y = 40;
					camera.position.z = 30;
					camera.lookAt(scene.position);
				//END

			var dracoLoader = new DRACOLoader();
			dracoLoader.setDecoderPath( '/examples/js/libs/draco/' );
			loader.setDRACOLoader( dracoLoader );

			var toIntersect = [];

			// Load a glTF resource
			loader.load(
				'./files/test55.gltf',
				function ( gltf ) {
					console.log('model', gltf)
					camera.position.z = 40;
					scene.add( gltf.scene );
					var t = gltf.scenes[0].children;
					scene.traverse(function (m) {
						if (m instanceof THREE.Mesh) {
							toIntersect.push(m);
						}
					});
				},
				// called while loading is progressing
				function ( xhr ) {
					//console.log('done')
					//console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );

				},
				// called when loading has errors
				function ( error ) {
					//console.log(error);
				}
			);
			

			var raycaster, mouse = { x : 0, y : 0 };
			raycaster = new THREE.Raycaster();
			var mouse = new THREE.Vector2();

			renderer.domElement.addEventListener( 'click', raycast, false );
		

			function raycast ( e ) {

				mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
				mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
				raycaster.setFromCamera( mouse, camera );

				// calculate objects intersecting the picking ray
				var intersects = raycaster.intersectObjects( scene.children, true );

				console.log('intersects',intersects)

				if(intersects && intersects[0]) {
					floor.style.display = 'inline-block';

				// console.log(intersects[0].object.parent.userData)

					let floorName = intersects[0].object.parent.userData.name;
					if(floorName === 'floor_1'){
						console.log('jhvju')
						floor.innerHTML = floorInfos.floor1.desc;
					} else if (floorName === 'floor_2'){
						floor.innerHTML = floorInfos.floor2.desc;
					}
					else if (floorName === 'floor_3'){
						floor.innerHTML = floorInfos.floor3.desc;
					}
					else if (floorName === 'floor_4'){
						floor.innerHTML = floorInfos.floor4.desc;
					}
			}   else{
				   floor.style.display = 'none';
			}
					 if(intersects[0]){
						for ( var i = 0; i < intersects.length; i++ ) {
							intersects[0].object.material.color.setHex( 0xff0000 )
						}
					}
					
						

				renderer.render( scene, camera );

				}
				setTimeout(()=> {
					render();

				}, 1000)
</script>
1 Like

test55.gltf (80.6 KB)
Here is file :slight_smile:

  1. Raycasting is alright (it’s basically your code, just removed for loop):
function raycast ( e ) {
  mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
  raycaster.setFromCamera( mouse, camera );
  var intersects = raycaster.intersectObjects( scene.children, true );
  
  // ...

  if(intersects[0]){
    intersects[0].object.material.color.setHex( 0xff0000 );
  }
  
  renderer.render( scene, camera ); // Note: No need to call that here
}
  1. Checking it in the glTF viewer, it seems like your entire model uses only one material - so if you change the color for any part of it, the rest will automatically inherit the new color. What you can do is either separate materials for each child - or, easier, you can try to clone the material when you want to override its color (clone only when necessary tho):
// ...

var raycaster, mouse = { x : 0, y : 0 };
raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

// (1) Save global material
var sharedMaterial;

renderer.domElement.addEventListener( 'click', raycast, false );

function raycast ( e ) {
  // ...

  if(intersects[0] && intersects[0].object.material){
    if (!sharedMaterial) {
      // (2) If sharedMaterial wasn't set, set it now
      sharedMaterial = intersects[0].object.material;
    }

    if (intersects[0].object.material === sharedMaterial) {
      // (3) If child uses the global material, clone it first
      intersects[0].object.material = intersects[0].object.material.clone();
    }

    // (4) Change the color on the cloned material, leaving global one intact
    intersects[0].object.material.color.setHex(0xff0000);
  }
}
2 Likes

It works thank you bro :slight_smile:
What can I do for you :slight_smile: ?
I am from Armenia , you can be sure you have one friend here

2 Likes

hello there, I am also facing a similar issue; this fix helps greatly. But how can reverse to the old color ? It would be a great help