Vue3+Three.js实现3D模型加载与动画(实践:官方的一个样例)
文章目录
- 目标
- 从github上面去克隆three.js到本地
- 实现过程
- 完整代码(需放入项目中)
- 实现效果
- 总结
目标
- 运行three.js这个项目的代码
- 在vue3项目中,绘制出来它的一个样例
从github上面去克隆three.js到本地
官网:https://threejs.org/
这个官网打开比较慢,我们最好是把项目克隆到本地,运行起来,然后,速度会快很多。克隆命令如下:
git clone https://github.com/mrdoob/three.js.git
安装依赖后,运行项目
pnpm start
在浏览器数据http://192.168.1.2:8081/,我们看到页面如下
红色的,我们查文档用的;绿色的,我们进行编辑用的;现在我们打开蓝色的examples,里面有样例,我们选择第一个来在自己的项目中,实现它:
这个是个模型,我们需要添加一个模型进来,来代替这个立方体,实现过程如下:
实现过程
我们先引进加载模型的加载器,然后使用加载器加载模型,并初始化。
// DRACOLoader是一个用于加载和解码Google Draco压缩格式3D模型的加载器,可以减小3D模型文件大小,提高加载效率。
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
// GLTFLoader用于加载GLTF格式的3D模型文件,这是Three.js的一个扩展加载器。
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import type { GLTF } from 'three/addons/loaders/GLTFLoader.js'let model: THREE.Group
// 动画混合器
let mixer: THREE.AnimationMixer// 添加模型
function initModel() {const loader = new GLTFLoader()loader.setDRACOLoader(new DRACOLoader().setDecoderPath('../jsm/'))loader.load('../models/gltf/LittlestTokyo.glb', setModel, undefined, (e) => {console.error(e)})// 初始化模型function setModel(gltf: GLTF) {model = gltf.scenemodel.position.set(2, 1, 0)model.scale.set(0.02, 0.02, 0.02)scene.add(model)initMixer(gltf)}// 初始化动画混合器function initMixer(gltf: GLTF) {mixer = new THREE.AnimationMixer(gltf.scene) // 创建动画混合器播放模型动画if (gltf.animations[0]) {mixer.clipAction(gltf.animations[0]).play()}}
}
我们这里不解释代码,只是给出来代码,知道替换哪里就行,我们替换掉立方体。(里面还含有动画混合器)
- 另外还有两个东西,就是我们鼠标可以拖拽这个物体,需要用到轨道控制器。
- 以及需要一个环境光,否则,看起来很黑暗。代码如下:
// 轨道控制
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'// 轨道控制器
let controls: OrbitControls// 添加控制器
function initControls() {controls = new OrbitControls(camera, canvasThree.value)
}
// RoomEnvironment用于创建一个室内环境,通常用来为3D场景提供基础的环境光照和反射效果,让3D模型在场景中看起来更加真实自然。
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'// 添加环境
function initEenvironment() {scene.environment = new THREE.PMREMGenerator(renderer).fromScene(new RoomEnvironment(), 0.04).texture
}
完整代码(需放入项目中)
<script setup lang="ts">
import type { GLTF } from 'three/addons/loaders/GLTFLoader.js'
import * as THREE from 'three'
// 轨道控制
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'// RoomEnvironment用于创建一个室内环境,通常用来为3D场景提供基础的环境光照和反射效果,让3D模型在场景中看起来更加真实自然。
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'
// DRACOLoader是一个用于加载和解码Google Draco压缩格式3D模型的加载器,可以减小3D模型文件大小,提高加载效率。
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
// GLTFLoader用于加载GLTF格式的3D模型文件,这是Three.js的一个扩展加载器。
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'import { onMounted, ref } from 'vue'const canvasThree = ref()// 创建scene、camera、renderer
let scene: THREE.Scene, camera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer, model: THREE.Group// 轨道控制器
let controls: OrbitControls
// 动画混合器
let mixer: THREE.AnimationMixer// 添加控制器
function initControls() {controls = new OrbitControls(camera, canvasThree.value)
}// 1.创建场景
function initScene() {scene = new THREE.Scene()
}// 2.创建相机
function initCamera() {camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000,)camera.position.set(0, 0, 10)scene.add(camera)
}// 3.创建物体(几何体 + 材质 = 物体)
// function initCube() {
// const boxWidth = 1
// const boxHeight = 1
// const boxDepth = 1
// const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth)// const material = new THREE.MeshBasicMaterial({ color: 0x44AA88 })// cube = new THREE.Mesh(geometry, material)// scene.add(cube)
// }// 添加模型
function initModel() {const loader = new GLTFLoader()loader.setDRACOLoader(new DRACOLoader().setDecoderPath('../jsm/'))loader.load('../models/gltf/LittlestTokyo.glb', setModel, undefined, (e) => {console.error(e)})// 初始化模型function setModel(gltf: GLTF) {model = gltf.scenemodel.position.set(2, 1, 0)model.scale.set(0.02, 0.02, 0.02)scene.add(model)initMixer(gltf)}// 初始化动画混合器function initMixer(gltf: GLTF) {mixer = new THREE.AnimationMixer(gltf.scene) // 创建动画混合器播放模型动画if (gltf.animations[0]) {mixer.clipAction(gltf.animations[0]).play()}}
}// 添加环境
function initEenvironment() {scene.environment = new THREE.PMREMGenerator(renderer).fromScene(new RoomEnvironment(), 0.04).texture
}// 4.渲染场景
function initRenderer() {// 创建渲染器renderer = new THREE.WebGLRenderer({ antialias: true, canvas: canvasThree.value })// 设置渲染器尺寸renderer.setSize(window.innerWidth, window.innerHeight)
}const clock = new THREE.Clock()
// 5.动画循环渲染场景
function animate() {requestAnimationFrame(animate)mixer && mixer.update(clock.getDelta()) // 更新3D模型的动画controls.update()// 渲染场景renderer.render(scene, camera)
}onMounted(() => {// 初始化场景、相机、渲染器、物体initScene()initCamera()initControls()initRenderer()initModel()initEenvironment()// 启动动画循环animate()
})
</script><template><canvas id="canvasThree" ref="canvasThree" />
</template>
实现效果
我们页面挂载完毕去调用这些函数即可。这个样例,主要是体会我们上次说的,结构与方法的问题。养成一个写代码比较好的思路。
总结
- 我们实现这个样例,主要是将cube这个物体替换为模型
- 其次是加了轨道控制器与环境光。(这两个在上次的3D物体样例中也可以加上。不同的就是这个模型,以及模型中的那个动画,这个模型中数据都是给定的,因此,我们只需要拿过来即可。这样问题就很简单了,体会一下,主要是后期对模型的控制,其实也是有了数据就好办,动画的话,有一个时间与位置的关系,后面再说。)