Easing on Model Rotation and Light Movement

Hello,

I am a newbie on threeJS. I’m trying to replicate the webgl effect on the site - Особенности - Деловой квартал «Сколково Парк» for practice. So far, I have Skolkovo Rebuild.

On mouse movement, a point light follows the cursor, I want a form of easing on the point light movement, so it takes some time before it catches up with the cursor position as is on the reference site. Also, the model rotates on the x-axis when the cursor moves along the y-axis and vice versa. I want an easing on the rotation as well, just as it is on the reference site.

Please, how can I achieve this?

import * as THREE from 'three'
  import OrbitControls from 'https://cdn.skypack.dev/threejs-orbit-controls'
  import { GLTFLoader } from 'https://cdn.skypack.dev/three/examples/jsm/loaders/GLTFLoader'
	import GUI from 'https://cdn.jsdelivr.net/npm/lil-gui@0.10.0/dist/lil-gui.esm.min.js'
  
  //Scene
 	const scene = new THREE.Scene()
  
  //Canvas
  const canvas = document.querySelector('.webgl')
  
  //Debug
  const gui = new GUI()
  const debugObject = {}
  
  //Object
  
  //Lights  
  const ambientLight = new THREE.AmbientLight('#ffffff', 1)
  scene.add(ambientLight)
  
  const directionalLight = new THREE.DirectionalLight('#ffffff', 2)
  gui.add(directionalLight.position, 'x', -10, 10, 0.01).name('directional light x')  
  gui.add(directionalLight.position, 'y', -10, 10, 0.01).name('directional light y')
  gui.add(directionalLight.position, 'z', -10, 10, 0.01).name('directional light z')
  directionalLight.position.set(3, 4, 4)
  scene.add(directionalLight)
  
  const pointLight = new THREE.PointLight('#E79C13', 2)
  scene.add(pointLight)
  pointLight.position.y = 1
  debugObject.pointLightIntensity = 50
  debugObject.pointLightDistance = 3
  pointLight.castShadow = true
  pointLight.shadow.camera.far = 6
  pointLight.shadow.camera.near = 0.5
  pointLight.shadow.mapSize.set(1024, 1024)
  pointLight.intensity = debugObject.pointLightIntensity
  pointLight.distance = debugObject.pointLightDistance
  gui.add(pointLight.position, 'x', -100, 100, 0.001).name('pointLightX')
  gui.add(pointLight.position, 'y', -100, 100, 0.001).name('pointLightY')
  gui.add(pointLight.position, 'z', -100, 100, 0.001).name('pointLightZ')
  gui.add(debugObject, 'pointLightIntensity', 0, 50, 1).onChange(()=>{
  	pointLight.intensity = debugObject.pointLightIntensity
  })
  gui.add(debugObject, 'pointLightDistance', 0, 10, 0.001).onChange(() => {
  	pointLight.distance = debugObject.pointLightDistance
  })
  
  const cameraHelper = new THREE.CameraHelper(pointLight.shadow.camera)
  
  const sphereSize = 1;
  const pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize );
  
  //Sizes
  const sizes = {
  	width: window.innerWidth,
    height: window.innerHeight
  }
  
  //Camera
  const camera = new THREE.PerspectiveCamera(50, sizes.width/sizes.height)
  scene.add(camera)
  camera.position.z = 10
  gui.add(camera.position, 'x', -100, 100, 1).name('camera position x')
  gui.add(camera.position, 'y', -100, 100, 1).name('camera position y')
  gui.add(camera.position, 'z', -100, 100, 1).name('camera position z')
  
  debugObject.maxPolarAngle = 0.95
  debugObject.minPolarAngle = 0.95
  
  //Controls 
  const controls = new OrbitControls(camera, canvas)
  controls.enableDamping = true
  controls.enablePanning = false
  controls.maxPolarAngle = debugObject.maxPolarAngle
  controls.minPolarAngle = debugObject.minPolarAngle
  controls.rotateSpeed = 0.1
 	controls.dampingFactor = 0.05
  
  //Texture loader
  const textureLoader = new THREE.TextureLoader()
 	const texture = textureLoader.load('https://uploads-ssl.webflow.com/6257f5b3771a401dee5b6377/6293a7e8ddc7b22cae335a50_bake_all.jpg')
  texture.encoding = THREE.sRGBEncoding
  
  const material = new THREE.MeshStandardMaterial({map: texture, aoMap: texture, aoMapIntensity: 0.8})

  //Models
  let architecture
  const gltfLoader = new GLTFLoader()
  gltfLoader.load('https://volt-three-js.netlify.app/models/architecture/building.gltf', (gltf) => {
  	architecture = gltf.scene
    architecture.traverse(child => {
    	if(child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial){
        child.material = material
        child.castShadow = true
        child.receiveShadow = true
      }
    })
    architecture.scale.set(1.5, 1.5)
    architecture.rotation.y = 0.1
    let box = new THREE.Box3().setFromObject( architecture )
    const size = box.getSize( new THREE.Vector3() ).length()
    const centerPosition = box.getCenter( new THREE.Vector3() )
    architecture.position.x += ( architecture.position.x - centerPosition.x )
    architecture.position.y += ( architecture.position.y - centerPosition.y )
    architecture.position.z += ( architecture.position.z - centerPosition.z )    
    scene.add(architecture)
    gui.add(architecture.scale, 'x', 0, 10, 0.001).name('model scale x')
    gui.add(architecture.scale, 'y', 0, 10, 0.001).name('model scale y')
    gui.add(architecture.scale, 'z', 0, 10, 0.001).name('model scale z')    
    gui.add(architecture.position, 'x', 0, 10, 1).name('model x')
    gui.add(architecture.position, 'y', 0, 10, 1).name('model y')
    gui.add(architecture.position, 'z', 0, 10, 1).name('model z')
    gui.add(architecture.rotation, 'x', -10, 10, 0.001).name('model rotation x')
    gui.add(architecture.rotation, 'y', -10, 10, 0.001).name('model rotation y')
    gui.add(architecture.rotation, 'z', -10, 10, 0.001).name('model rotation z')
  })
  
  gui.add(debugObject, 'maxPolarAngle', -Math.PI, Math.PI, 0.001).onChange(() => {
  	controls.maxPolarAngle = debugObject.maxPolarAngle
  })
  gui.add(debugObject, 'minPolarAngle', -Math.PI, Math.PI, 0.001).onChange(() => {
  	controls.minPolarAngle = debugObject.minPolarAngle
  })
  
  //Renderer
  const renderer = new THREE.WebGLRenderer({
  	canvas,
    antialias: true
  })
  
  //Resizing
  window.addEventListener('resize', () => {
  	//Update the sizes object
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight
    
    //Update camera
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()
    
    //Update the renderer
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  })
  
  renderer.setSize(sizes.width, sizes.height)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
  renderer.render(scene, camera)
  renderer.physicallyCorrectLights = true
  renderer.outputEncoding = THREE.sRGBEncoding
  renderer.toneMapping = THREE.ReinhardToneMapping
  renderer.toneMappingExposure = 3
  renderer.shadowMap.enabled = true
  renderer.shadowMap.type = THREE.PCFSoftShadowMap
  renderer.setClearColor('#131312')
  
  gui.add(renderer, 'toneMapping', {
  	No: THREE.NoToneMapping,
    Linear: THREE.LinearToneMapping,
    Reinhard: THREE.ReinhardToneMapping,
    Cineon: THREE.CineonToneMapping,
    ACESFilmic: THREE.ACESFilmicToneMapping
  })
  
  gui.add(renderer, 'toneMappingExposure', 0, 20, 0.01)
  
  let mousePosition = new THREE.Vector3()
  let cursor = {}
  
  window.addEventListener('mousemove', (event) => {
  	cursor.x = (event.clientX / window.innerWidth) * 2 - 1
    cursor.y = (event.clientY / window.innerHeight) * 2 - 1
    

    // Make the sphere follow the mouse
    let vector = new THREE.Vector3(cursor.x, cursor.y, 0.5)
    vector.unproject(camera)
    let dir = vector.sub(camera.position).normalize()
    let distance = -camera.position.z / dir.z
    let pos = camera.position.clone().add(dir.multiplyScalar(distance))
    mousePosition = pos
  })

	//Animate
  let previousTime = 0
  const clock = new THREE.Clock();
  const tick = () => {
  	const elapsedTime = clock.getElapsedTime()
    let deltaTime = elapsedTime - previousTime
    previousTime = elapsedTime
    
    //Update controls
    controls.update()
    
    if(architecture){
    	architecture.rotation.x = mousePosition.y < 0 ? architecture.rotation.lerp() : -0.2
    }
    
    //Easing
    pointLight.position.x = mousePosition.x
    pointLight.position.z = mousePosition.y
    
    //mouseMesh.position.copy(pos)
    //pointLight.position.copy(new THREE.Vector3(mousePosition.x , 1, mousePosition.y))

  	//Render
  	renderer.render(scene, camera)
  	
  	window.requestAnimationFrame(tick)
  }
  
  tick()

Hello

Can anyone help me with this please?

lerp: The three graces - CodeSandbox

let speed = 0.1
let whereTo = 2

someValue = THREE.MathUtils.lerp(someValue, whereTo, speed)
someObj.position.lerp({ x: whereTo, 0, 0 }, speed)

Thank you very much @drcmda

You just helped me with a proper understanding of how the lerp function works, and with a very awesome example.

Thanks again.