Three.js教程
入门
使用vite和uniapp搭建小程序Three.js环境

今天,这篇文章带大家一起使用 uniapp 和 Three.js 搭建小程序开发环境。

uniapp 搭建

uniapp 有一个官方的编辑器 HBuilderX,在官网就可以下载。这里我们不使用它来创建项目,使用 vite 来管理项目。

官方安装教程地址: https://zh.uniapp.dcloud.io/quickstart-cli.html (opens in a new tab)

这里我们使用 vue3 和 vite,所以用下面这条命令

npx degit dcloudio/uni-preset-vue#vite my-vue3-project

等待一会,命令执行完成后,我们就完成了项目的创建了。 之后进入项目,执行

npm install

运行项目

npm run dev:mp-weixin

通过这条命令,会生成一个 dist 目录,这个目录就是我们的小程序项目。

小程序工具

在开始小程序之前,大家需要先去创建小程序获取 appID。然后在下面的地址,下载小程序开发工具。 https://mp.weixin.qq.com/wxamp/thirdtools/extend?token=821503770&lang=zh_CN (opens in a new tab)

打开小程序开发工具,导入项目,选择 dist 目录,然后点击确定。

three 配置

这里,我们不能直接直接安装 three 依赖

通过一通调研,找到了https://three-x.cn/这个网站,这个网站提供了一个可以在小程序中使用的three.js库。 (opens in a new tab)

然后,我们需要通过小程序插件模式来引入这个库。 访问 https://mp.weixin.qq.com/wxopen/plugindevdoc?appid=wx5d6376b4fc730db9 (opens in a new tab) ,点击添加插件将这个插件添加到我们的小程序项目中。

接着打开,我们刚才创建的项目代码,进入 src 下的 minifest.json 文件

找到 mp-weixin,然后在里面添加插件配置。

{
  "mp-weixin": {
    "plugins": {
      "ThreeX": {
        "version": "3.2.1",
        "provider": "wx5d6376b4fc730db9",
        "export": "threex.js"
      }
    }
  }
}

在 src 下创建一个文件 threex.js,然后在里面引入 three-x 库。

module.exports = {
  getApp() {
    return getApp();
  },
  getCurrentPages() {
    return getCurrentPages();
  },
  wx_request() {
    return wx.request;
  },
  wx_downloadFile() {
    return wx.downloadFile;
  },
};

到此,我们关于 three.js 的配置就完成了。

代码

将下面的代码插入到 pages/index/index.vue 文件中,做一下测试。下面的代码有几个地方解释下。

  1. 引入插件库,通过 requirePlugin("ThreeX") 来引入插件库。
  2. 注意 THREE.DHTML,这个是插件库提供的一些全局变量,比如 document, window, Event, Event0, requestAnimationFrame, cancelAnimationFrame。因为小程序的环境和浏览器环境不一样,所以这些全局变量需要通过插件库提供的变量来使用。否则直接使用小程序的全局变量会报错。

通过下面的代码,就可以在小程序中看到一个立方体。

<template>
  <view id="page">
    <canvas
      id="canvas_webgl2"
      type="webgl2"
      @touchstart="webgl_touch"
      @touchmove="webgl_touch"
      @touchend="webgl_touch"
      @touchcancel="webgl_touch"
    >
    </canvas>
  </view>
</template>
 
<script>
const THREE = requirePlugin("ThreeX");
 
const {
  document,
  window,
  Event,
  Event0,
  requestAnimationFrame,
  cancelAnimationFrame,
} = THREE.DHTML;
var requestId;
 
export default {
  data() {
    return {
      setting: {
        color: "#00ff00",
        width: 1,
        height: 2,
        depth: 3,
      },
    };
  },
  onUnload() {
    cancelAnimationFrame(requestId, this.canvas);
    this.worker && this.worker.terminate();
    this.renderer.forceContextLoss();
    this.renderer.context = null;
    this.renderer.domElement = null;
    this.renderer = null;
  },
  onLoad() {
    document
      .createElementAsync("canvas", "webgl2", this)
      .then((canvas) => this.run(canvas).then());
  },
 
  methods: {
    webgl_touch(e) {
      const web_e = (window.platform == "devtools" ? Event : Event0).fix(e);
      this.canvas.dispatchEvent(web_e);
    },
    createMesh() {
      if (this.mesh) {
        this.scene.remove(this.mesh);
      }
      var material = new THREE.MeshLambertMaterial({
        color: this.setting.color,
      });
      var mesh = new THREE.Mesh(
        new THREE.BoxGeometry(
          this.setting.width,
          this.setting.height,
          this.setting.depth
        ),
        material
      );
 
      this.scene.add(mesh);
      this.mesh = mesh;
    },
    async run(canvas) {
      var that = this;
      this.canvas = canvas;
      var renderer = (this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        canvas,
      }));
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.outputEncoding = THREE.sRGBEncoding;
 
      var scene = (this.scene = new THREE.Scene());
      scene.background = "#888888";
      var camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        100
      );
      camera.position.set(10, 5, 10);
      camera.lookAt(scene.position);
 
      /////////////////////////////////////////
      const light0 = new THREE.AmbientLight(0xffffff, 0.5);
      scene.add(light0);
      //
      const light1 = new THREE.DirectionalLight(0xffffff, 0.5);
      light1.position.set(-5, 10, 5);
      scene.add(light1);
      that.createMesh();
 
      function animate() {
        requestAnimationFrame(() => {
          animate();
        });
        renderer.render(scene, camera);
      }
      animate();
    },
  },
};
</script>
 
<style>
canvas {
  width: 100vw;
  height: 100vh;
}
</style>

代码

github

https://github.com/calmound/threejs-demo/tree/main/three-uniapp (opens in a new tab)

gitee

https://gitee.com/calmound/threejs-demo/tree/main/three-uniapp (opens in a new tab)