Rotate GLTF model with Mouse Move

Howdy yall, super new to THREE.JS and could use some help. I have a codepen with a sphere mesh and a jet mesh. Currently the code tells the sphere to rotate in relation to the mouse movement but I would like to apply that rotation to the jet instead. Any help is greatly appreciated. :slightly_smiling_face:

Hello.

I hope this helps you.
Below is the suggest code.

GLTFLoader

let myModel; // NewCode
loader.load('https://assets.codepen.io/1618468/F-16D_1.gltf', function ( gltf ) {
  myModel = gltf.scene; // NewCode
  //adds 3d object to scene after loading
  scene.add(myModel);
 ...etc

animate() Function

onst animate = () =>
{
  targetX = mouseX * .001
  targetY = mouseY * .001

  const elapsedTime = clock.getElapsedTime()

  //Update objects - increase number to create automated animation
  sphere.rotation.x = 0 * elapsedTime
  sphere.rotation.y = 0 * elapsedTime

  sphere.rotation.x += 2 * (targetY - sphere.rotation.x)
  sphere.rotation.y += 1.5 * (targetX - sphere.rotation.y)
  // NewCode
  if (myModel){
    myModel.rotation.copy(sphere.rotation.clone())
  }
  ...etc

Result
jet2

2 Likes

Thank you ShoOsaka! :star_struck:

How do I remove the sphere completely but keeping the jet rotating?
Is it possible to add easing or damping to this rotation?

This code works with the sphere:
sphere.rotation.x += 2 * (targetY - sphere.rotation.x)
sphere.rotation.y += 1.5 * (targetX - sphere.rotation.y)

When I try to replace the sphere with myModel I get a console error. ;(
myModel.rotation.x += 2 * (targetY - myModel.rotation.x)
myModel.rotation.y += 1.5 * (targetX - myModel.rotation.y)

Uncaught TypeError: Cannot read properties of undefined (reading ‘rotation’)

What am I doing wrong?

Try it the way I did with the squirrel
BeginnerExample step 3

From the Collection of examples from discourse.threejs.org

Mr.DeltaFrog

I didn’t make it clear enough.

“MyModel” is Async Object.
Before Loading “MyModel”, Animate Functions is moving.
for that reason, it needs "if (my Model){}"in animate Functions.
Below this put Sample Code.

if (myModel){
  myModel.rotation.x += 2 * (targetY - myModel.rotation.x);
  myModel.rotation.y += 1.5 * (targetX - myModel.rotation.y);
}

if you want to remove sphere objects, sphere removed or set “visiable” “false”

“remove objects”

function animate () {
    targetX = mouseX * .001
    targetY = mouseY * .001

    const elapsedTime = clock.getElapsedTime()
    
  if (myModel){
     myModel.rotation.set(targetY, targetX, myModel.rotation.z);
    // Sphere Remove
    if (sphere.parent === scene){{
      scene.remove(sphere);
      sphere.material.dispose();
      sphere.geometry.dispose();
    }
  }

    // Render
    renderer.render(scene, camera)

    // Call tick again on the next frame
   window.requestAnimationFrame(animate)
    
}

“visible: false”

if (myModel){
   myModel.rotation.set(targetY, targetX, myModel.rotation.z);
   sphere.visible = false; // Here
}

Also, easing can be expressed as “value += (target value - current value) * deceleration value”.

EasingExample

let mouseX
let mouseY

let targetX
let targetY

const windowHalfX = window.innerWidth / 2
const windowHalfY = window.innerHeight / 2
let targetRotation = new THREE.Vector2();
let currentRotation = new THREE.Vector2();
let rotationSpeed = 0.01;
function onDocumentMouseMove (event) {
    mouseX = (event.clientX - windowHalfX)
    mouseY = (event.clientY - windowHalfY)
  targetRotation.x = mouseX;
  targetRotation.y = mouseY;
}


const clock = new THREE.Clock()
let isEasing = true;
function animate () {
    
    let d = .001;
    targetX = mouseX * d;
    targetY = mouseY * d;
    currentRotation.x += (targetRotation.x - currentRotation.x) * rotationSpeed;
    currentRotation.y += (targetRotation.y - currentRotation.y) * rotationSpeed;

    const elapsedTime = clock.getElapsedTime()
    
  if (myModel){
    if (isEasing){
      myModel.rotation.set(currentRotation.y * Math.PI / 180, currentRotation.x * Math.PI / 180, myModel.rotation.z);
    }
    else {
      myModel.rotation.set(targetY, targetX, myModel.rotation.z);
    }
    if (sphere.parent === scene){
      scene.remove(sphere);
      sphere.material.dispose();
      sphere.geometry.dispose();
    }
  }

    // Render
    renderer.render(scene, camera)

    // Call tick again on the next frame
   window.requestAnimationFrame(animate)
    
}

animate()

i hope i can help you

1 Like

Thank you ShoOsaka! Very very helpful. Thank you for explaining!

I added the easing code, thank you! My problem now is the GLTF keeps rotating past where I wish it to stop. https://codepen.io/deltafrogcraft/pen/XWPyOoj

This previous setup shows where I wish the GLTF rotation to stop.

How would I restrict the rotation amount on the loaded GLTF so it does not rotate past a desired amount?

My goal is to create a similar functionality as the arrow grid here: https://www.refokus.com/

Mr.DeltaFrog

I’m glad it went well.

To control the rate of rotation, we need to add an IF statement before the rotation.
Three.js has a convenient function “MathUtils.radToDeg” that makes it easy to understand angles, and you can write it using this.

How to write sample code
This will result that changes “targetX” by -10 to +10 degrees and “targetY” by -5 to 5 degrees.

if (myModel){
  if (
    THREE.MathUtils.radToDeg(targetY) > -5 && THREE.MathUtils.radToDeg(targetY) < 5 &&
    THREE.MathUtils.radToDeg(targetX) > -10 && THREE.MathUtils.radToDeg(targetX) < 10
  ){
    myModel.rotation.set(targetY, targetX, myModel.rotation.z);
  }
}

resultCapture
jet3

I hope it goes well.

1 Like