Sharp alignment of z-axis ( three-viewport-gizmo)

Hey,I use the three-vieport-gizmo library for my project.It looks similar to the original ViewHelper library, so I think a lot of people will understand what I mean.
I have an “autoRotate” parameter in the dat.gui on my scene. To do this, I constantly update the OrbitControls “update” method in the animate function. But when, for example, from the bottom view of the model I click on the “y” axis of three-viewport-gizmo div to switch to the top view, then although the main transition is normal from top to bottom, there is a sharp “jump” during alignment along the “z” axis. I noticed that this is due to the fact that I do OrbitControlsObj.update() in the animation function. The only solution that works I found is to do a check in the animation function
like “if (! gizmo.animating) controls.update()” But I have little experience in this, so I do not know how correct this is from a performance point of view. I really want to know how to do it the best way.
Part of code
useEffect(() => {
if (typeof window === ‘undefined’ || !mountRef.current) return

	const scene = new Scene()
	const renderer = new WebGLRenderer({ antialias: true })
	const fov = options.preset === 'assetgenerator' ? (0.8 * 180) / Math.PI : 60
	const camera = new PerspectiveCamera(
		fov,
		mountRef.current.clientWidth / mountRef.current.clientHeight,
		0.1,
		1000
	)
	const controls = new OrbitControls(camera, renderer.domElement)
	acticveCameraRef.current = camera
	camera.position.set(0, 0, 3)

	//scene.background = new Color(state.bgColor)
	const hemiLight = new HemisphereLight(0xffffff, 0x8d8d8d, 3)
	hemiLight.position.set(0, 20, 0)
	scene.add(hemiLight)
	scene.add(camera)

	renderer.setClearColor(0xcccccc)
	renderer.setPixelRatio(window.devicePixelRatio)
	renderer.setSize(
		mountRef.current.clientWidth,
		mountRef.current.clientHeight
	)

	pmremGenerator.current = new PMREMGenerator(renderer)
	pmremGenerator.current.compileEquirectangularShader()
	neutralEnv.current = pmremGenerator.current.fromScene(
		new RoomEnvironment()
	).texture

	controlsRef.current = controls
	sceneRef.current = scene
	rendererRef.current = renderer
	cameraRef.current = camera
	mountRef.current.appendChild(renderer.domElement)

	const gizmo = new ViewportGizmo(camera, renderer, {
		container: mountRef.current,
		type: 'sphere',
	})
	viewHelper.current = gizmo
	gizmo.target = controls.target.set(0, 0, 0)
	camera.lookAt(controls.target)
	gizmo.addEventListener('start', () => {
		controls.enabled = false
		console.log('start')
	})
	gizmo.addEventListener('end', () => {
		controls.enabled = true
		console.log('end')
	})
	controls.addEventListener('change', () => {
		console.log('change')
		gizmo.update(false)
	})

	const handleResize = () => {
		if (!mountRef.current) return

		const { clientWidth, clientHeight } = mountRef.current
		camera.aspect = clientWidth / clientHeight
		camera.updateProjectionMatrix()
		renderer.setSize(clientWidth, clientHeight) //
		gizmo.update()
		controls.update()
	}
	window.addEventListener('resize', handleResize, false)
	setIsSceneReady(true)
	if (typeof window !== 'undefined') addGUI()

	const animate = () => {
		animationFrameIdRef.current = requestAnimationFrame(animate)
		if (!gizmo.animating) controls.update()

		renderer.clear()
		renderer.render(scene, camera)
		gizmo.render()
	}

	//addAxesHelper()
	animate()
	//if (options.kiosk) Gui.current?.close()
	return () => {
		console.log('CLEANUP')
		if (renderer) {
			renderer.dispose()
			renderer.domElement.remove()
		}
		if (animationFrameIdRef.current) {
			cancelAnimationFrame(animationFrameIdRef.current)
		}
		if (Gui.current && GuiWrap.current) {
			GuiWrap.current.removeChild(Gui.current.domElement)
			Gui.current.destroy() 
			Gui.current = null 
		}
		if (viewHelper.current) viewHelper.current.dispose()
		window.removeEventListener('resize', handleResize)
	}
}, [])

Working exmp(With if (!gizmo.animating) controls.update())

Example with sharp transition on z ax.(Without if (!gizmo.animating), only controls.update())

Smoothe transition,but without autoRotate (no controls.update() in anim func)

I would be glad if someone explains what the problem is and shares their opinion. :heart:

1 Like

The problem only occurs when autoRotate is on, meaning the two animations are overlapping, and you’ve practically solved it :grinning:! Adding if (!gizmo.animating) controls.update() effectively prevents the OrbitControls from rotating while the gizmo is animating.

Here’s a simplified jsFiddle where you can see it in action.

Not sure about this, but I might need to update the library so it internally disable the OrbitControls during the gizmo’s animation?

1 Like

Thank you for your reply! I am glad that my solution with the if (!gizmo.animating) controls.update() check turned out to be correct from the performance point of view. Indeed, the problem was in the conflict of animations, and this approach allows to avoid overlapping of the OrbitControls and ViewportGizmo animations.

Regarding your suggestion to change the library, I would be happy to answer you. I am sure that you, as the author of the library, know better how to make it even more convenient and efficient

Thank you again for your timely help and for your contribution to the creation of the library as an improved alternative to the original library! I will follow the updates. :heart:

2 Likes