当微信小程序遇到AR(三)

摘要:
当微信小程序遇到AR,会擦出怎么样的火花?期待与激动......通过该教程,可以从基础开始打造一个微信小程序的AR框架,所有代码开源,提供大家学习。接下来的另一个基础人物就是对接Three.js库:1.实现在微信小程序中访问摄像头,并且可以实时的拿到每一帧画面的数据。注册地址=˃注册成功之后,需要下载微信小程序开发工具。

微信小程序遇到AR,会擦出怎么样的火花期待激动......

通过该教程,可以从基础开始打造一个微信小程序的AR框架,所有代码开源,提供大家学习。

本课程需要一定的基础:微信开发者工具,JavaScript,Html,Css

第三章:基石-接入Three.js

【前情提要】

上一章,我们已经可以在微信小程序中访问摄像头,并且获得每一帧的数据了。接下来的另一个基础人物就是对接Three.js库:

1. 实现在微信小程序中访问摄像头,并且可以实时的拿到每一帧画面的数据。
2. 实现在微信小程序中访问WebGL接口,实现绘制三维物体。该教程采用Three.js引擎
3. 实现在背景为摄像头实时画面的背景上显示WebGL的3D物体。
4. 整体框架搭建
5. 图像算法接入

【目的】

将Three.js引擎接入微信小程序,实现一个cube旋转的基本demo。

【准备】

下面需要搭建环境,做一些准备工作。

首先,需要注册微信小程序开发者。注册地址=>

注册成功之后,需要下载微信小程序开发工具。下载地址=>

目前笔者的开发环境是:Windows 10

下载的微信小程序版本为:RC v1.0.2.1909111

【创建工程】

按照与上一章同样的步骤,我们创建一个简单的基本工程。这里就不再赘述了。创建好之后的基本工程目录结构如下:

当微信小程序遇到AR(三)第1张

[开发]

下面我们将完成一下几个步骤:

1. 导入Three.js库,并做相应的适配。

2. 创建微信小程序的WebGL画布Canvas并初始化。

3. 利用Three.js创建一个包含Cube的场景,并显示。

4. 加入Cube的运动动画。

1. 导入Three.js库,并做相应的适配

首先我们需要去Three.js的官网下载最新版本的Three.js库文件,可以前往官方的:Github=>

打开Github页面之后,在“Bruch”,下选择“Master”分支,如下图:

当微信小程序遇到AR(三)第2张

这时候,我们可以进入到“Build”文件夹下,下载最新编译好的库,可以看到当前的Build最新的版本为r109。当然同学们在学习的时候,可能最新的版本会更高,没有关系,下载你们当前最新的版本即可。

当微信小程序遇到AR(三)第3张

进入“Build”文件夹之后,会看见几个编译好的库:three.js, three.min.js, three.module.js。其中:

three.js: 编译好的原始库文件

three.min.js:编译好的压缩过的库文件(压缩之后的库文件大小更小了,但是里面的内容已经不具备可读性了)

three.module.js:如果不以库的形式而是以一个模块的形式使用three.js可以下载这个文件

目前,我们为了能做一些微信的适配,需要明文可读的库文件,所以选择第一个three.js文件

当微信小程序遇到AR(三)第4张

点击“Download”按钮下载该文件。(可能你的浏览器不会提示下载,而是直接在页面上打开了这个文件,可以选择全选然后复制里面的内容到一个新的文本文件,在保存为three.js格式即可)。

当微信小程序遇到AR(三)第5张

接下来,我们需要在小程序工具中,新建一个文件夹用来保存所有的库文件,所以新建一个名为:“libs”的文件夹,并将下载好的“three.js”文件放入其中,如下如:

当微信小程序遇到AR(三)第6张

至此,我们就导入了three.js文件到我们的项目工程中,保存之后,重新编译,可以看到并没有报任何错误。

当微信小程序遇到AR(三)第7张

从编译中可以看出,three.js已经编译了,并且由于文件过大跳过了压缩过程以及ES6转ES5的过程。这里不用做任何处理,说明three.js已经被我们的小程序工具支持了。不需要做过多的适配工作。(在之前版本的three.js或者微信开发者工具基础库比较旧的版本上,导入three.js会出现很多错误提示,这是由于three.js中很多关于DOM的引用都没有被小程序开发基础库支持,而现在的版本可以看到已经被很好的支持了)。

