概述

Three.js是一个JavaScript库,主要用于创建和显示3D图形。它基于WebGL,一个在浏览器中实现3D效果的API。通过使用Three.js,开发者可以在网页上创建和展示3D场景、模型和动画。它提供了丰富的3D显示功能,包括场景管理、几何体、光照、材质、纹理映射等。使用Three.js可以简化3D程序的实现过程,使得在浏览器中创建和展示3D内容更加容易。

场景构建

使用Three.js构建3D场景的过程可以分为以下几个步骤:

  1. 创建场景:首先需要创建一个场景对象,这个对象将包含所有的3D对象。可以使用Three.js提供的Scene类来创建一个场景。

  2. 创建相机:相机用于定义观察场景的视角。Three.js提供了多种类型的相机,如PerspectiveCamera和OrthographicCamera。根据需要选择适合的相机类型,并将其添加到场景中。

  3. 创建渲染器:渲染器负责将场景渲染到屏幕上。使用Three.js提供的WebGLRenderer类创建一个渲染器实例,并将其添加到HTML页面中。

  4. 添加光源:光源影响物体表面的光照效果。使用Three.js提供的光源类创建光源对象,并将其添加到场景中。

  5. 渲染循环:最后,需要创建一个渲染循环,不断更新场景、相机和光源的状态,并调用渲染器进行绘制。在渲染循环中,可以监听用户输入、处理动画和物理计算等。

以上是使用Three.js构建3D场景的基本过程。通过不断调整和优化场景中的对象、材质、光源等属性,可以创建出丰富多彩的3D效果。

基本代码示例

// 创建场景
scene = new THREE.Scene();
scene.background = new THREE.Color(0xa0a0a0);
// 创建相机
camera = new THREE.PerspectiveCamera(angle, SCREEN_WIDTH / SCREEN_HEIGHT, nearest, farthest);
camera.position.set(20, 20, 30);
// 环境光
scene.add(new THREE.AmbientLight(4210752, 3));
// 平行光
var light = new THREE.DirectionalLight(16777215, 1);
light.position.set(0, 50, 50);
scene.add(light);
// 创建渲染器
var renderer = new THREE.WebGLRenderer({
	antialias: true, // 平滑效果
	alpha: true, // canvas背景透明
});
renderer.render(scene, camera);

加载FBX模型

FBX模型是一种3D通用模型文件格式,最早并非由Autodesk开发,但后来被其收购。它支持所有主要的三维数据元素以及二维、音频和视频媒体元素,因此被众多标准建模软件所支持,如3ds Max、Maya、Softimage等。FBX格式可以用于在各种软件间进行模型、材质、动作和摄影机信息的互导,从而发挥这些软件的优势。例如,在3D Studio Max、Maya、Softimage等软件间进行模型、材质、动作和摄影机信息的互导,这样可以方便地在不同的软件中进行协同工作。

要在Three.js中加载FBX模型,你可以使用three.js的FBXLoader类。以下是一个简单的示例代码:

var loader = new THREE.FBXLoader();  
  
loader.load('model.fbx', function (object) {  
  // 在回调函数中处理加载完成的模型  
  scene.add(object);  
}, undefined, function (error) {  
  // 处理加载错误  
  console.error(error);  
});

在上面的代码中,首先创建了一个FBXLoader实例,然后使用其load方法加载FBX模型文件。在回调函数中,你可以获取到加载完成的模型对象,并将其添加到场景中。如果加载过程中出现错误,可以在回调函数的错误处理部分输出错误信息。

需要注意的是,FBXLoader支持多种版本的FBX格式,因此在使用时需要确保你的FBX模型文件与加载器版本兼容。另外,加载大型FBX模型可能需要较长时间,因此最好在加载完成后添加适当的加载提示或进度条。

播放动画

在加载模型后,使用AnimationMixer和AnimationAction来控制动画的播放。以下是一个简单的示例代码:

var loader = new THREE.FBXLoader();  
  
loader.load('path/to/model.fbx', function (object) {  
  // 将模型添加到场景中  
  scene.add(object);  
  
  // 获取模型的动画控制器  
  var mixer = new THREE.AnimationMixer(object);  
  var action = mixer.clipAction(object.animations[0]); // 假设模型只有一个动画  
  
  // 播放动画  
  action.play();  
}, undefined, function (error) {  
  // 处理加载错误  
  console.error(error);  
});

除此之外,还要不断更新mixers:

function render() {
	window.requestAnimationFrame(()=>{
		render()
	});
	var delta = clock.getDelta();
	mixer.update(delta);
	controls.update();
	renderer.render(scene, camera);
}

