vue3.0 + ts + threejs 实现简单的demo

10,948

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

背景

去年之所以再次兴起了学习 WebGL 的念头,主要是有两个原因:

  • 其一是现阶段元宇宙概念巨火;
  • 其二是想用 Web 技术实现游戏和3D动画场景,比如头号玩家电影中的科幻场景,或者像宫崎骏的动漫中的场景,简直酷毙了。

技术

实现

创建一个项目

用 ue-cli 可以快速的创建一个项目,我本地已经创建好了如下:

image.png

引入 threejs

因为我们用typescript,所以我们引入@types/three

要看@types/three文档可以去

npm: www.npmjs.com/package/@ty…

github: github.com/DefinitelyT…

安装threejs

npm install --save @types/three

安装好的效果,如下

image.png

应用threejs

在我们要用得项目中引入three

import * as THREE from "three";

image.png

引入后我们发现报错,解决如下:在shims-vue.d.ts文件中加入

declare module "@types/three";

image.png

写个demo

  1. 在router/index.ts增加路由,代码如下:
{
    path: "/demo01",
    name: "Demo01",
    component: () => import("@/views/Demo01/Demo01.vue"),
  }

image.png 2. 在views中增加目录,如下:

image.png

  1. demo01.vue代码:
<template>
  <div class="demo"></div>
</template>

<script lang="ts">
import ThreeJs from "./index";
import { defineComponent, onMounted } from "vue";
export default defineComponent({
  name: "Demo01",
  props: {},
  setup() {
    onMounted(() => {
      new ThreeJs();
    });
  },
});
</script>
<style scoped lang="scss"></style>
  1. index.ts 代码,如下:
import * as THREE from "three";

export default class ThreeJs {
  scene: THREE.Scene | null = null;
  camera: THREE.PerspectiveCamera | null = null;
  renderer: THREE.WebGLRenderer | null = null;
  ambientLight: THREE.AmbientLight | null = null;
  mesh: THREE.Mesh | null = null;

  constructor() {
    this.init();
  }

  init(): void {
    // 第一步新建一个场景
    this.scene = new THREE.Scene();
    this.setCamera();
    this.setRenderer();
    this.setCube();
    this.animate();
  }

  // 新建透视相机
  setCamera(): void {
    // 第二参数就是 长度和宽度比 默认采用浏览器  返回以像素为单位的窗口的内部宽度和高度
    this.camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    this.camera.position.z = 5;
  }

  // 设置渲染器
  setRenderer(): void {
    this.renderer = new THREE.WebGLRenderer();
    // 设置画布的大小
    this.renderer.setSize(window.innerWidth, window.innerHeight);
    //这里 其实就是canvas 画布  renderer.domElement
    document.body.appendChild(this.renderer.domElement);
  }

  // 设置环境光
  setLight(): void {
    if (this.scene) {
      this.ambientLight = new THREE.AmbientLight(0xffffff); // 环境光
      this.scene.add(this.ambientLight);
    }
  }

  // 创建网格模型
  setCube(): void {
    if (this.scene) {
      const geometry = new THREE.BoxGeometry(); //创建一个立方体几何对象Geometry
      // const material = new THREE.MeshBasicMaterial({ color: 0xff3200 }); //材质对象Material
      const texture = new THREE.TextureLoader().load(
        "/assets/imgs/dalishi.jpg"
      ); //首先,获取到纹理
      const material = new THREE.MeshBasicMaterial({ map: texture }); //然后创建一个phong材质来处理着色,并传递给纹理映射
      this.mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
      this.scene.add(this.mesh); //网格模型添加到场景中
      this.render();
    }
  }

  // 渲染
  render(): void {
    if (this.renderer && this.scene && this.camera) {
      this.renderer.render(this.scene, this.camera);
    }
  }

  // 动画
  animate(): void {
    if (this.mesh) {
      requestAnimationFrame(this.animate.bind(this));
      this.mesh.rotation.x += 0.01;
      this.mesh.rotation.y += 0.01;
      this.render();
    }
  }
}

  1. 看效果:

动画.gif

往期文章