three.js
three.js copied to clipboard
ArcballControls - Extra rotation after recreating the controls
Describe the bug
If a camera rotation is performed using ArcballControls before recreating the controls, an extra rotation happens after releasing the mouse on subsequent rotations. If no camera rotation is performed before recreating the controls, everything works fine.
To Reproduce
Steps to reproduce the behavior:
- Create a basic Three.js setup
- Add ArcballControls to it
- Make some function / logic to recreate the controls on demand
- Launch the page and rotate camera around
- Trigger the controls' re-creation function / logic
- Try to rotate camera around again
- Notice the extra rotation after releasing the mouse button
Code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {margin: 0;}
</style>
</head>
<body>
<script type="importmap">
{
"imports":
{
"three": "http://localhost:8080/three.module.js",
"ArcballControls": "http://localhost:8080/ArcballControls.js"
}
}
</script>
<script type="module">
import * as THREE from "three";
import {ArcballControls} from "ArcballControls";
var scene, camera, light, renderer, earth, controls, reqid, paused = false;
function createcontrols()
{
controls = new ArcballControls(camera, renderer.domElement, scene);
controls.addEventListener("change", function(e) {renderer.render(scene, camera); controls.update();});
};
function create()
{
renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 1.75);
light = new THREE.AmbientLight("rgb(255, 255, 255)");
light.position.copy(camera.position);
var geometry = new THREE.SphereGeometry(1, 360, 180);
var material = new THREE.MeshPhongMaterial();
material.map = new THREE.TextureLoader().load("http://localhost:8080/Earth.png");
material.displacementMap = new THREE.TextureLoader().load("http://localhost:8080/Earth - Height.png");
material.displacementScale = 0.002 * 99;
earth = new THREE.Mesh(geometry, material);
scene = new THREE.Scene();
scene.add(camera);
scene.add(light);
scene.add(earth);
createcontrols();
document.addEventListener("keyup", function(e)
{
switch (e.code)
{
case "KeyP": console.log("P"); paused = !paused; if (!paused) {animate();} else {stagnate();}; break;
case "KeyR": console.log("R"); controls.dispose(); controls = undefined; createcontrols(); renderer.render(scene, camera); controls.update(); break;
};
}, {passive: false});
};
function animate()
{
if (paused) {return;};
requestAnimationFrame(animate);
earth.rotation.y += 0.01;
renderer.render(scene, camera);
};
function stagnate()
{
if (!paused) {return;};
cancelAnimationFrame(reqid);
};
create();
animate();
</script>
</body>
</html>
Live example
None
Expected behavior
For the simpleton code above, drag to rotate the globe, press the R key to recreate ArcballControls, then rotate again to see how it "jumps" to a new rotation after releasing the mouse. I expect that the jump does not happen (like it doesn't for the other controls). My actual usage scenario is switching from one control to another (all 8 included in my code) on some mouse scroll, by the way - I chose to illustrate recreating the controls in the interest of simplicity. Let me know if this can be replicated, or if by any chance there is something obvious missing from the code above (like updating some matrix and such) that fixes the issue.
Screenshots
None
Platform:
- Device: Desktop
- OS: Windows 10
- Browser: Chrome, Edge WebView2 via the WebView plugin for Rainmeter
- Three.js version: r.140, r.143