Model Rotation: Automatic & Mouse Mapped Issue

Hello, I’m creating an interactive animation for a friend which moves a model with mouseX & mouseY as well as has automatic movement if the cursor is off the canvas. However when off the canvas, there is no continuity between the previous angle and the new automatic angle. Any help regarding this issue is greatly appreciated. Thanks!

let coin;
let angleX;
let angleY;
let angleZ;

function preload() {
  coin = loadModel('COIN.obj')
}

function setup() {
  createCanvas(400, 400, WEBGL);
  angleMode(DEGREES);
}
function draw() {
  rotateY(0);
  scale(0.5);
  background(220);
  background('teal');
  angleX = map(mouseY, 0, 400, 30, -30);
  angleY = map(mouseX, 0, 400, -30, 30);
  if (mouseX < width && mouseY < height) {
    rotateX(angleX);
    rotateY(angleY);
  } else {
    rotateZ(map(frameCount, 0, 60, -5, 5));
    rotateX(map(frameCount, 0, 60, -5, 5));
    rotateY(map(frameCount, 0, 60, -5, 5));
  }
  normalMaterial();
  model(coin);
  translate(width / 2, height / 2);
}

Hi,

Welcome to the forum! :wink:

Here is a working version of the code with comments :

let coin;

let angleX = angleY = angleZ = 0;

// The rotation speed of the coin
const rotationSpeed = 0.5;

function preload() {
  coin = loadModel('COIN.obj')
}

function setup() {
  createCanvas(400, 400, WEBGL);
  angleMode(DEGREES);
}

function draw() {
  background('teal');

  if (mouseX < width && mouseY < height) {
    // Use the mouse as pointer
    angleX = map(mouseY, 0, width, 30, -30);
    angleY = map(mouseX, 0, height, -30, 30);
    angleZ = map(mouseX + mouseY, 0, width + height, -30, 30);
  } else {
    // Increase coin rotation
    angleX += rotationSpeed;
    angleY += rotationSpeed / 2;
    angleZ += rotationSpeed;
  }

  // Scale before rotation
  scale(0.5);

  // Always rotate the same way
  rotateZ(angleZ);
  rotateX(angleX);
  rotateY(angleY);

  // Display the coin
  normalMaterial();
  model(coin);
}

Few notes :

  • I removed unused instructions (like background(220) or rotateY(0)) because they are not necessary and your code becomes less readable.

  • The solution I found to have continuity between the two states is to apply a rotation on both 3 axis because you were only moving the coin on X and Y but it’s tedious to compute the resulting Z rotation in order to start from it when in automatic mode.

    So when the mouse is no more inside the canvas we increase the angles so it’s starting from the last computed value.

  • When using the map() function, directly use the width and height variables so if you change the size of the canvas, you don’t need to change the value 400 in all the places in your code. It’s the power of variables :grinning:

  • You can use this trick : let angleX = angleY = angleZ = 0; to initialize any number of variables you want to a certain value.

    Note that you can also use destructuring assignment in JavaScript to do this (more verbose…) :

    let angleX, angleY, angleZ;
    
    [angleX, angleY, angleZ] = [0, 0, 0];
    

Hope it helps! :yum:

1 Like