Three.js 纹理动画使用教程:超越基础

380 阅读3分钟

在 Three.js 的三维世界构建中,纹理动画能为场景增添动态活力,让静态模型栩栩如生。本教程将深入探讨纹理动画在 Three.js 中的使用,涵盖关键概念、代码实现及优化技巧,助你提升场景表现力。

纹理动画基础原理

纹理动画的核心在于按特定顺序和时间间隔切换纹理。在 Three.js 里,通常借助 TextureLoader 加载纹理图片,利用材质(如 MeshBasicMaterial 或 MeshStandardMaterial)将纹理应用到几何体上。通过改变材质的map属性来切换纹理,配合requestAnimationFrame实现流畅动画效果。

准备工作

开始前,需确保已引入 Three.js 库。可通过 CDN 链接在 HTML 文件中引入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>

同时,准备一系列用于动画的纹理图片,假设这些图片命名规则为texture_0.jpg、texture_1.jpg...texture_n.jpg,且保存在textures/目录下。

加载纹理序列

首先,编写函数加载纹理序列:

function loadTextureSequence(numTextures) {
    const textureLoader = new THREE.TextureLoader();
    const textures = [];
    for (let i = 0; i < numTextures; i++) {
        const texture = textureLoader.load(`textures/texture_${i}.jpg`);
        textures.push(texture);
    }
    return textures;
}

此函数通过循环加载指定数量的纹理图片,返回包含所有纹理的数组。

创建动画材质

接着,创建用于动画的材质,动态更新map属性:

function createAnimatedMaterial(textures) {
    const material = new THREE.MeshStandardMaterial({
        map: textures[0]
    });
    let currentTextureIndex = 0;
    const textureUpdateInterval = 100; // 每100毫秒切换一次纹理,可根据需求调整
    let textureUpdateTimer = 0;
    return {
        material,
        update: (deltaTime) => {
            textureUpdateTimer += deltaTime;
            if (textureUpdateTimer >= textureUpdateInterval) {
                textureUpdateTimer = 0;
                currentTextureIndex = (currentTextureIndex + 1) % textures.length;
                material.map = textures[currentTextureIndex];
                material.needsUpdate = true;
            }
        }
    };
}

上述代码定义了一个createAnimatedMaterial函数,接受纹理数组作为参数。在返回的对象中,包含动画材质material和用于更新纹理的update函数。update函数根据时间间隔切换纹理,并标记材质需要更新。

整合到场景中

将动画材质应用到几何体并添加到场景:

// 创建场景、相机和渲染器
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 numTextures = 10; // 假设共有10张纹理图片
const textures = loadTextureSequence(numTextures);
// 创建动画材质
const animatedMaterialObject = createAnimatedMaterial(textures);
const animatedMaterial = animatedMaterialObject.material;
// 创建几何体并应用动画材质
const geometry = new THREE.BoxGeometry(1, 1, 1);
const mesh = new THREE.Mesh(geometry, animatedMaterial);
scene.add(mesh);
// 设置相机位置
camera.position.z = 5;
// 动画循环
function animate() {
    requestAnimationFrame(animate);
    const deltaTime = clock.getDelta();
    animatedMaterialObject.update(deltaTime);
    renderer.render(scene, camera);
}
const clock = new THREE.Clock();
animate();

上述代码创建了一个简单场景,加载纹理序列,创建动画材质并应用到立方体上。通过requestAnimationFrame和clock.getDelta()实现动画更新和渲染。

优化与扩展

  • 纹理压缩:使用压缩格式(如 JPEG、WebP)减少纹理文件大小,提升加载速度。
  • 预加载:在场景加载初期预加载所有纹理,避免动画卡顿。可使用Promise.all方法并行加载纹理。
  • 动态帧率调整:根据设备性能动态调整纹理切换间隔,保证动画流畅性。例如,在性能较低设备上适当增大切换间隔。

纹理动画为 Three.js 场景注入生机。通过理解原理、掌握代码实现及优化技巧,你能创建更具吸引力的三维场景,为用户带来沉浸式体验。