微信小程序遇到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

【创建工程】

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

 [开发]

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

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

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

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

  4. 加入Cube的运动动画。

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

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

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

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

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

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

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

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

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

  

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

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

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

  从编译中可以看出,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="width:{{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 = new THREE.Scene();
this._scene = scene; //创建Cube几何体
var cubeGeo = new THREE.CubeGeometry(30, 30,30);
//创建材质,设置材质为基本材质(不会反射光线,设置材质颜色为绿色)
var mat = new THREE.MeshBasicMaterial({ color: 0x00FF00 });
//创建Cube的Mesh对象
var cube = new THREE.Mesh(cubeGeo, mat);
//设置Cube对象的位置
cube.position.set(0,0,-100);
//将Cube加入到场景中
this._scene.add(cube); //创建渲染器
var renderer = new THREE.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);
}

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

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

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

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

  可以看到,通过之前的设置,无论屏幕的分辨率是多少,我们都可以将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左右

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

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

【总结】

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

【代码】

Github=>

当微信小程序遇到AR(三)的更多相关文章

  1. 当微信小程序遇到AR(四)

    当微信小程序遇到AR,会擦出怎么样的火花?期待与激动...... 通过该教程,可以从基础开始打造一个微信小程序的AR框架,所有代码开源,提供大家学习. 本课程需要一定的基础:微信开发者工具,JavaS ...

  2. 当微信小程序遇到AR(二)

    当微信小程序遇到AR,会擦出怎么样的火花?期待与激动...... 通过该教程,可以从基础开始打造一个微信小程序的AR框架,所有代码开源,提供大家学习. 本课程需要一定的基础:微信开发者工具,JavaS ...

  3. 使用wepy开发微信小程序商城第三篇:购物车(布局篇)

    使用wepy开发微信小程序商城 第三篇:购物车(布局篇) 前两篇如下: 使用wepy开发微信小程序商城第一篇:项目初始化 使用wepy开发微信小程序商城第二篇:路由配置和页面结构 基于上两篇内容,开始 ...

  4. 微信小程序把玩(三十三)Record API

    原文:微信小程序把玩(三十三)Record API 其实这个API也挺奇葩的,录音结束后success不走,complete不走,fail也不走, 不知道是不是因为电脑测试的原因,只能等公测或者等他们 ...

  5. 微信小程序把玩(三十四)Audio API

    原文:微信小程序把玩(三十四)Audio API 没啥可值得太注意的地方 重要属性: 1. wx.getBackgroundAudioPlayerState(object) 获取播放状态 2.wx.p ...

  6. 微信小程序把玩(三十一)wx.uploadFile(object), wx.downloadFile(object) API

    原文:微信小程序把玩(三十一)wx.uploadFile(object), wx.downloadFile(object) API 反正我是没有测通这两个API!!!!不知道用的方式不对还是其他的!! ...

  7. 微信小程序把玩(三十九)navigation API

    原文:微信小程序把玩(三十九)navigation API 演示效果也看到了小程序也就提供这几个处理导航控制.值得注意的是只能同时导航五个页面 主要属性: 导航条一些方法 wx.setNavigati ...

  8. 微信小程序把玩(三十五)Video API

    原文:微信小程序把玩(三十五)Video API 电脑端不能测试拍摄功能只能测试选择视频功能,好像只支持mp4格式,值得注意的是成功之后返回的临时文件路径是个列表tempFilePaths而不是tem ...

  9. 微信小程序把玩(三十六)Storage API

    原文:微信小程序把玩(三十六)Storage API 其实这个存储在新建Demo的时候就已经用到了就是存储就是那个logs日志,数据存储主要分为同步和异步 异步存储方法: 存数据 wx.setStor ...

随机推荐

  1. HTML5游戏2D开发引擎

    1.PixiJS(基于webGl和canvas) 官网:http://www.pixijs.com/ github(star:20672):https://github.com/pixijs/pixi ...

  2. BOOTP引导程序协议

    我们介绍了一个无盘系统,它在不知道自身 I P地址的情况下,在进行系统引导时能够通过R A R P来获取它的I P地址.然而使用R A R P有两个问题:(1)I P地址是返回的唯一结果:(2)既然R ...

  3. python_生成器

    生成器: # 生成器函数(内部是否包含yield) def func(): print('F1') yield 1 print('F2') yield 2 print('F3') yield 100 ...

  4. HDU 6154 - CaoHaha's staff | 2017 中国大学生程序设计竞赛 - 网络选拔赛

    /* HDU 6154 - CaoHaha's staff [ 构造,贪心 ] | 2017 中国大学生程序设计竞赛 - 网络选拔赛 题意: 整点图,每条线只能连每个方格的边或者对角线 问面积大于n的 ...

  5. .NET调用AS/400上的程序(.NET CALL AS/400 PGM)

    http://www.3rgb.com/entry/dotnet_call_as400_program2 .NET连接AS400出现[Safe handle has been closed http: ...

  6. web开发下载文件夹

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用.此控件PC全平台支持包括mac,linux系统的文件上传,文章末尾将附上控件下载与教程链接 ...

  7. [51Nod] 配对

    https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 求出树的重心,跑spfa #include <iostre ...

  8. (WA)BZOJ 1503: [NOI2004]郁闷的出纳员

    二次联通门 : BZOJ 1503: [NOI2004]郁闷的出纳员 /* BZOJ 1503: [NOI2004]郁闷的出纳员 考虑这样一个事实 无论是加或减 都是针对全体人员的 那么只需要记录一个 ...

  9. 「ARC103D」Robot Arms「构造」

    题意 给定\(n\)个点,你需要找到一个合适的\(m\)和\(d_1,d_2,...,d_m\),使得从原点出发每次向四个方向的某一个走\(d_i\)个单位,最终到达\((x_t, y_t)\).输出 ...

  10. python3 操作ppt

    # pip install pywin32com# ppt太大会读取失败import win32com from win32com.client import Dispatch, constants ...