2. 创建微信小程序的WebGL画布Canvas并初始化。

下面新建一个Canvas用来绘制WebGL的内容,打开"pages/index/index.wxml"文件,添加相关的标签如下:

<!--index.wxml-->
<view>
  <!--创建canvas标签用于WebGL-->
  <canvas 
    type="webgl"
    id="webgl"
    canvas-id="webgl"
    style="{{canvasWidth}}px;height:{{canvasHeight}}px;">
  </canvas>
</view>

在这段代码中,我们制定了canvas的类型type为“webgl”,设置了id为"webgl"(以便js代码访问到),以及canvas的样式style。样式style我们通过了数据绑定的方法来实现,以便后面在js代码中动态的修改canvas的样式(主要是canvas的大小)。接下来,我们就打开“pages/index/index.js”文件,添加代码初始化canvas:

//index.js
//获取应用实例
const app =getApp();
Page({
  data: {
    canvasWidth:0,
    canvasHeight:0
  },
  /**
   * 页面加载回调函数
   */
  onLoad: function() {
    //初始化Canvas对象
    this.initWebGLCanvas();
  },
  /**
   * 初始化Canvas对象
   */
  initWebGLCanvas:function()
  {
    //获取页面上的标签id为webgl的对象,从而获取到canvas对象
    const query =wx.createSelectorQuery();
    query.select('#webgl').node().exec((res) =>{
      var canvas = res[0].node;
      this._webGLCanvas =canvas;
      //获取系统信息,包括屏幕分辨率,显示区域大小,像素比等
      var info =wx.getSystemInfoSync();
      this._sysInfo =info;
      //设置canvas的大小,这里需要用到窗口大小与像素比乘积来定义
      this._webGLCanvas.width = this._sysInfo.windowWidth * this._sysInfo.pixelRatio;
      this._webGLCanvas.height = this._sysInfo.windowHeight * this._sysInfo.pixelRatio;
      //设置canvas的样式
      this._webGLCanvas.style ={};
      this._webGLCanvas.style.width = this._webGLCanvas.width.width;
      this._webGLCanvas.style.height = this._webGLCanvas.width.height;
      //设置显示层canvas绑定的样式style数据,页面层则直接用窗口大小来定义
      this.setData({
        canvasWidth: this._sysInfo.windowWidth,
        canvasHeight: this._sysInfo.windowHeight
      });
    });
  }
})

小提示:

笔者的使用习惯,是在每一个语句结尾使用分号";",当然在js中也可以不使用。这个习惯是来源于c++的编程习惯。笔者认为加上分号能更好的区分每一条语句,不容易和下一行发生混淆。当然,大家可以有自己的使用习惯。

解释一下上面的代码,首先在onLoad回调函数中,加入了一个initWebGLCanvas的自定义函数,用来初始化WebGL的canvas对象。在这个函数中:

首先应用wx.createSelectorQuery和select语句获取到当前的canvas对象;

接着通过wx.getSystemInfoSync语句获取到当前的系统相关信息,主要用到了窗口大小和像素比两个信息。

最后通过创就大小和像素比设置canvas的长宽属性。

3. 利用Three.js创建一个包含Cube的场景,并显示

接下来,我们将利用three.js创建一个新的三维场景,并显示一个Cube对象。

小知识:

Three.js在构建场景的时候与大多数的三维引擎类似,都有几个基本的抽象概念:

Camera:描述了某个视图观察者的视觉属性,包括观察的位置,方向,范围等。

Scene:一个三维的场景。

Light:三维场景中的灯光。

Mesh:三维场景中的某个网格对象,包括了网格的集合描述以及材质的描述。

Geomtry:三维图形的集合描述。

Material:三维图形的表面材质属性。

Texture:贴图。

该教程,并不会对Three.js进行展开讲解,毕竟该教程主要是讲解如何在微信小程序中搭建AR环境,如果感兴趣的同学,可以自行学习=>

具体的步骤就是首先创建WebGLRenderer(WebGL渲染器),然后创建基本的三维显示元素,包括摄像头,场景,物体等。最后执行渲染操作。我么可以在initWebGLCanvas函数最后加一个自定义函数的调用:initWebGLScene,然后在这个自定义的函数中,来实现场景的初始化。然后在这个函数结尾再调用一个自定义的执行渲染的函数,具体的代码如下:

