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

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

image.png

1. 基本设置

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

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

2. 引入动画库

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

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

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

定义相机切换函数
function smoothCameraTransition(targetPosition, targetLookAt) {
    // 保存当前相机的位置和朝向
    const startPosition = camera.position.clone();
    const startLookAt = new THREE.Vector3();
    camera.getWorldDirection(startLookAt);
​
    // 创建 tween 动画
    new TWEEN.Tween(startPosition)
        .to(targetPosition, 2000) // 动画持续时间为2000毫秒
        .easing(TWEEN.Easing.Quadratic.InOut) // 使用缓动函数
        .onUpdate(() => {
            camera.position.copy(startPosition);
        })
        .start();
​
    new TWEEN.Tween(startLookAt)
        .to(targetLookAt, 2000)
        .easing(TWEEN.Easing.Quadratic.InOut)
        .onUpdate(() => {
            camera.lookAt(startLookAt);
        })
        .start();
}
更新渲染循环

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

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

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

添加射线投射器

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

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

5. 完整代码示例

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js Smooth Camera Transition</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.umd.js"></script>
    <script>
        // 基本设置
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 5, 10);
​
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
​
        const light = new THREE.DirectionalLight(0xffffff, 1);
        light.position.set(0, 10, 10);
        scene.add(light);
​
        // 添加示例模型
        const geometry = new THREE.BoxGeometry();
        const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
        const cube = new THREE.Mesh(geometry, material);
        cube.position.set(0, 1, 0);
        scene.add(cube);
​
        const sphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);
        const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
        const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.set(2, 1, 0);
        scene.add(sphere);
​
        // 动画函数
        function smoothCameraTransition(targetPosition, targetLookAt) {
            const startPosition = camera.position.clone();
            const startLookAt = new THREE.Vector3();
            camera.getWorldDirection(startLookAt);
​
            new TWEEN.Tween(startPosition)
                .to(targetPosition, 2000)
                .easing(TWEEN.Easing.Quadratic.InOut)
                .onUpdate(() => {
                    camera.position.copy(startPosition);
                })
                .start();
​
            new TWEEN.Tween(startLookAt)
                .to(targetLookAt, 2000)
                .easing(TWEEN.Easing.Quadratic.InOut)
                .onUpdate(() => {
                    camera.lookAt(startLookAt);
                })
                .start();
        }
​
        function animate() {
            requestAnimationFrame(animate);
            TWEEN.update();
            renderer.render(scene, camera);
        }
        animate();
​
        // 添加射线投射器
        const raycaster = new THREE.Raycaster();
        const mouse = new THREE.Vector2();
​
        function onMouseClick(event) {
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            raycaster.setFromCamera(mouse, camera);
            const intersects = raycaster.intersectObjects(scene.children);
​
            if (intersects.length > 0) {
                const intersectedObject = intersects[0].object;
                const targetPosition = new THREE.Vector3().copy(intersectedObject.position).add(new THREE.Vector3(0, 2, 5));
                const targetLookAt = intersectedObject.position.clone();
                smoothCameraTransition(targetPosition, targetLookAt);
            }
        }
​
        window.addEventListener('click', onMouseClick, false);
    </script>
</body>
</html>

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

附送250套精选项目源码

源码截图

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

最近更新

  1. TCP协议是安全的吗?

    2024-06-15 20:50:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-15 20:50:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-15 20:50:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-15 20:50:01       18 阅读

热门阅读

  1. Windows环境下JDK安装及环境变量配置指南

    2024-06-15 20:50:01       9 阅读
  2. LeetCode //MySQL - 177. Nth Highest Salary

    2024-06-15 20:50:01       7 阅读
  3. 【什么是几度cms,主要功能有什么】

    2024-06-15 20:50:01       6 阅读
  4. php中配置variables_order详解

    2024-06-15 20:50:01       8 阅读
  5. React中Hooks--useEffect | useState | useCallback | useMemo

    2024-06-15 20:50:01       4 阅读
  6. 八股系列 Flink

    2024-06-15 20:50:01       6 阅读
  7. 【Qt实现绘制3D图形】

    2024-06-15 20:50:01       6 阅读
  8. 描述React中的函数组件和类组件之间的区别

    2024-06-15 20:50:01       9 阅读
  9. 【设计模式】面向对象的优点

    2024-06-15 20:50:01       10 阅读
  10. React.ReactElement 与 React.ReactNode

    2024-06-15 20:50:01       10 阅读
  11. 程序分享--常见算法/编程面试题:Z 字形变换

    2024-06-15 20:50:01       10 阅读