Skip to content
文章摘要

vue3项目中使用three.js

前提

在vue3项目中,通过three.js实现了一个简单的三维效果图。

Three.js 交互式3D模型

Three.js(也称为ThreeJS)是一个用于在Web上创建3D图形的JavaScript库。它为开发人员提供了一组强大的工具和功能,使他们能够轻松地在浏览器中构建交互式3D场景、模型和动画。Three.js 封装了 WebGL(Web Graphics Library),这是一种用于在浏览器中进行硬件加速图形渲染的技术。通过 Three.js,开发人员可以避免直接操作复杂的 WebGL API,而是使用更高级别、更友好的抽象来创建3D内容。

Three.js 提供了一系列用于创建和管理3D对象、灯光、材质、相机等的类和方法。它还支持动画、几何体生成、粒子系统、阴影、纹理贴图、相机控制等功能。

3D模型网站

模型是从这个网站上找的,Sketchfab,邮箱注册后可以下免费的模型。

刚开始学习的时候,建议先去threejs(官网)上找个示例练下手,会理解的更深刻一点。

vue3中安装与使用

  • 安装
npm install three
yarn install three
  • 使用
javascript
// 在要使用的页面中引入three.js
import * as THREE from 'three';
// 引入轨道控制器,它是你能否控制模型的旋转和移动的关键,如果你不想别人控制你的模型,可以不引入
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 引入资源加载器,加载你的外部gltf/glb模型文件
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
  • 完整代码
typescript
<template>
  <div id="container" class="three-canvas" ref="canvas"></div>
</template>

<script setup lang="ts">
import { onMounted, ref, watch, nextTick } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'

// 重点来了,你所需要的变量只能定义在外面,不然会一直报错,类型自己定义,我这里省了
let container: any, clock: any, mixer: any, width: number, height: number
let camera: any, scene: any, renderer: any, model:any, controls:any

onMounted(() => {
  init()
})

const init = () => {
  container = document.querySelector('.three-canvas')
  const { width, height } = container?.getBoundingClientRect()
  clock = new THREE.Clock()
  // 透视相机,设置模型视角位置
  camera = new THREE.PerspectiveCamera(40, width / height, 0.25, 500)
  camera.position.set(5, 2, 9)
  camera.lookAt(1, 1, 10)

  // 场景设置,放置物体、灯光、摄像机
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x58acbf)

  // 这个东西文档上面叫半球光,其实就是环境光
  // 颜色为白色到黑色渐变,强度为0.5,这个强度可以控制光照强度
  const hemiLight = new THREE.HemisphereLight(0xffffff, 0x000000, 2.5)
  hemiLight.position.set(-5, 10, 30)
  scene.add(hemiLight)

  // 平行光,就是太阳光,从某个方向照射
  // 控制光的颜色和强度,位置
  const dirLight = new THREE.DirectionalLight(0xffffff, 2)
  dirLight.position.set(-10, 30, 30)
  scene.add(dirLight)
  // 投影阴影设置为true
  dirLight.castShadow = true
  // 设置可以投影的宽高
  dirLight.shadow.mapSize.width = 2048
  dirLight.shadow.mapSize.height = 2048
  dirLight.shadow.camera.near = 1
  dirLight.shadow.camera.far = 50

  // 添加接收阴影的平面
  const planeGeometry = new THREE.PlaneGeometry(2000, 2000)
  const planeMaterial = new THREE.MeshStandardMaterial({
    color: 0x58acbf,
    depthWrite: false,
  })
  const plane = new THREE.Mesh(planeGeometry, planeMaterial)
  plane.rotation.x = -Math.PI / 2
  plane.position.y = -0.1 // 设置平面位置在物体下方
  plane.receiveShadow = true
  scene.add(plane)

  // 资源加载器-- 加载你的模型资源
  const loader = new GLTFLoader()
  loader.load(
    '/src/models/SmolAme.glb',
    (gltf: any) => {
      model = gltf.scene
      scene.add(model)
      // 设置物体的所有投影属性设置为true
      model.traverse((object:Record<string, any>) => {
        if (object.isMesh) {
          object.castShadow = true;
          object.receiveShadow = true;
        }
      });
      // 动画混合器/控制器,是你模型能不能动的关键,可以打印gltf.animations看看你的模型有哪些动画
      mixer = new THREE.AnimationMixer(model)
      mixer.clipAction(gltf.animations[0]).play()
    },
    undefined,
    (e: Error) => {
      console.error(e)
    }
  )
  // 设置渲染器的场景和行为
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.shadowMap.enabled = true;// 开启渲染器生成阴影
  renderer.shadowMap.type = THREE.PCFSoftShadowMap ; // 默认THREE.PCFShadowMap,调整阴影类型
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(width, height)
  container.appendChild(renderer.domElement)
  // 设置轨道控制器(鼠标或者手能否控制的关键)
  controls = new OrbitControls(camera, renderer.domElement)
  controls.update()
  window.addEventListener('resize', onWindowResize)
  animate()
}
const animate = () => {
  const dt = clock.getDelta()
  if (mixer) mixer.update(dt)
  requestAnimationFrame(animate)
  renderer.render(scene, camera)
}
const onWindowResize = () => {
  camera.aspect = width / height
  camera.updateProjectionMatrix()
  renderer.setSize(width, height)
}
</script>

<style>
.three-canvas {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: fixed;
  top: 4rem;
  left: 0;
}
</style>

最终实现效果

评论
-