Vue + Threejs Web 可视化搭建
项目背景
因旧项目升级改造需要,加以 WebGL 和元宇宙概念兴起,经过技术讨论最用采用 Vue + Threejs 技术栈对项目进行重新编写,此篇笔记只记录 Three.js 相关代码示例。项目配置相关和请求封装等不做介绍。
项目创建
TIP
- Node.js v14.18.1 、yarn v1.22.17、@vue/cli 4.5.15、three.js 141.0 Vue2
使用 vueCLI 创建项目
vue create three-project
初始化画布
- 安装 three.js 依赖包
yarn add three
- 初始化画布,实现基础场景创建基础场景创建
项目实现效果
基础场景创建
<template>
<div class="demo-box" id="demo"></div>
</template>
<script>
import {
Scene,
Color,
Fog,
PerspectiveCamera,
AxesHelper,
BoxGeometry,
MeshStandardMaterial,
Mesh,
AmbientLight,
PointLight,
WebGLRenderer,
sRGBEncoding
} from 'three'
// 引入鼠标控制(旋转、缩放)
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
let scene, renderer, camera
let ambient, point
let controls
export default {
name: 'base_scene',
components: {},
mounted() {
this.init()
this.animate()
},
methods: {
// 初始化
init() {
let _this = this
/* 创建场景 */
scene = new Scene()
scene.background = new Color(0x443333)
// 雾化,简单的说:场景中越远的位置看起
scene.fog = new Fog(0x443333, 1, 1800)
/* 创建相机 */
camera = new PerspectiveCamera(
120,
window.innerWidth / window.innerHeight,
1,
1000
)
camera.position.z = 400
camera.position.x = 200
camera.position.y = 100
/* 创建灯光 */
_this.createLightingHandle()
// 添加坐标系参考
scene.add(new AxesHelper(1000))
// 添加立方体
let geometry, material, mesh
geometry = new BoxGeometry(100, 100, 100)
material = new MeshStandardMaterial({
color: 'green',
opacity: 0.25
})
mesh = new Mesh(geometry, material)
mesh.position.set(0, 50, 0)
scene.add(mesh)
// 创建场景渲染器
_this.rendererHandle()
// 添加鼠标控制器
_this.controlsHandle()
//窗口大小变化监听
window.addEventListener('resize', this.onWindowResize, false)
},
// 创建灯光
createLightingHandle() {
ambient = new AmbientLight(0xffffff, 0.5) //环境光
ambient.position.set(200, 300, 200) //点光源位置
scene.add(ambient)
point = new PointLight(0xffffff, 0.5) //光源设置
point.position.set(300, 320, 200) //点光源位置
scene.add(point) //将光源添加到场景中
},
// 渲染场景
rendererHandle() {
// alpha: true
renderer = new WebGLRenderer({ antialias: false })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
renderer.outputEncoding = sRGBEncoding
document.getElementById('demo').appendChild(renderer.domElement)
},
// 鼠标控制器
controlsHandle() {
controls = new OrbitControls(camera, renderer.domElement)
controls.target.set(0, 100, 0)
controls.enableDamping = true
// controls.maxDistance = 600 // 最大缩放
// controls.minDistance = -35 // 最小缩放
//上下翻转的最大角度,地面的法线方向
// controls.maxPolarAngle = 1.5
//上下翻转的最小角度,接近地面的角度
// controls.minPolarAngle = 0.3
controls.update()
},
// 添加动画
animate() {
requestAnimationFrame(this.animate)
controls.update()
renderer.render(scene, camera)
},
// 监听窗口大小
onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
// 渲染窗口大小
renderer.setSize(window.innerWidth, window.innerHeight)
}
},
// 销毁方法
destroyed() {
this.init()
this.animate()
this.onWindowResize()
window.removeEventListener('resize', this.onWindowResize, false)
}
}
</script>
<style lang="scss" scoped>
.demo-box {
overflow: hidden;
height: 100%;
width: 100%;
}
.adsorb-top {
position: fixed;
background: rgba(32, 83, 131, 0.6);
width: 100%;
padding: 20px;
box-sizing: content-box;
color: #ffffff;
font-size: 1.125rem;
}
</style>
加载模型
加载 FBX 模型
<div id="container"></div>
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'
// ....
// 初始化模型加载器
let fbxloader = new FBXLoader()
fbxloader.load('models/测试模型.fbx', (fbx) => {
fbx.position.set(item.position.x, item.position.y, item.position.z) // 模型位置
fbx.scale.set(0.02, 0.02, 0.02) // 模型缩放
fbx.rotation.y = item.rotation.y // 模型旋转
fbx.rotation.z = item.rotation.z // 模型旋转
scene.add(fbx) // 添加fbx模型到场景中
})
//....
合并 mesh 对象
地面反射
后期合成地面漫反射
添加镜子反射物体
项目总结
模型对接问题
材质渲染器
三维软件内的材质和 threejs 的材质不一致问题