变形动画
几何体的顶点的位置坐标发生变化,从一个状态过渡到另一个状态自然就产生了变形动画
微信跳一跳小游戏就是变形动画
var geometry = new THREE.BoxGeometry(5, 5, 5); //立方体几何对象
// 为geometry提供变形目标的数据
var box1 = new THREE.BoxGeometry(6, 3, 6); //为变形目标1提供数据
var box2 = new THREE.BoxGeometry(4, 10, 4); //为变形目标2提供数据
// 设置变形目标的顶点数据数组
geometry.morphAttributes.position = [];
//第一组变形数据
geometry.morphAttributes.position[0] = new THREE.Float32BufferAttribute(
box1.getAttribute("position").array,
3
);
//第二组变形数据
geometry.morphAttributes.position[1] = new THREE.Float32BufferAttribute(
box2.getAttribute("position").array,
3
);
var material = new THREE.MeshLambertMaterial({
color: "red",
}); //材质对象
var mesh = new THREE.Mesh(geometry, material); //网格模型对象
//配置第一组顶点在没有动画的情况下的是否影响 0->不影响 1->完全影响 0-1 之间的状态
mesh.morphTargetInfluences && (mesh.morphTargetInfluences[0] = 1);
//配置第二组顶点在没有动画的情况下的是否影响 0->不影响 1->完全影响 0-1 之间的状态
mesh.morphTargetInfluences && (mesh.morphTargetInfluences[1] = 0);
//第一组顶点变化 时间在 0, 10, 20 之间 权重分别是 0, 1, 0 (0秒不会改变原来的顶点,10秒完全改变到设置的第一组变形顶点,20秒恢复到默认的顶点
const Track1 = new THREE.KeyframeTrack(
".morphTargetInfluences[0]",
[0, 10, 20],
[0, 1, 0]
);
//第二组顶点变化
const Track2 = new THREE.KeyframeTrack(
".morphTargetInfluences[1]",
[20, 30, 40],
[0, 1, 0]
);
const clip = new THREE.AnimationClip("default", 40, [Track1, Track2]);
const mixer = new THREE.AnimationMixer(mesh); //创建混合器
const AnimationAction = mixer.clipAction(clip); //返回动画操作对象
AnimationAction.timeScale = 5;
AnimationAction.clampWhenFinished = true; //暂停在最后一帧播放的状态
AnimationAction.play();
//配置初始动画
configPrimaryAnimation(
new Map<string, Function>([
[
"a1",
() => {
clock.current && mixer.update(clock.current.getDelta());
},
],
])
);
addObjectToScene([mesh]);
使用外部模型
大部分情况下对于复杂的模型,都是采用 3D 软件设计模型导入到 THREE.js 进行交互
常用的外部模型:obj, fbx, gltf
主流的是 gltf(GL TransmissionFormat),即图形语言交换格式,它是一种 3D 内容的格式标准,由 Khronos Group 管理 (Khronos Group 还管理着 OpenGL 系列、OpenCL 等重要的行业标准) glTF 的 设计是面向实时渲染应用的,尽量提供可以直接传输给图形 API 的数据形式,不再需要二次转换; glTF 对 OpenGL ES、WebGL 非常友好,glTF 的目标是:3D 领域的 JPEG; GLTF 具体的数据存储格 式可以去官方网站上看:https://www.khronos.org/gltf/,使用 json 描述模型的结构
gltf 常用的格式:
- 用二进制格式(.glb),通常较小且独立,但不易编辑
- 嵌入式格式(.gltf), 其他模型利用转换工具也可以转成 .gltf 格式,基于 json 的文本文件
- 分离式的
如果不想使用 THREE.JS 渲染 可以直接显示一个模型在网页里,还是伟大的谷歌公司开源的组件 model-viewer
谷歌公司开源的一个 JS 项目: model-viewer 项目 Github 地址 :https://github.com/google/model-viewer 项目官网:https://modelviewer.dev/ 项目介绍 :Easily display interactive 3D models on the web & in AR 简单来说就是:在 Web 或 AR 中 ,一个简单的用来显示 3D 模型的 JS 库。
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
const loader = new GLTFLoader();
//模型文件如果是本地加载的话,要放在 public 目录内
loader.load(
"models/untitled.gltf",
(gltf) => {
gltf.scene.traverse((p) => {
if (p.type === "Mesh") {
const mesh = p as THREE.Mesh;
const material = mesh.material as THREE.MeshStandardMaterial;
material.color = new THREE.Color("pink");
}
});
gltf.scene.translateX(2);
addObjectToScene([gltf.scene]);
},
undefined,
(error) => {
console.log(error.message);
}
);
精灵模型和粒子系统
精灵模型对象 Sprite。精灵模型对象和网格模型一样需要设置材质,不过精灵模型不需要程序员设 置几何体,Threejs 系统渲染的时候会自动设置。通过 Threejs 精灵模型可以给场景中模型对象设 置标签,也快成大量精灵模型对象模拟一个粒子系统,实现下雨或下雪的渲染效果
它的特性是,永远正对相机平面。不像广告牌,可以绕到后面看看,绕到侧面看看,它永远会正对着 你。所以我们可以用它来显示一些标签,比如在可视化监控系统中,就可以显示传感器的数据,
模拟下雨
const texture = new THREE.TextureLoader().load(rain);
//创建精灵材质对象SpriteMaterial
const spriteMaterial = new THREE.SpriteMaterial({
color: 0xffffff, //设置精灵矩形区域颜色
//rotation:Math.PI/4,//旋转精灵对象45度,弧度值
map: texture, //设置精灵纹理贴图
});
const sprite = new THREE.Sprite(spriteMaterial);
//z 方向的分量不会使用
sprite.scale.set(1, 1, 0);
const group = new THREE.Group();
for (let index = 0; index < 800; index++) {
const clone = sprite.clone();
clone.position.set(
100 * (Math.random() - 0.5),
30 * Math.random(),
100 * (Math.random() - 0.6)
);
clone.rotateX(Math.PI * Math.random());
clone.rotateY(Math.PI * Math.random());
clone.rotateZ(Math.PI * Math.random());
group.add(clone);
}
const grasslandTextureLoader = new THREE.TextureLoader();
const grasslandTexture = grasslandTextureLoader.load(grassland);
const planeGeometry = new THREE.PlaneGeometry(120, 120);
const plan = new THREE.Mesh(
planeGeometry,
new THREE.MeshLambertMaterial({ map: grasslandTexture })
);
plan.rotateX(-Math.PI * 0.5);
plan.position.set(0, 1, 0);
addObjectToScene([group, plan]);
configPrimaryAnimation(
new Map<string, Function>([
[
"a1",
() => {
group.children.forEach((p) => {
if (p.position.y < -1) {
p.position.y = 30;
}
p.position.y -= 0.2;
});
},
],
])
);
dat.gui 工具的使用
Google Data Arts Team 开源一款插件,three.js 发起人参与此开源项目,此工具最大优势就是可插拨 的加入项目,由于改变对象的属性
在这个开源工具的基础有有基于 react 开发的其他工具
GUI 会根据你设置的属性类型来渲染不同的控件
- 如果是 Number 类型则用 slider 来控制
- 如果是 Boolean 类型,则用 Checkbox 来控制
- 如果是 Function 类型则用 button 来控制
- 如果是 String 类型则用 input 来控制
gui.add(text, "noiseStrength").step(5); // 增长的步长
gui.add(text, "growthSpeed", -5, 5); // 最大、最小值
gui.add(text, "maxSize").min(0).step(0.25); // 最大值和步长
// 文本输入项
gui.add(text, "message", ["pizza", "chrome", "hooray"]);
// 下拉框形式选择文案
gui.add(text, "speed", { Stopped: 0, Slow: 0.1, Fast: 5 });
为了方便使用进行封装,见 hooks