Three.js not updating color to mesh on runtime

Ok so I´m trying to create a simple program with a simple animation which changes the color of a traffic light from green to red and viceversa every 2 seconds, but the color is not changing.

I have tried debugging the code printing the booleans that should make the code work, and the results are correct but the color is not changing at all. The mesh im trying to change is the one called bombilla, which im trying to change in the changeColor function called every two seconds by setInterval()

  var scene;
  var camera;
  var renderer;
  var cube;
  var cylinder;

  var red = 1;

  //Create the scene to draw
  scene = new THREE.Scene();
  scene.background = new THREE.Color( 0xf0f0f0 );

  //Create orthographic camera and add it to scene
  camera = new THREE.OrthographicCamera( window.innerWidth/-200, window.innerWidth/200, window.innerHeight/200, window.innerHeight/-200, 0.1, 1000 );
  scene.add( camera );

  //Create a renderer for the scene
  renderer = new THREE.WebGLRenderer();
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  cube = new THREE.BoxBufferGeometry( 1, 1, 1 );
  cylinder = new THREE.CylinderGeometry( 0.1, 0.1, 5, 100 );

  var carga =      new THREE.Mesh( cube, new THREE.MeshLambertMaterial( { color:0xA6A6A6 } ) );
  var cabina =     new THREE.Mesh( cube, new THREE.MeshLambertMaterial( { color:0xF2F2F2 } ) );
  var luna =       new THREE.Mesh( cube, new THREE.MeshLambertMaterial( { color:0xf0f0f0 } ) );
  var ventanilla = new THREE.Mesh( cube, new THREE.MeshLambertMaterial( { color:0xF6F6F6 } ) );
  var poste =      new THREE.Mesh( cube, new THREE.MeshLambertMaterial( { color:0x000000 } ) );
  var semaforo =   new THREE.Mesh( cube, new THREE.MeshLambertMaterial( { color:0x000000 } ) );
  var wheel1 =     new THREE.Mesh( cylinder, new THREE.MeshLambertMaterial( { color:0x000000 } ) );
  var wheel2 =     new THREE.Mesh( cylinder, new THREE.MeshLambertMaterial( { color:0x000000 } ) );
  var bombilla =   new THREE.Mesh( cylinder, new THREE.MeshLambertMaterial( { color:0xFF0000 } ) );

  scene.add( carga );
  scene.add(cabina);
  scene.add(luna);
  scene.add(ventanilla);
  scene.add(poste);
  scene.add(semaforo);
  scene.add(wheel1);
  scene.add(wheel2);
  scene.add(bombilla);

  var light = new THREE.DirectionalLight( 0xffffff, 1.5 );
        light.position.set( 2, 1, 5 ).normalize();
        scene.add( light );

  var init = function()
  {
    //Move the camera to be able to see the object
    camera.position.z = 3;

    //Set the truck
    carga.rotation.y = 1;
    carga.rotation.x = 0.5;

    carga.scale.z = 1.5;

    //Set the cabin
    cabina.rotation.y = 1;
    cabina.rotation.x = 0.5;

    cabina.scale.x = 0.75;
    cabina.scale.y = 0.8;
    cabina.scale.z = 0.95;

    cabina.position.x = 0.7;
    cabina.position.y = -0.3;
    cabina.position.z = 0.35;

    //set the windshield
    luna.rotation.y = 1;
    luna.rotation.x = 0.5;

    luna.scale.x = 0.5;
    luna.scale.y = 0.3;
    luna.scale.z = 0.01;

    luna.position.x = 1.1;
    luna.position.y = -0.3;
    luna.position.z = 0.9;

    //set the window
    ventanilla.rotation.y = 1;
    ventanilla.rotation.x = 0.5;

    ventanilla.scale.x = 0.01;
    ventanilla.scale.y = 0.3;
    ventanilla.scale.z = 0.3;

    ventanilla.position.x = 0.7;
    ventanilla.position.y = -0.4;
    ventanilla.position.z = 2;

    //set the front wheel
    wheel1.rotation.y = 1;
    wheel1.rotation.x = 0.5;
    wheel1.rotation.z = 3.1415/2;

    wheel1.scale.x = 1;
    wheel1.scale.y = 0.02;
    wheel1.scale.z = 1;

    wheel1.position.x = 0.7;
    wheel1.position.y = -0.97;
    wheel1.position.z = 0.5;

    //set the back wheel
    wheel2.rotation.y = 1;
    wheel2.rotation.x = 0.5;
    wheel2.rotation.z = 3.1415/2;

    wheel2.scale.x = 1;
    wheel2.scale.y = 0.02;
    wheel2.scale.z = 1;

    wheel2.position.x = -0.5;
    wheel2.position.y = -0.65;
    wheel2.position.z = 0.;

    //set the traffic light stand
    poste.rotation.y = 1;
    poste.rotation.x = 0.5;

    poste.scale.x = 0.2;
    poste.scale.y = 1.5;
    poste.scale.z = 0.2;

    poste.position.x = 2;
    poste.position.y = 0;
    poste.position.z = 0;

    //set the traffic light
    semaforo.rotation.y = 1;
    semaforo.rotation.x = 0.5;

    semaforo.scale.x = 0.2;
    semaforo.scale.y = 0.7;
    semaforo.scale.z = 0.5;

    semaforo.position.x = 2.01;
    semaforo.position.y = 0.4;
    semaforo.position.z = 0;

    //set the light bulb
    bombilla.rotation.y = 1;
    bombilla.rotation.x = 0.5;
    bombilla.rotation.z = 3.1415/2;

    bombilla.scale.x = 1;
    bombilla.scale.y = 0.002;
    bombilla.scale.z = 1;

    bombilla.position.x = 1.95;
    bombilla.position.y = 0.35;
    bombilla.position.z = 0.8;
  };

  var changeColor = function ()
  {
    if(red == 1)
      {
        bombilla.material.color.set(0x0CAB00);
        red = 0;
      }
      else if(red == 0)
      {
        bombilla.material.color.set(0xFF0000);
        red = 1;
      }
  }

  var update = function()
  {
    setInterval(changeColor,2000);
  };

  var render = function()
  {
    renderer.render(scene, camera);
  };

  var GameLoop = function()
  {
    //requestAnimationFrame(GameLoop);
    init();
    update();
    render();
  };

  GameLoop();

1 answer

  • answered 2019-06-12 01:24 ScieCode

    There are two main problems with your code at the moment.

    requesteAnimationFrame() is commented, therefore the scene is only getting rendered once and never again, making any animations or changes to the scene irrelevant.

    The more pronounce problem is using setInterval inside the animation loop to control when to change the material color. You are calling setInterval at every frame update. Which means that, after two seconds, the material will swap colors at every frame update.

    What you need to do, instead, is detect if two seconds have gone by since the last update, and only then execute your changeColor function.

    This logic can be easily controlled using THREE.Clock

    // global scope
    var clock = new THREE.Clock(); //automatically starts clock
    
    // update function
    var update = function() {
      var time = clock.getElapsedTime(); // elapsed time since last reset
      if ( time > 2 ) {
        changeColor();
        clock.start(); // resets clock
      }
    };
    

    JSFiddle