暂停、重置动画

要停止Three.js中的动画,你可以使用AnimationMixer的timeScale属性。将timeScale属性设置为0可以暂停动画的播放。如果你想重新开始动画,可以将timeScale属性设置为1。可以使用stopAllAction方法停止Three.js中的所有动画。这个方法会停止所有与特定AnimationMixer对象关联的动画。

// 停止动画
stop(){
  mixer.stopAllAction();
},
// 暂停动画
suspended() {
  mixer.timeScale = 0;
},
// 继续播放
continueAnimation() {
  mixer.timeScale = 1
}

在VUE中完成这些操作

首先使用NPM或Yarn安装three.js

npm i three
<template>
  <div class="three-container">
    <div ref="dom" class="three-dom"></div>
  </div>
</template>

<style scoped>
* {
  margin: 0;
  padding: 0;
}

.three-container {
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.three-dom {
  width: 100%;
  height: 100%;
}
</style>

<script>
import * as THREE from 'three'

import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

export default {
  name: 'ThreeContainer',

  data() {
    return {
      scene: null,
      renderer: null,
      camera: null,
      controls: null,
      group: null,
      mixers: [],
      clock:null
    }
  },

  mounted() {
    this.clock = new THREE.Clock();
    this.initScene()
  },

  methods: {
    initScene() {
      this.scene = new THREE.Scene()
      this.scene.background = new THREE.Color(0xa0a0a0);

      this.camera = new THREE.PerspectiveCamera(
        90,
        window.innerWidth / window.innerHeight,
        1,
        1000
      );
      this.camera.position.set(20, 20, 30);
      // this.scene.add(this.camera)

      // 环境光
      this.scene.add(new THREE.AmbientLight(4210752, 3));
      // 平行光
      var light = new THREE.DirectionalLight(16777215, 1);
      light.position.set(0, 50, 50);
      this.scene.add(light);

      
      // 加载模型
      const loader = new FBXLoader()
      loader.load('/1.fbx', (fbxObj) => {
        fbxObj.scale.set(0.15, 0.15, 0.15)
        console.log(fbxObj);

        fbxObj.mixer = new THREE.AnimationMixer(fbxObj);
        this.mixers.push(fbxObj.mixer)

        var AnimationAction = fbxObj.mixer.clipAction(fbxObj.animations[0]);
        AnimationAction.play(); //播放动画

        this.scene.add(fbxObj)

      })
      
      // 添加渲染器
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true, // canvas背景透明
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(window.innerWidth, window.innerHeight)
      // this.renderer.setClearColor(0x132c3e)
      this.$refs.dom.appendChild(this.renderer.domElement)

      // OrbitControls
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.target.set(0, 0, 0);
      this.animate();

      // 监听窗口大小变化
      window.addEventListener('resize', this.handleResize)
    },
    animate() {
      requestAnimationFrame(() => {
        this.animate()
      });
      // 创建一个时钟对象Clock
      var delta = this.clock.getDelta();
      if (this.mixers.length > 0) {
        // 更新混合器相关的时间
        for (let i = 0; i < this.mixers.length; i++) {
          this.mixers[i].update(delta);
        }
      }
      this.controls.update()
      this.renderer.render(this.scene, this.camera)
    },

    handleResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight
      this.camera.updateProjectionMatrix()

      this.renderer.setSize(window.innerWidth, window.innerHeight)
    }
  }
}
</script>

更好的方案

FBX、 OBJ (Wavefront)和 DAE (Collada)格式仍然是其中最受欢迎的格式,尽管它们都存在阻碍其广泛采用的问题。比如OBJ不支持动画,FBX是属于Autodesk的封闭格式,Collada规范过于复杂,导致大文件难以加载。

然而,最近,一个名为glTF的新成员已成为在网络上交换3D资源的事实上的标准格式。 glTF(GL传输格式),有时被称为 3D中的JPEG,由 Kronos Group创建,他们负责WebGL、OpenGL和一大堆其他图形API。glTF最初于2017年发布,现在是在网络和许多其他领域交换3D资源的最佳格式。它专为在网络上共享模型而设计,因此文件大小尽可能小,并且您的模型将快速加载。

但是,由于glTF相对较新,您最喜欢的应用程序可能还没有导出器。在这种情况下,您可以在使用模型之前将它们转换为glTF。

学习资料

官方文档 第三方资料

模型资源下载

你可以去three.js官方的Github仓库下载相关模型以及学习相关使用案例,或者使用本站提供的FBX模型测试开发。