three.js 小游戏vue3实践

本次实践在vue中引入three.js,然后实现3D动画运动场景,只要用于尝试vue3的项目练手。

1.安装准备

1)、vue-cli初始化项目,vue-cli需要最新版本4.5.x。
2)、安装three,npm install three
3)、安装轨道控件插件,npm install three-orbit-controls
4)、安装加载.obj和.mtl文件的插件,npm i --save three-obj-mtl-loader; .obj和.mtl文件为3D模型文件
5)、安装渲染器插件,npm i --save three-css2drender

2. 引入并调用

安装好相关框架和插件后,还需要在调用页面引入。引入代码如下:

import * as Three from ‘three’;
import {MTLLoader, OBJLoader} from 'three-obj-mtl-loader'; 

1)引入后,正式运行,会遇到问题。
比如遇到:
16087935773727
.obj文件要放在静态文件的文件夹下,并且是未经过webpack处理的静态文件夹下,vue-cli3.0之后,有个public目录,把模型文件都移到该目录下即可。引用路径时,为${process.env.BASE_URL}+模型文件在public目录下的路径。

2)另外还会遇到MTLLoader报错,是由于three-obj-mtl-loader插件(1.0.3版本)太老了,很久没有维护,新版本的Three有些函数与插件匹配不上了。
报错信息:
THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.
这个时候,就要去改插件源码了。
方法是,node_module > three-obj-mtl-loader > index.js
16087943281113
语句:var loader = manager.getHandler(url);
以上步骤完成,使用Three开发基本不会有外部干扰报错了,剩下就是具体的业务方向。

3. 基础内容

1)坐标系。3D模型,坐标系分x、y、z轴,并且使用右手坐标系,经典图(来自百度百科)如下:
16091351168719
由坐标系观察可知,在简单水平面运动下,有变化和重点关注的是x轴和-z轴。
2)3D相机。three.js的透视照相机构造函数为THREE.PerspectiveCamera(fov, aspect, near, far)
fov: 可视角度,是视景体竖直方向上的张角。
aspect:是照相机水平方向和竖直方向长度的比值(下图w/h的值),通常是canvas宽高比。
near:相机到视景体最近的距离。
far: 相机到视景体最远的距离。且far>near的值。
16091403724221
3)WEBGL渲染器。new THREE.WebGLRenderer(),一般会设置设备的像素比率,防止canvas画布输出模糊。用到的代码如下:

 // WebGL渲染器
 const webGLRenderer = new THREE.WebGLRenderer();

 // 设置设备像素比率,防止Canvas画布模糊输出.
 webGLRenderer.setPixelRatio(window.devicePixelRatio);
 webGLRenderer.setSize(window.innerWidth, window.innerHeight);

webgl渲染器比canvas渲染器在渲染效果上是要更加好的。
16091423849682
左侧为webgl渲染器,右侧为canvas渲染器。
4)光源。是一种单点发光、照射所有方向的光源。模拟现实环境中,人们看到物体。

4. 运动难点归总

本实践中,小车在某个区域外的运动检测复原等问题,需要运用很多数学知识为基础。比如相交判定,向量等。以此推断边界,并进行相应操作。
下面介绍2D向量相乘法:
2条选段相交,每个端点需要x,y值确定平面的坐标位置
16091495073515
线段在交界(碰撞)边缘或者穿过(已跨过边界)时,可如上图所示,a线为车身边缘(前轮已经后轮的坐标点位置),b线为轨道边缘。
碰撞检测和空间划分紧密相关,向量叉乘的意义在于确定方位,方便划分空间(左右部分)。
向量叉乘(又称向量积)公式:
16092120855796
具体推导,可自行百度或知乎。
16092125574402
对应上图的公式可表示为:b.x * c.y - c.x * b.y,b,c都为向量。

以b向量为参考轴,c相对于b的方位:
叉乘结果 > 0: c在b的逆时针方向,且角度小于180度,也就是上图红虚线c。
叉乘结果 < 0: c在b的顺时针方向,且角度小于180度,即上图红虚线c‘。
叉乘结果 = 0: c与b平行。
根据向量叉乘,a向量所在的线段的2个端点,就是c和c’,所以可得出结论:a的2个端点如果分别在b的2个空间中,b的2个端点分别在a的2个空间也同样满足,判定a,b相交。

综合以上,线段相交可如下计算

var a = {
    p0: {
      x: 2.1,
      y: -5.1
    },
    p1: {
      x: 10.2,
      y: 4.9
    }
};
var b = {
    p0: {
     x: 0,
     y: 0
    },
    p1: {
     x: 9.5,
     y: 2.1
    }
};
var ap0 = a.p0;
var ap1 = a.p1;
var bp0 = b.p0;
var bp1 = b.p1;
var resultFlag = function() {
  var flag = (bp1.x - bp0.x)*(ap1.y - bp0.y)-(ap1.x - bp0.x)*(bp1.y-bp0.y);
  return flag
}

浮点数计算js中是不精准的,所以可以把上面的 return返回改写一下return flag>0

以上是碰撞检测的知识点,涉及到的数学知识,需要有相关基础,示例是在默认掌握向量基础知识,掌握向量积知识的积累基础上直接说明实际与代码结合的部分,更多理论知识需要自行补充。

5. vue3

本次实践涉及到一点点的vue3的知识。
vue3不需要写一堆分块的东西了,比如datamethods,created等等,只需要一个setup函数搞定。模板区域要用的,类似2.x时定义在data中的变量,只需要在setupreturn返回即可。
ref,onMounted都需要从vue引入,其中ref用作创建响应式的值。vue2.x定义在data中的变量,是不需要我们手动添加响应的,在其他函数中更改,是可以直接体现在视图层,暂时还没有研究此创建响应式的好处,留待后续。更多新的特性也留待以后研究。本次实践主要以尝试创建项目以及基本能运行vue3项目的目的为准。

16092331413120

总结

本次实践过程,旨在尝试各知识点的新基础,许多知识点都还处在基础阶段,深入进阶仍需假以时日。实践中,掌握了运动的向量实践知识,以及vue3的新特性小知识,收获尚可。