首先,一开始需要引用three.js库文件:

//index.js
//导入three.js库
import * as THREE from '../../libs/three.js'

接着来定义我们的InitWebGLScene函数以及渲染函数renderWebGL

  /**
   * 初始化WebGL场景
   */
  initWebGLScene:function()
  {
    //创建摄像头
    var camera = new THREE.PerspectiveCamera(60,this._webGLCanvas.width /this._webGLCanvas.height , 1, 1000);
    this._camera =camera;
    //创建场景
    var scene = newTHREE.Scene();
    this._scene =scene;
    //创建Cube几何体
    var cubeGeo = new THREE.CubeGeometry(30, 30,30);
    //创建材质,设置材质为基本材质(不会反射光线,设置材质颜色为绿色)
    var mat = new THREE.MeshBasicMaterial({ color: 0x00FF00});
    //创建Cube的Mesh对象
    var cube = newTHREE.Mesh(cubeGeo, mat);
    //设置Cube对象的位置
    cube.position.set(0,0,-100);
    //将Cube加入到场景中
    this._scene.add(cube);
    //创建渲染器
    var renderer = newTHREE.WebGLRenderer({
      canvas: this._webGLCanvas
    });
    //设置渲染器大小
    this._renderer =renderer;
    this._renderer.setSize(this._webGLCanvas.width, this._webGLCanvas.height);
    //开始渲染
    this.renderWebGL();
  },
  /**
   * 渲染函数
   */
  renderWebGL:function(){
    //渲染执行场景,指定摄像头看到的画面
    this._renderer.render(this._scene,this._camera);
  }

这样,我们就完成了场景的创建和渲染。保存编译的化,发现出现了错误:

当微信小程序遇到AR(三)第8张

这个错误指出addEventListener不是一个有效的函数,定位到了three.js中的代码,我们可以看到具体的问题出在了以下两行:

当微信小程序遇到AR(三)第9张

这就是之前提到的适配问题,three.js的原生代码和微信小程序的框架不适应。这两行代做所做的事情就是在创建WebGL之前先添加两个事件监听函数,用来监听WebGL的Contex对象是否消逝或者再次出现。然而在微信小程序的框架中,会自动管理WebGL的Context对象,也不支持对Canvas添加这两个事件,所以我们直接注释掉这两行代码即可。

再次保存,编译,我们就可以看到正确的显示了:

当微信小程序遇到AR(三)第10张

可以看到,通过之前的设置,无论屏幕的分辨率是多少,我们都可以将WebGL的画布铺满整个屏幕,而且保持了正确像素比,渲染出来的立方体也没有变形。

不过,目前完全没有WebGL的Feel,所以我们可以加一些代码,让这个Cube立方体动起来。

4. 加入Cube的运动动画。

运动,就需要每一帧的刷新。所以我们会用到微信提供的WebGL帧刷新事件。另外,我们需要刷新cube对象的角度,让它旋转起来,这就需要在renderWebGL函数中访问到cube对象。当然可以有很多方法,例如我们可以将cube对象传递到renderWebGL函数中。从而在渲染函数渲染每一帧画面前旋转cube对象。

另外我们需要控制运动的速度,但是由于每一帧渲染的时间并不是固定的,这就受到手机性能,场景复杂程度,代码逻辑等一系列因素影响,如果我们每一帧旋转一个固定的角度,那么最后Cube旋转的速度就不是匀速的,也不可控。所以如何要控制旋转的速度固定匀速呢?

这就需要我们获取到每一帧的时间间隔,然后根据时间间隔来设置每一帧Cube的旋转角度。如果间隔较大,那旋转角度也要大一点,因为用了比较长的时间,反之则越小。所以每一帧需要设置的旋转角度应该和间隔时间成正比。

