Skip to content
Advertisement

(Three.js) How to slowly rotate a mesh until it reaches a specific value

I’ve just gotten into Three.JS, and I’ve ran into an issue. I’m trying to make a car, that is drivable using the Arrow Keys. So far, I’ve gotten it to move forwards, and backwards, and the wheels turn when you press Up (Forwards) and Down (Backwards). So, logically, the next step would be turning. However, that’s where I run I to my issue.

I can’t figure out how to make it so that when I press the left or right arrow keys, it will slowly, gradually increase the rotation of the wheels, until they reach a certain value, say, 45 for left, and -45 for right.

I have a cube, stretched out to the shape of a mostly flat rectangle, called chassis. I have four wheels, Wheel_FL, FR, RL, and RR. F meaning Front, First R meaning rear, L meaning Left, Second R meaning right. Both Wheel_FL and Wheel_FR have a group as their parent, which I will use to rotate them left or right, they act as a pivot. I cannot figure out how to do this, I’ve tried looking for an answer everywhere for the past couple of days, to no avail. If anyone has any ideas, please, let me know! And if anyone needs any more information, please, let me know!

I’m also looking for a way to, then, once this steering issue is fixed, to rotate the chassis itself in a way that is realistic to how a car would turn.

Thanks!

If anyone needs an example, I have one here.

Advertisement

Answer

I can help you with the first part of the question:

Let’s name the variables: Wheel_FL, Wheel_FR, Group_FL, Group_FR;. Each wheel is nested inside its respective group with Group_FL.add(Wheel_FL);

So to spin the wheels, you’d probably do Wheel_FL.rotation.x += spinAngle; or maybe rotation.z based on the orientation of your asset. Now to steer left/right, you’d want to rotate the container Group so it doesn’t interfere with the spinning angle: Group_FL.rotation.y = steerAngle;

To animate, or tween this steering angle, you could use the MathUtils.lerp() function (lerp stands for Linear-interpolation), which takes a variable and eases it towards its target.

var Wheel_FL, Wheel_FR;
var Group_FL = new THREE.Group();
var Group_FR = new THREE.Group();
Group_FL.add(Wheel_FL);
Group_FR.add(Wheel_FR);

var spinAngle = 0;
var steerAngle = 0;
var steerAngleTarget = 0;

function update() {
    // Update wheel spin
    Wheel_FL.rotation.x += spinAngle;
    Wheel_FR.rotation.x += spinAngle;

    // Tween steering angle towards target
    steerAngle = MathUtils.lerp(steerAngle, steerAngleTarget, 0.1);

    // Rotate parent group around y-axis
    Group_FL.rotation.y = steerAngle;
    Group_FR.rotation.y = steerAngle;
}

function steerLeft() {
    steerAngleTarget = Math.PI / 4; // 45 deg in radians
}

function steerRight() {
    steerAngleTarget = - Math.PI / 4; // -45 deg in radians
}

I’ve created a working demo for you below. Use w-a-s-d keys to steer, accelerate, and decelerate:

var camera, scene, renderer, clock, container;

container = document.getElementById( 'container' );

camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 100 );
camera.position.y = 10;
camera.position.z = 5;
camera.lookAt(0, 0, 0);

scene = new THREE.Scene();
scene.background = new THREE.Color( 0xeeeeee );
scene.fog = new THREE.Fog( 0xcccccc, 100, 1500 );

clock = new THREE.Clock();

var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x222222, 1.5 );
hemiLight.position.set( 1, 1, 1 );
scene.add( hemiLight );

var floor = new THREE.Mesh(new THREE.PlaneBufferGeometry(10, 10), new THREE.MeshBasicMaterial({color: 0x999999}));
floor.rotation.x = -Math.PI/2;
scene.add(floor);

renderer = new THREE.WebGLRenderer();
renderer.setSize( container.offsetWidth, container.offsetHeight );
container.appendChild( renderer.domElement );

window.addEventListener( 'resize', onWindowResize, false );
window.addEventListener("keydown", onKeyPress);
window.addEventListener("keyup", onKeyRelease);

// Create wheels
var Wheel_FL = new THREE.Mesh(
    new THREE.CylinderBufferGeometry(1, 1, 1, 8),
  new THREE.MeshBasicMaterial({color: 0xffff00, wireframe: true})
);
var Wheel_FR = new THREE.Mesh(
    new THREE.CylinderBufferGeometry(1, 1, 1, 8),
  new THREE.MeshBasicMaterial({color: 0xffff00, wireframe: true})
);
var Group_FL = new THREE.Group();
var Group_FR = new THREE.Group();

// Set initial positions and rotations
Wheel_FL.position.y = 1;
Wheel_FR.position.y = 1;
Wheel_FL.rotation.z = Math.PI / 2;
Wheel_FR.rotation.z = Math.PI / 2;

// Add wheels to group, and position groups
Group_FL.add(Wheel_FL);
Group_FR.add(Wheel_FR);
Group_FL.position.x = -2;
Group_FR.position.x = 2;
scene.add(Group_FL);
scene.add(Group_FR);

var spinAngle = 0;
var steerAngle = 0;
var steerAngleTarget = 0;

// WASD to turn, accelerate, and decelerate
function onKeyPress(evt) {
    switch(evt.key) {
    case 'a':
        steerAngleTarget = Math.PI / 6; // 45 deg in radians
    break;
    case 'd':
        steerAngleTarget = - Math.PI / 6; // -45 deg in radians
    break;
    case 'w':
        spinAngle += 0.01; // accelerate
    break;
    case 's':
        spinAngle -= 0.01; // decelerate
    break;
  }
}

// Returns wheels to center
function onKeyRelease() {
    steerAngleTarget = 0;
}

function onWindowResize() {
    camera.aspect = container.offsetWidth / container.offsetHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( container.offsetWidth, container.offsetHeight );
}

function update() {
  // Update wheel spin
  Wheel_FL.rotation.x -= spinAngle;
  Wheel_FR.rotation.x -= spinAngle;

  // Tween steering angle towards target
  steerAngle = THREE.MathUtils.lerp(steerAngle, steerAngleTarget, 0.1);

  // Rotate parent group around y-axis
  Group_FL.rotation.y = steerAngle;
  Group_FR.rotation.y = steerAngle;
    requestAnimationFrame( update );

    renderer.render(scene, camera);
}

update();
body, html {
  background-color: #fff;
  color: #222;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

#container {
  position: absolute;
  top: 0;
  width: 100%;
  bottom: 0px;
}
<script src="https://cdn.rawgit.com/mrdoob/three.js/dev/build/three.js"></script>
<div id="container">
</div>
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement