jorgeb
jorgeb

Reputation: 23

Change color of InstancedMesh dynamically in Three.js

I am trying in Three.js to randomly change the color of an instance of an instancedMesh on a button click event with no success.

let instancesCount = 10;
let matrix = new THREE.Matrix4();
let geometry = new THREE.BoxBufferGeometry(1, 1, 1);
let material = new THREE.MeshLambertMaterial();
let mesh = new THREE.InstancedMesh(geometry, material, instancesCount);
scene.add(mesh);

const clickHandler = (e) => {

  let max = instancesCount-1;
  let min = 0;
  let index = Math.floor(Math.random() * (max - min) + min);

  let x = Math.floor(Math.random() * (max - min) + min);
  let y = Math.floor(Math.random() * (max - min) + min);
  let z = Math.floor(Math.random() * (max - min) + min);

  matrix.setPosition(x, y, z);
  mesh.setMatrixAt(index, matrix);
  mesh.setColorAt(index, new THREE.Color(0xffffff * Math.random()));
  mesh.instanceMatrix.needsUpdate = true;
  mesh.instanceColor.needsUpdate = true;
}

Upvotes: 1

Views: 2191

Answers (1)

prisoner849
prisoner849

Reputation: 17586

Add matrix.makeScale(1, 1, 1) right before matrix.setPosition(x, y, z):

body{
  overflow: hidden;
  margin: 0;
}
<button id="btn_rand" style="position: absolute;margin: 5px;">
  PressMe
</button>
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.setScalar(15);
let renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x202020);
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

new OrbitControls(camera, renderer.domElement);

let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));

scene.add(new THREE.GridHelper(20, 20));

let instancesCount = 10;
let matrix = new THREE.Matrix4();
let color = new THREE.Color();
let geometry = new THREE.BoxBufferGeometry(1, 1, 1);
let material = new THREE.MeshLambertMaterial({color: "white"});
let mesh = new THREE.InstancedMesh(geometry, material, instancesCount);
new Array(10).fill(0).forEach((c, i) => {mesh.setColorAt(i, color.set(0xffffff))});
scene.add(mesh);

btn_rand.addEventListener("click", clickHandler);

function clickHandler (e) {

  let max = instancesCount-1;
  let min = 0;
  let index = THREE.MathUtils.randInt(min, max);

  let x = Math.floor(Math.random() * (max - min) + min);
  let y = Math.floor(Math.random() * (max - min) + min);
  let z = Math.floor(Math.random() * (max - min) + min);
    
  
  matrix.makeScale(1, 1, 1);
  matrix.setPosition(x, y, z);
  mesh.setMatrixAt(index, matrix);
  mesh.setColorAt(index, color.set(0xffffff * Math.random()));
  mesh.instanceMatrix.needsUpdate = true;
  mesh.instanceColor.needsUpdate = true;
}

renderer.setAnimationLoop( _ => {
    renderer.render(scene, camera);
})
</script>

Upvotes: 3

Related Questions