接下来我们就用代码实现一下,首先我们在initWebGLScene函数的结尾,修改一下代码,记录一下第一次渲染的时间,以及传递cube引用到renderWebGL函数中:

  /**
   * 初始化WebGL场景
   */
  initWebGLScene:function()
  {
   。。。省略之前的代码
//设置渲染器大小 this._renderer =renderer; this._renderer.setSize(this._webGLCanvas.width, this._webGLCanvas.height); //记录当前时间 var lastTime =Date.now(); this._lastTime =lastTime; //开始渲染 this.renderWebGL(cube); }

接着我们修改一下renderWebGL函数:

/**
   * 渲染函数
   */
  renderWebGL:function(cube){
    //获取当前一帧的时间
    var now =Date.now() ;
    //计算时间间隔,由于Date对象返回的时间是毫秒,所以除以1000得到单位为秒的时间间隔
    var duration = (now - this._lastTime) / 1000;
    //打印帧率
    console.log(1/duration + 'FPS');
    //重新赋值上一帧时间
    this._lastTime =now;
    //旋转Cube对象,这里希望每秒钟Cube对象沿着Y轴旋转180度(Three.js中用弧度表示,所以是Math.PI)
    cube.rotation.y += duration *Math.PI;
    //渲染执行场景,指定摄像头看到的画面
    this._renderer.render(this._scene,this._camera);
    //设置帧回调函数,并且每一帧调用自定义的渲染函数
    this._webGLCanvas.requestAnimationFrame(()=>{
      this.renderWebGL(cube);
    });
  }

在渲染函数中,我们修改了Cube对象的旋转角度,并且打印了帧率。在笔者的电脑上。帧率维持在60FPS左右

当微信小程序遇到AR(三)第11张

当微信小程序遇到AR(三)第12张

当然,这是在模拟器中的版本。在真机上的测试(修改了Canvas的高度,以便显示输出面板,所以Cube形状会有一些压扁)。笔者的手机是华为Mate10Pro,测试结果如下图:

当微信小程序遇到AR(三)第13张

发现帧率也是基本维持在60FPS左右。这已经可以满足当前绝大多数三维应用的开发了。

【总结】

这一章,我们在微信小程序中引入了Three.js库,并且对库中不适配的地方做了修改。最后在Three.js库的帮助下,创建了一个动态的三维场景并且真机上测试。至此,如果只是开发微信小程序WebGL的同学已经可以在现在的基础上创建出绚丽多彩的WebGL程序了~

【代码】

Github=>

免责声明:文章转载自《当微信小程序遇到AR(三)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇sqlserver批量规律修改字段值海康SDK编程指南下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

WebSocket实战

前言 互联网发展到现在,早已超越了原始的初衷,人类从来没有像现在这样依赖过他;也正是这种依赖,促进了互联网技术的飞速发展。而终端设备的创新与发展,更加速了互联网的进化; HTTP/1.1规范发布于1999年,同年12月24日,HTML4.01规范发布;尽管已到2012年,但HTML4.01仍是主流;虽然 HTML5的草案已出现了好几个年头,但转正日期,遥...

小程序加入echart 图表

github上的地址 https://github.com/ecomfe/echarts-for-weixin 复制到当前项目根目录下 添加展示bar图表例子的文件夹  index.json 中配置使用的组件,以及组件的位置 这一配置的作用是,允许我们在 pages/bar/index.wxml 中使用 <ec-canvas> 组件。注意路径...

微信小程序添加、删除class’

终于等到公司开发小程序了,学习的时候不觉得有什么,实际开发就会出现各种问题。 今天第一天开发就遇到问题了。 项目需求,要一个平时的nav导航栏,这玩意用jQuery两行代码解决了,可是小程序不允许操作dom啊; 折腾一个多小时最终找到两种方法,分享给大家; 第一种比较直接但是,不适合多个操作; 1,第一种感觉比较傻      <view class=...

有关Canvas的一点小事—canvas数据和像素点

1、  canvas生成base64数据 canvas.toDataURL()生成的数据可以直接给image对象使用作为<img>显示在前端,也可以传给后台生成图片保存。前端生成保存图片的好像也有,但是比较麻烦,而且不兼容。我记得zip.js就可以在前端打包图片生成压缩包,不过我现在用不到,哪天想到了再整理整理。                ...

关于微信小程序map地图的使用

结构部分:  <map bindregionchange='bindregionchange' show-location longitude='{{longitude}}' latitude='{{latitude}}' markers='{{markers}}' scale='18' > <cover-image bindtap='...

微信小程序---生命周期函数【详解】

在小程序的开发过程中,小程序的生命周期是非常重要的,特别是这7个小程序生命周期函数。 小程序的7个生命周期函数: 1、onLoad 监听页面加载 onLoad函数:一个页面只会被调用一次,可以在onLoad中获取当前页面所调用的 query 参数。 示例:onLoad:function(options){} 2、onReady 监听页面初次渲染完成 onR...