Three.js UV 贴图动画:让静态纹理跳起数字芭蕾

211 阅读4分钟

在三维世界里,模型是演员,材质是戏服,而 UV 贴图就是裁缝手中的魔法剪刀 —— 它把二维布料严丝合缝地裹在三维身体上。当我们用 Three.js 搭建虚拟舞台时,学会操纵 UV 贴图动画,就像给这些戏服注入了生命,让它们能随着剧情翩翩起舞。

一、UV:三维世界的 “皮肤密码”

UV 坐标就像是三维模型的 “皮肤坐标系”,它把 0 到 1 的横纵区间铺展在模型表面。想象你要给恐龙模型贴鳞片纹理,UV 就是指导你把鳞片图案像纹身贴纸一样精准对齐的蓝图。在 Three.js 中,每个网格模型都默认携带 UV 数据,它们藏在mesh.geometry.attributes.uv里,就像恐龙皮下的隐形纹身模板。

二、基础准备:搭建舞台

首先,我们要召唤 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: 0xffffff });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

三、纹理登场:贴上 “动态皮肤”

现在轮到 UV 贴图大显身手了!我们先加载一张纹理图片,这就像给演员挑选一件花衬衫:

const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('yourTexture.jpg');

把纹理应用到材质上时,Three.js 会自动用 UV 坐标 “裁剪” 纹理,让图案精准贴合模型表面。但这还不够,我们要让这件 “衬衫” 动起来!

四、动画原理:拨动 UV 坐标的琴弦

UV 动画的核心,是通过时间推移改变 UV 坐标。想象我们在纹理图片上放置一个透明窗口,窗口滑动时,显示的图案也会随之变化。在 Three.js 中,我们通过修改mesh.geometry.attributes.uv来移动这个 “观察窗口”。

例如,让纹理横向滚动:

function animate() {
    requestAnimationFrame(animate);
    // 遍历每个顶点的UV坐标
    for (let i = 0; i < cube.geometry.attributes.uv.count; i++) {
        const u = cube.geometry.attributes.uv.getX(i);
        const v = cube.geometry.attributes.uv.getY(i);
        // 让u坐标随时间增加,制造横向滚动效果
        cube.geometry.attributes.uv.setXY(i, u + 0.01, v);
    }
    cube.geometry.attributes.uv.needsUpdate = true;
    renderer.render(scene, camera);
}
animate();

这里的needsUpdate = true就像按下刷新按钮,告诉 Three.js:“嘿!UV 坐标变了,快重新计算纹理显示!”

五、进阶玩法:复杂动画的交响曲

如果想要更炫酷的效果,可以结合三角函数来实现波浪、旋转等动态。比如让纹理产生水波扩散:

function waveAnimate() {
    requestAnimationFrame(waveAnimate);
    const time = Date.now() * 0.001;
    for (let i = 0; i < cube.geometry.attributes.uv.count; i++) {
        const u = cube.geometry.attributes.uv.getX(i);
        const v = cube.geometry.attributes.uv.getY(i);
        // 用正弦函数制造波浪起伏
        const offsetX = Math.sin(time + u * 10) * 0.1;
        const offsetY = Math.cos(time + v * 10) * 0.1;
        cube.geometry.attributes.uv.setXY(i, u + offsetX, v + offsetY);
    }
    cube.geometry.attributes.uv.needsUpdate = true;
    renderer.render(scene, camera);
}
waveAnimate();

这段代码就像给纹理施了魔法,让它随着时间产生规律的扭曲变形,仿佛水面泛起涟漪。

六、避坑指南:别让动画 “翻车”

  1. 性能陷阱:频繁修改attributes.uv会消耗性能。可以尝试减少顶点数量,或者使用纹理动画帧序列来替代实时计算。
  1. UV 重复:如果纹理出现拉伸或错位,检查 UV 坐标是否超出 0 到 1 的范围,就像检查裁缝是否把布料剪错尺寸。
  1. 材质模式:不同材质(如MeshBasicMaterial和MeshStandardMaterial)对 UV 动画的支持略有差异,记得按需选择合适的 “戏服面料”。

当你掌握了 UV 贴图动画的奥秘,就相当于拥有了三维世界的 “视觉魔法”。从飘落的雪花到流动的熔岩,从闪烁的霓虹灯到摇曳的旗帜,任何静态纹理都能在你的代码指挥下,跳起属于数字世界的华丽芭蕾。快打开编辑器,让你的模型穿上会动的 “数字华服” 吧!

以上文章涵盖了 Three.js UV 贴图动画的基础与进阶玩法。若你想对某个部分深入学习,或尝试其他动画效果,欢迎和我说说。