three.js camera smoothly transitions to the target object

foreword

The camera transition code I found on the Internet is not a problem with the code, but it is recommended to write the dead track coordinates to move, and what I want is to move to the target coordinates, and then face the target model and adjust the angle of the camera towards the target model. . Finally, relying on the knowledge of trigonometric functions accumulated in Canvas before, this function was finally realized.

Ready to work

  1. Download tween.js for transition effects
  2. If you want to review trigonometric functions, you can check out this website www.shuxuele.com/sine-cosine…

Problem Description

After testing, there is no problem with the camera moving to the target coordinates. The problem is that the camera is looking at the wrong target angle, and the camera cannot face the target model. Results as shown below

2022-4-5.gif

Function realization

  • official:
    • Math.PI / 2 = radians, radians converted to degrees = 90 degree angle.
    • X = Math.cos(Math.PI / 2) * separation distance + target coordinate
    • Y = Math.sin(Math.PI / 2) * separation distance + target coordinate

QQ screenshot 20220405181945.png

In fact, the effect of looking at a 90-degree angle can be achieved without using Math.PI / 2, which means that you cannot set other angles you want to look at.

full code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body {
            margin: 0;
        }
    </style>
</head>
<body>
<div id="WebGl-output"></div>
<script src="libs/three.js"></script>
<script src="libs/OrbitControls.js"></script>
<script src="libs/tween.js"></script>
<script>
    let scene = new THREE.Scene()
    let camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)

    let renderer = new THREE.WebGLRenderer()
    renderer.setClearColor(0x000000);
    renderer.setSize(window.innerWidth, window.innerHeight)
    renderer.shadowMap.enabled = true

    let axes = new THREE.AxesHelper(20)
    scene.add(axes)

    let planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1)
    let planeMatrices = new THREE.MeshLambertMaterial({color: 0xAAAAAA})
    let plane = new THREE.Mesh(planeGeometry, planeMatrices)
    plane.position.set(15, 0, 0)
    plane.rotation.set(-0.5 * Math.PI, 0, 0)
    plane.receiveShadow = true
    scene.add(plane)

    let cubeGeometry = new THREE.BoxGeometry(4, 4, 4)
    let cubeMatrices = new THREE.MeshLambertMaterial({
        color: 0xff0000,
    })
    let cube = new THREE.Mesh(cubeGeometry, cubeMatrices)
    cube.castShadow = true
    cube.position.set(-4, 3, 0)
    scene.add(cube)

    let sphereGeometry = new THREE.SphereGeometry(4, 20, 20)
    let sphereMatrices = new THREE.MeshLambertMaterial({
        color: 0x7777ff,
    })
    let sphere = new THREE.Mesh(sphereGeometry, sphereMatrices)
    sphere.position.set(20, 4, 2)
    sphere.castShadow = true
    scene.add(sphere)

    let spotLight = new THREE.SpotLight(0xffffff)
    spotLight.position.set(-40, 40, -15)
    spotLight.castShadow = true
    spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
    spotLight.shadow.camera.far = 130;
    spotLight.shadow.camera.near = 40;
    scene.add(spotLight)

    camera.position.set(-30, 40, 30)
    camera.lookAt(scene.position)

    let ambient = new THREE.AmbientLight(0x353535);
    scene.add(ambient);

    document.getElementById('WebGl-output').append(renderer.domElement)

    let controls = new THREE.OrbitControls(camera, renderer.domElement)

    controls.target = new THREE.Vector3(0, 0, 0)

    const raycaster = new THREE.Raycaster()
    let mouse = new THREE.Vector2()
    let intersects = null
    renderer.domElement.addEventListener('click', function (event) {
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
        raycaster.setFromCamera(mouse, camera);
        intersects = raycaster.intersectObject(scene, true);
        if (intersects.length > 0) {
            let boxMaxY = new THREE.Box3().setFromObject(intersects[0].object).max.y

            let distance = boxMaxY + 10
            let angel = Math.PI / 5

            let position = {
                x: intersects[0].object.position.x + Math.cos(angel) * distance,
                y: intersects[0].object.position.y,
                z: intersects[0].object.position.z + Math.sin(angel) * distance
            }

            let tween = new TWEEN.Tween(camera.position).to(position, 3000)
            let tween1 = new TWEEN.Tween(controls.target).to(intersects[0].object.position, 3000)

            controls.enabled = false;
            tween.onComplete(function () {
                controls.enabled = true;
            })

            tween.start()
            tween1.start()
        }
    });

    function render() {
        requestAnimationFrame(render)
        TWEEN.update()
        controls.update()
        renderer.render(scene, camera)
    }

    render()
</script>
</body>
</html>
复制代码

Guess you like

Origin juejin.im/post/7083068912627089438