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


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM