本人对Threejs非常感兴趣,我觉得3D技术是前端的未来科技,以后3D技术的应用会越来越多。
Vue是我几天做前端,最常使用的MVVM框架。
所以趁着最近辞职,使用Vite+Vue3+Typescript对Threejs进行了以下整合。
1. 搭建脚手架
工欲善其事,必先利其器。
我们首先要用Vite搭建一下脚手架。
在Dos命令中使用
pnpm create vite threejs-vue3-ts --template vue
可以一键生成vue3+typescript所需要的所有基础代码(对尤雨溪大神敬仰得五体投地)
2. 设置Vue的路由
这里我写了三个threejs的demo, 所以配置了三个路由,代码如下:
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const history = createWebHistory()
const routes: Array<RouteRecordRaw> = [
{
path: '/',
redirect: 'bridgeTraffic'
},
{
path: '/bridgeTraffic',
name: 'bridgeTraffic',
component: () => import('../views/BridgeTraffic.vue')
},
{
path: '/car',
name: 'car',
component: () => import('../views/Car.vue')
},
{
path: '/earthAndMoon',
name: 'earthAndMoon',
component: () => import('../views/EarthAndMoon.vue')
}
]
const router = createRouter({
history,
routes
})
export default router
3. Demo具体的代码结构。
我建了个scene的文件夹,里面放所有场景的代码,所有的场景都继承CommonScene这个类。
CommonScene里面分装了场景所需要的代码。
import {
WebGLRenderer,
PerspectiveCamera,
Scene
} from 'three';
import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
export class CommonScene {
container: HTMLElement;
renderer: THREE.WebGLRenderer;
labelRenderer: CSS2DRenderer;
camera: PerspectiveCamera;
scene: Scene;
constructor(el: HTMLElement) {
const container = this.container = el;
const renderer = this.renderer = new WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(container.offsetWidth, container.offsetHeight);
this.container.appendChild(renderer.domElement);
// 透视相机
const camera = this.camera = new PerspectiveCamera(55, this.container.offsetWidth / this.container.offsetHeight, 1, 20000);
camera.layers.enableAll();
const labelRenderer = this.labelRenderer = new CSS2DRenderer();
labelRenderer.setSize( this.container.clientWidth, this.container.clientHeight );
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
this.container.appendChild( labelRenderer.domElement );
// 相机轨道控制器
let controls: OrbitControls = new OrbitControls(camera, labelRenderer.domElement);
controls.maxPolarAngle = Math.PI * 0.495;
// controls.enablePan = false
// controls.target.set(0, 10, 20);
controls.maxDistance = 2000.0;
controls.update();
// 场景
this.scene = new Scene();
}
}
在Vue文件里,我写了个container,用来渲染:
<template>
<div class="container" ref="container">
</div>
</template>
Script用vue3的setup:
import { ref, onMounted, onUnmounted, reactive, watch } from 'vue'
import { CarScene } from '../scene/CarScene'
import { SceneTime } from '../scene/SceneTime'
// 当前时间
const now = new Date();
// 场景的时间,默认是开始时间,可以手动修改时间
const time = reactive({
hour: now.getHours(),
minute: now.getMinutes(),
second: now.getSeconds()
})
let scene:CarScene | null;
const container = ref();
onMounted(() => {
// 场景的容器
scene = new CarScene(container.value, new SceneTime(time.hour, time.minute, time.second));
scene.init();
})
onUnmounted(() => {
if (scene) {
scene.clear();
}
});
4. 总结和源码获取。
借助vue3, threejs的代码可以更好的工程化,提高我们工作的效率,本文代码已上传到gitee了,有兴趣的同学可以下载下来看看。