使用 Three.js 更新场景(How to Update Things)

person 少陵野老    watch_later 2024-10-11 22:54:36
visibility 37    class How to Update Things    bookmark 专栏

在 Three.js 中,更新场景是创建动态和交互式三维应用的关键。通过不断更新场景中的对象、摄像机、光源等,可以实现动画效果、交互反应和视觉变化。本文将详细介绍如何在 Three.js 中更新场景,包括更新位置、旋转、缩放,以及处理动画和响应用户输入。

1. 基础概念

在 Three.js 中,更新场景通常涉及以下几个方面:

  • 位置、旋转和缩放:对对象的基本变换。
  • 动画:使用 AnimationMixer 更新模型的动画。
  • 用户输入:通过监听事件更新场景。
  • 渲染循环:通过 requestAnimationFrame 实现流畅的更新。

2. 创建基本场景

在开始之前,我们先创建一个基本的 Three.js 场景,包含一个立方体和一个摄像机。

2.1 安装 Three.js

确保在你的 HTML 文件中引入 Three.js:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 更新场景示例</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>

2.2 创建基本场景

<script> 标签中,设置基本的 Three.js 场景、摄像机和渲染器:

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

camera.position.z = 5;

3. 更新位置、旋转和缩放

3.1 更新位置

我们可以通过修改对象的 position 属性来更新其位置。以下是一个简单的例子,使立方体在 x 轴上移动:

function updatePosition() {
    cube.position.x += 0.01; // 每帧向右移动
    if (cube.position.x > 5) {
        cube.position.x = -5; // 循环移动
    }
}

3.2 更新旋转

可以通过修改对象的 rotation 属性来旋转对象。以下是使立方体旋转的代码:

function updateRotation() {
    cube.rotation.x += 0.01; // 绕 x 轴旋转
    cube.rotation.y += 0.01; // 绕 y 轴旋转
}

3.3 更新缩放

类似地,可以通过 scale 属性更新对象的缩放:

function updateScale() {
    cube.scale.x = Math.sin(Date.now() * 0.001) + 1; // 使立方体在 x 轴上动态缩放
}

4. 渲染循环

将所有更新逻辑结合在一起,通过 requestAnimationFrame 实现渲染循环:

function animate() {
    requestAnimationFrame(animate);

    updatePosition();
    updateRotation();
    updateScale();

    renderer.render(scene, camera);
}

animate();

5. 添加灯光和阴影

为了增强场景的视觉效果,可以添加光源和启用阴影。

5.1 添加光源

const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 环境光
scene.add(ambientLight);

const directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 平行光
directionalLight.position.set(5, 5, 5).normalize();
scene.add(directionalLight);

5.2 启用阴影

renderer.shadowMap.enabled = true;
cube.castShadow = true;
directionalLight.castShadow = true;

6. 处理动画

如果模型包含动画,可以使用 AnimationMixer 来更新动画。以下是一个使用 GLTFLoader 加载模型并播放动画的示例:

6.1 加载 GLTF 模型

const loader = new THREE.GLTFLoader();
let mixer;

loader.load('path/to/model.glb', (gltf) => {
    scene.add(gltf.scene);
    mixer = new THREE.AnimationMixer(gltf.scene);
    gltf.animations.forEach((clip) => {
        mixer.clipAction(clip).play();
    });
});

6.2 更新动画

在渲染循环中更新动画:

function animate() {
    requestAnimationFrame(animate);

    updatePosition();
    updateRotation();
    updateScale();

    if (mixer) mixer.update(0.01); // 更新动画

    renderer.render(scene, camera);
}

7. 响应用户输入

通过监听用户输入(例如鼠标、键盘等),可以动态更新场景。以下是一个响应键盘输入以控制立方体颜色的示例:

7.1 监听键盘事件

window.addEventListener('keydown', (event) => {
    if (event.key === 'r') {
        cube.material.color.set(0xff0000); // 按 R 键时改变颜色
    }
    if (event.key === 'g') {
        cube.material.color.set(0x00ff00); // 按 G 键时改变颜色
    }
    if (event.key === 'b') {
        cube.material.color.set(0x0000ff); // 按 B 键时改变颜色
    }
});

8. 完整示例代码

将所有内容整合,得到完整的 HTML 文件:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 更新场景示例</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/examples/js/loaders/GLTFLoader.js"></script>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script>
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        const geometry = new THREE.BoxGeometry();
        const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
        const cube = new THREE.Mesh(geometry, material);
        scene.add(cube);

        camera.position.z = 5;

        function updatePosition() {
            cube.position.x += 0.01; // 每帧向右移动
            if (cube.position.x > 5) {
                cube.position.x = -5; // 循环移动
            }
        }

        function updateRotation() {
            cube.rotation.x += 0.01; // 绕 x 轴旋转
            cube.rotation.y += 0.01; // 绕 y 轴旋转
        }

        function updateScale() {
            cube.scale.x = Math.sin(Date.now() * 0.001) + 1; // 使立方体在 x 轴上动态缩放
        }

        function animate() {
            requestAnimationFrame(animate);

            updatePosition();
            updateRotation();
            updateScale();

            renderer.render(scene, camera);
        }

        animate();

        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        // 添加光源
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(5, 5, 5).normalize();
        scene.add(directionalLight);

        // 监听键盘事件
        window.addEventListener('keydown', (event) => {
            if (event.key === 'r') {
                cube.material.color.set(0xff0000); // 改变颜色
            }
            if (event.key === 'g') {
                cube.material.color.set(0x00ff00);
            }
            if (event.key === 'b') {
                cube.material.color.set(0x0000ff);
            }
        });
    </script>
</body>
</

html>

9. 结论

在本文中,我们详细探讨了如何在 Three.js 中更新场景,包括基本的对象变换、处理动画和用户输入,以及创建流畅的渲染循环。这些更新机制使得开发者能够创建生动的三维应用,提升用户体验。希望本博客能帮助你更好地理解 Three.js 的使用!如果有任何问题或建议,欢迎在评论区留言讨论!

评论区
评论列表
menu