在Vue3里面使用Threejs

2,469 阅读2分钟

本人对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了,有兴趣的同学可以下载下来看看。

代码地址:gitee.com/tntxia/thre…