在 Three.js 中,实现相机视角的平滑过渡和点击模型切换到查看模型视角是一个常见且有用的功能。这种效果不仅能提升用户体验,还能为场景互动添加更多的动态元素。本文将详细介绍如何在 Three.js 中实现这一功能。
首先,我们需要创建一个基本的 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);
为了实现平滑过渡,我们引入 tween.js 动画库。
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/18.6.4/tween.umd.js"></script>
- 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();
我们需要添加射线投射器来检测用户点击的模型。
- 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);
将上述代码片段整合在一起,形成一个完整的示例。
- <!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 开发中有所帮助。
源码截图
源码获取:关注公众号「码农园区」,回复 【源码】,即可获取全套源码下载链接