当前项目需要搭建一个农场的3D模型,就想到了使用Three.js
但是,在网络中VUE使用Three.js的文章是在是少之又少,特此记录一下
如需转载,请标明来源
npm 引用:npm install three --save-dev
页面import
import Stats from 'stats-js' // 帧速率显示
import * as Three from 'three' // 引用Three.js
import OrbitControls from 'three-orbitcontrols' //鼠标
import { OBJLoader, MTLLoader} from 'three-obj-mtl-loader'
data() {
return {
show: false,
stats: null, // 用于显示帧速率
camera: null, // 相机
scene: null, // scene对象
renderer: null, // 加载器
labelRenderer: null, //CSS2D加载器
mouse: null, // 鼠标对象
controls: null, // 鼠标旋转
publicPath: process.env.BASE_URL, // public地址
}
}
此处的publicPath是为了更方便的引用外部OBJ模型和MTL文件
项目中往往不会全部由前端进行模型的构建,此时就需要引入外部的模型,比较常用的就是OBJ模型,引用时需要注意所有需要加载的文件都需要放在public目录下
废话不多说,直接上代码
<div id="Stats-output"/> // 用于加载帧速率显示器--没有需求的话可以不写
<div id="container"/> // 加载3D模型主题
init() {
// state 加载帧速率显示器
this.stats = new Stats()
this.stats.setMode(0)
const state = document.getElementById('Stats-output')
state.appendChild(this.stats.domElement)
// 获取到实例
const container = document.getElementById('container')
// 获取相机 此处使用的是透视相机
this.camera = new Three.PerspectiveCamera(80, container.clientWidth/container.clientHeight, 1, 10000)
// 此处用于设置相机位置
this.camera.position.set(300, 200, 300)
this.scene = new Three.Scene()
// 加载辅助坐标系 实际应用的时候需要注释此代码
const axisHelper = new Three.AxisHelper(250)
this.scene.add(axisHelper)
// 聚光源
const spotLight = new Three.SpotLight(0xac6c25);
// 设置聚光光源位置
spotLight.position.set(-500, 200, 500);
// 聚光灯光源指向网格模型
// spotLight.target = this.mesh;
// 设置聚光光源发散角度
spotLight.angle = Math.PI / 6
spotLight.penumbra = 1
spotLight.name = '聚光灯'
this.scene.add(spotLight);//光对象添加到scene场景中
// 环境光
const ambient = new Three.AmbientLight(0xFFFFFF)
ambient.name = '环境光'
this.scene.add(ambient)
// 加载器
this.renderer = new Three.WebGLRenderer({ antialias: true })
this.renderer.setSize(container.clientWidth, container.clientHeight)
container.appendChild(this.renderer.domElement)
this.renderer.setClearColor(0xffffff, 0.9)
},
// 鼠标控制器
this.getOrbitControls()
鼠标控制器—通过鼠标控制模型的旋转
// 鼠标旋转
getOrbitControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement)
// 设置相机距离原点的最近距离
this.controls.minDistance = 300
// 设置相机距离原点的最远距离
this.controls.maxDistance = 500
// 是否开启右键拖拽
// this.controls.enablePan = true
},
渲染动画
animate() {
requestAnimationFrame(this.animate)
// 更新帧数显示
this.stats.update()
// 更新加载器
this.renderer.render(this.scene, this.camera)
},
所有的函数准备完毕后在mounted()函数中开始引用
mounted() {
this.init() // 初始化函数
this.animate() // 渲染
},
此时一个场景就加载完成了
但是当前还没有创建任何的模型
写一个函数getCube()用于创建一个常见的正方体
getCube() {
// 获取材质
const material = new Three.MeshBasicMaterial({
color: 0x5C3A21 })
const cube = new Three.BoxGeometry(100, 100, 100)
const cubeMesh = new Three.Mesh(cube, material)
// 控制位置
cubeMesh.position.set(0, 0, 0)
// 加载
this.scene.add(cubeMesh)
}
写好后,在任何地方调用都可以 建议放在init()函数的末尾
这样一个简单模型就加载出来了
// 加载OBJ和MTL文件
getWall() {
const OBJLoader = new Three.OBJLoader()// obj加载器
const MTLLoader = new Three.MTLLoader()// 材质文件加载器
MTLLoader.load(`${this.publicPath}frame/frame.mtl`, mtl => {
// obj的模型会和MaterialCreator包含的材质对应起来
OBJLoader.setMaterials(mtl)
OBJLoader.load(`${this.publicPath}frame/frame.obj`, obj => {
console.log(obj)
obj.scale.set(1, 1, 1) // 放大obj组对象
obj.position.set(0, 0, 0) //调整位置
obj.name = '墙'
this.scene.add(obj)// 返回的组对象插入场景中
})
})
},
同理,写好的函数可以在任何地方使用 建议放在init()函数的末尾
需要注意的是,在加载外部模型的时候,如果MTL文件中使用了贴图,则需要对该文件进行相应的修改