• 【Three.js】知识梳理二十二:相机视角的平滑过渡与点击模型视角切换


    在 Three.js 中,实现相机视角的平滑过渡和点击模型切换到查看模型视角是一个常见且有用的功能。这种效果不仅能提升用户体验,还能为场景互动添加更多的动态元素。本文将详细介绍如何在 Three.js 中实现这一功能。

    image.png

    1. 基本设置

    首先,我们需要创建一个基本的 Three.js 场景,包括相机、渲染器、光源以及一些示例模型。

    创建场景和相机
    1. // 创建场景
    2. const scene = new THREE.Scene();
    3. // 创建相机
    4. const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    5. camera.position.set(0, 5, 10);
    6. // 创建渲染器
    7. const renderer = new THREE.WebGLRenderer();
    8. renderer.setSize(window.innerWidth, window.innerHeight);
    9. document.body.appendChild(renderer.domElement);
    10. // 创建光源
    11. const light = new THREE.DirectionalLight(0xffffff, 1);
    12. light.position.set(0, 10, 10);
    13. scene.add(light);
    添加示例模型
    1. // 创建一个简单的几何体
    2. const geometry = new THREE.BoxGeometry();
    3. const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
    4. const cube = new THREE.Mesh(geometry, material);
    5. cube.position.set(0, 1, 0);
    6. scene.add(cube);
    7. // 创建另一个几何体
    8. const sphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);
    9. const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
    10. const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
    11. sphere.position.set(2, 1, 0);
    12. scene.add(sphere);

    2. 引入动画

    为了实现平滑过渡,我们引入 tween.js 动画库。

    <script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.umd.js"></script>
    

    3. 实现相机视角的平滑切换

    定义相机切换函数
    1. function smoothCameraTransition(targetPosition, targetLookAt) {
    2.    // 保存当前相机的位置和朝向
    3.    const startPosition = camera.position.clone();
    4.    const startLookAt = new THREE.Vector3();
    5.    camera.getWorldDirection(startLookAt);
    6.    // 创建 tween 动画
    7.    new TWEEN.Tween(startPosition)
    8.       .to(targetPosition, 2000) // 动画持续时间为2000毫秒
    9.       .easing(TWEEN.Easing.Quadratic.InOut) // 使用缓动函数
    10.       .onUpdate(() => {
    11.            camera.position.copy(startPosition);
    12.       })
    13.       .start();
    14.    new TWEEN.Tween(startLookAt)
    15.       .to(targetLookAt, 2000)
    16.       .easing(TWEEN.Easing.Quadratic.InOut)
    17.       .onUpdate(() => {
    18.            camera.lookAt(startLookAt);
    19.       })
    20.       .start();
    21. }
    更新渲染循环

    确保在渲染循环中更新 tween 动画。

    1. function animate() {
    2.    requestAnimationFrame(animate);
    3.    TWEEN.update();
    4.    renderer.render(scene, camera);
    5. }
    6. animate();

    4. 实现点击模型切换视角

    添加射线投射器

    我们需要添加射线投射器来检测用户点击的模型。

    1. const raycaster = new THREE.Raycaster();
    2. const mouse = new THREE.Vector2();
    3. function onMouseClick(event) {
    4.    // 将鼠标点击位置转换为标准化设备坐标
    5.    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    6.    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    7.    // 更新射线投射器
    8.    raycaster.setFromCamera(mouse, camera);
    9.    // 计算交互对象
    10.    const intersects = raycaster.intersectObjects(scene.children);
    11.    if (intersects.length > 0) {
    12.        const intersectedObject = intersects[0].object;
    13.        // 切换相机视角到点击的模型
    14.        const targetPosition = new THREE.Vector3().copy(intersectedObject.position).add(new THREE.Vector3(0, 2, 5));
    15.        const targetLookAt = intersectedObject.position.clone();
    16.        smoothCameraTransition(targetPosition, targetLookAt);
    17.   }
    18. }
    19. window.addEventListener('click', onMouseClick, false);

    5. 完整代码示例

    将上述代码片段整合在一起,形成一个完整的示例。

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4.    <meta charset="UTF-8">
    5.    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    6.    <title>Three.js Smooth Camera Transition</title>
    7.    <style>
    8.        body { margin: 0; }
    9.        canvas { display: block; }
    10.    </style>
    11. </head>
    12. <body>
    13.    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    14.    <script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.umd.js"></script>
    15.    <script>
    16.        // 基本设置
    17.        const scene = new THREE.Scene();
    18.        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    19.        camera.position.set(0, 5, 10);
    20.        const renderer = new THREE.WebGLRenderer();
    21.        renderer.setSize(window.innerWidth, window.innerHeight);
    22.        document.body.appendChild(renderer.domElement);
    23.        const light = new THREE.DirectionalLight(0xffffff, 1);
    24.        light.position.set(0, 10, 10);
    25.        scene.add(light);
    26.        // 添加示例模型
    27.        const geometry = new THREE.BoxGeometry();
    28.        const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
    29.        const cube = new THREE.Mesh(geometry, material);
    30.        cube.position.set(0, 1, 0);
    31.        scene.add(cube);
    32.        const sphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);
    33.        const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
    34.        const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
    35.        sphere.position.set(2, 1, 0);
    36.        scene.add(sphere);
    37.        // 动画函数
    38.        function smoothCameraTransition(targetPosition, targetLookAt) {
    39.            const startPosition = camera.position.clone();
    40.            const startLookAt = new THREE.Vector3();
    41.            camera.getWorldDirection(startLookAt);
    42.            new TWEEN.Tween(startPosition)
    43.               .to(targetPosition, 2000)
    44.               .easing(TWEEN.Easing.Quadratic.InOut)
    45.               .onUpdate(() => {
    46.                    camera.position.copy(startPosition);
    47.               })
    48.               .start();
    49.            new TWEEN.Tween(startLookAt)
    50.               .to(targetLookAt, 2000)
    51.               .easing(TWEEN.Easing.Quadratic.InOut)
    52.               .onUpdate(() => {
    53.                    camera.lookAt(startLookAt);
    54.               })
    55.               .start();
    56.       }
    57.        function animate() {
    58.            requestAnimationFrame(animate);
    59.            TWEEN.update();
    60.            renderer.render(scene, camera);
    61.       }
    62.        animate();
    63.        // 添加射线投射器
    64.        const raycaster = new THREE.Raycaster();
    65.        const mouse = new THREE.Vector2();
    66.        function onMouseClick(event) {
    67.            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    68.            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    69.            raycaster.setFromCamera(mouse, camera);
    70.            const intersects = raycaster.intersectObjects(scene.children);
    71.            if (intersects.length > 0) {
    72.                const intersectedObject = intersects[0].object;
    73.                const targetPosition = new THREE.Vector3().copy(intersectedObject.position).add(new THREE.Vector3(0, 2, 5));
    74.                const targetLookAt = intersectedObject.position.clone();
    75.                smoothCameraTransition(targetPosition, targetLookAt);
    76.           }
    77.       }
    78.        window.addEventListener('click', onMouseClick, false);
    79.    </script>
    80. </body>
    81. </html>

    通过以上步骤,我们成功实现了 Three.js 中的平滑相机视角切换和点击模型视角切换功能。这种技术可以大大提升用户的交互体验,并为3D场景添加更多的动态效果。希望本文对你在 Three.js 开发中有所帮助。

    附送250套精选项目源码

    源码截图

     源码获取:关注公众号「码农园区」,回复 【源码】,即可获取全套源码下载链接

  • 相关阅读:
    01.AJAX 概念和 axios 使用
    基于小波变换的像素级图像融合实例研究-含Matlab代码
    python基于django的汽车租赁系统nodejs+vue+element
    unsafe value used in a resource URL context,angular框架下嵌入iframe报错问题解决
    springMVC执行流程详解
    web前端期末大作业:HTML+CSS+JavaScript绿色的盆栽花店网站响应式模板 大学生鲜花网页设计
    WebSocket封装(TypeScript、单例模式、自动重连、事件监听、Vue中使用)
    Spring学习从练气到化虚
    [游戏开发][Unity] UnityWebRequest中断续传
    单元测试 - 测试场景记录
  • 原文地址:https://blog.csdn.net/lwzhang1101/article/details/139655772