Three.js 基础3
😋 Three.js 就是一款基于原生 WebGL 封装运行在浏览器中的 3D 引擎,可以用它创建各种三维场景
2022/6/1 10:00:00
➡️

变形动画

几何体的顶点的位置坐标发生变化,从一个状态过渡到另一个状态自然就产生了变形动画

微信跳一跳小游戏就是变形动画

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 常用的格式:

  1. 用二进制格式(.glb),通常较小且独立,但不易编辑
  2. 嵌入式格式(.gltf), 其他模型利用转换工具也可以转成 .gltf 格式,基于 json 的文本文件
  3. 分离式的

如果不想使用 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 发起人参与此开源项目,此工具最大优势就是可插拨 的加入项目,由于改变对象的属性

官方文档https://github.com/dataarts/dat.gui/blob/master/API.md

在这个开源工具的基础有有基于 react 开发的其他工具

GUI 会根据你设置的属性类型来渲染不同的控件

  1. 如果是 Number 类型则用 slider 来控制
  2. 如果是 Boolean 类型,则用 Checkbox 来控制
  3. 如果是 Function 类型则用 button 来控制
  4. 如果是 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

dat-gui使用效果

👍🎉🎊