285  
查询码:00000571
小程序中使用three.js
来源:https://developers.weixin.qq.com/community/develop/article/doc/00066c4b230b085051592292f5bc13
作者: 朱凡 于 2020年02月26日 发布在分类 / FM组 / FMWechat 下,并于 2020年02月26日 编辑
内容 链接 插入 canvas three.js


置顶 小程序中使用three.js 精选 热门

在小程序中使用three.js, 支持基本模型,OrbitControl, GTLFLoader, OBJLoader等。

小程序中使用three.js

目前小程序支持了webgl, 同时项目中有相关3D展示的需求,所以考虑将three.js移植到小程序中。
但是小程序里面没有浏览器相关的运行环境如 window,document等。要想在小程序中使用three.js需要使用相应的移植版本。https://github.com/yannliao/three.js实现了一个在 three.js 的基本移植版, 目前测试支持了 包含 BoxBufferGeometry, CircleBufferGeometry, ConeBufferGeometry, CylinderBufferGeometry, DodecahedronBufferGeometry 等基本模型,OrbitControl, GTLFLoader, OBJLoader等。

使用

下载https://github.com/yannliao/three.js项目中build目录下的three.weapp.min.js到小程序相应目录,如:

在index.wxml中加入canvas组件, 其中需要手动绑定相应的事件,用于手势控制。

<view style="height: 100%; width: 100%;" bindtouchstart="documentTouchStart" bindtouchmove="documentTouchMove" bindtouchend="documentTouchEnd" > <canvas type="webgl" id="c" style="width: 100%; height:100%;" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd" bindtouchcancel="touchCancel" bindlongtap="longTap" bindtap="tap"></canvas> </view> 

在页面中引用three.js 和相应的Loader:

import * as THREE from '../../libs/three.weapp.min.js' import { OrbitControls } from '../../jsm/loaders/OrbitControls' 

在onLoad中获取canvas对象并注册到THREE.global中,THREE.global.registerCanvas可以传入id, 用于通过THREE.global.document.getElementById找到, 如果不传id默认使用canvas对象中的_canvasID, registerCanvas同时也会将该canvas选为当前使用canvas对象. 同时请在onUnload回调中注销canvas对象. 注意: THREE.global 中最多同时注册 5 个canvas对象, 并可以通过id找到. 注册的canvas对象, 会长驻内存, 如果不及时清理可能造成内存问题.THREE.global为three.js的运行环境, 类似于浏览器中的window.

Page({ data: { canvasId: '' }, onLoad: function () {
    wx.createSelectorQuery()
    .select('#c')
    .node()
    .exec((res) => { const canvas = THREE.global.registerCanvas(res[0].node) this.setData({ canvasId: canvas._canvasId }) // const canvas = THREE.global.registerCanvas('id_123', res[0].node) // canvas代码 })
  }, onUnload: function () {
    THREE.global.unregisterCanvas(this.data.canvasId) // THREE.global.unregisterCanvas(res[0].node) // THREE.global.clearCanvas() },

注册相关touch事件. 由于小程序架构原因, 需要手动绑定事件到THREE.global.canvas或者THREE.global.document上. 可以使用THREE.global.touchEventHandlerFactory('canvas', 'touchstart')生成小程序的事件回调函数,触发默认canvas对象上的touch事件.

{
 touchStart(e) { console.log('canvas', e)
  THREE.global.touchEventHandlerFactory('canvas', 'touchstart')(e)
 },
 touchMove(e) { console.log('canvas', e)
  THREE.global.touchEventHandlerFactory('canvas', 'touchmove')(e)
 },
 touchEnd(e) { console.log('canvas', e)
  THREE.global.touchEventHandlerFactory('canvas', 'touchend')(e)
 },
}

编写three.js代码, 小程序运行环境中没有requestAnimationFrame, 目前可以使用canvas.requestAnimationFrame之后会将requestAnimationFrame注入到THREE.global中.

const camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 1, 1000);
camera.position.z = 500; const scene = new THREE.Scene();
scene.background = new THREE.Color(0xAAAAAA); const renderer = new THREE.WebGLRenderer({ antialias: true }); const controls = new OrbitControls(camera, renderer.domElement); // controls.enableDamping = true; // controls.dampingFactor = 0.25; // controls.enableZoom = false; camera.position.set(200, 200, 500);
controls.update(); const geometry = new THREE.BoxBufferGeometry(200, 200, 200); const texture = new THREE.TextureLoader().load('./pikachu.png'); const material = new THREE.MeshBasicMaterial({ map: texture }); // const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 }); const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh); // renderer.setPixelRatio(wx.getSystemInfoSync().pixelRatio); // renderer.setSize(canvas.width, canvas.height); function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(canvas.width, canvas.height);
} function render() {
  canvas.requestAnimationFrame(render); // mesh.rotation.x += 0.005; // mesh.rotation.y += 0.01; controls.update();
  renderer.render(scene, camera);
}

render()

完整示例:

index.js

import * as THREE from '../../libs/three.weapp.min.js' import { OrbitControls } from '../../jsm/loaders/OrbitControls' Page({ data: {}, onLoad: function () {
  wx.createSelectorQuery()
   .select('#c')
   .node()
   .exec((res) => { const canvas = THREE.global.registerCanvas(res[0].node) this.setData({ canvasId: canvas._canvasId }) const camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 1, 1000);
    camera.position.z = 500; const scene = new THREE.Scene();
    scene.background = new THREE.Color(0xAAAAAA); const renderer = new THREE.WebGLRenderer({ antialias: true }); const controls = new OrbitControls(camera, renderer.domElement); // controls.enableDamping = true; // controls.dampingFactor = 0.25; // controls.enableZoom = false; camera.position.set(200, 200, 500);
    controls.update(); const geometry = new THREE.BoxBufferGeometry(200, 200, 200); const texture = new THREE.TextureLoader().load('./pikachu.png'); const material = new THREE.MeshBasicMaterial({ map: texture }); // const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 }); const mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh); // renderer.setPixelRatio(wx.getSystemInfoSync().pixelRatio); // renderer.setSize(canvas.width, canvas.height); function onWindowResize() {
     camera.aspect = window.innerWidth / window.innerHeight;
     camera.updateProjectionMatrix();
     renderer.setSize(canvas.width, canvas.height);
    } function render() {
     canvas.requestAnimationFrame(render); // mesh.rotation.x += 0.005; // mesh.rotation.y += 0.01; controls.update();
     renderer.render(scene, camera);
    }

    render()

   })
 }, onUnload: function () {
  THREE.global.unregisterCanvas(this.data.canvasId)
 },
 touchStart(e) { console.log('canvas', e)
  THREE.global.touchEventHandlerFactory('canvas', 'touchstart')(e)
 },
 touchMove(e) { console.log('canvas', e)
  THREE.global.touchEventHandlerFactory('canvas', 'touchmove')(e)
 },
 touchEnd(e) { console.log('canvas', e)
  THREE.global.touchEventHandlerFactory('canvas', 'touchend')(e)
 },
 touchCancel(e) { // console.log('canvas', e) },
 longTap(e) { // console.log('canvas', e) },
 tap(e) { // console.log('canvas', e) },
 documentTouchStart(e) { // console.log('document',e) },
 documentTouchMove(e) { // console.log('document',e) },
 documentTouchEnd(e) { // console.log('document',e) },
})

index.wxml

<view style="height: 100%; width: 100%;" bindtouchstart="documentTouchStart" bindtouchmove="documentTouchMove" bindtouchend="documentTouchEnd" > <canvas type="webgl" id="c" style="width: 100%; height:100%;" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd" bindtouchcancel="touchCancel" bindlongtap="longTap" bindtap="tap"></canvas> </view> 

其他

全部示例在 https://github.com/yannliao/threejs-example

three.js 库 https://github.com/yannliao/three.js

loader 组件在 threejs-example 中的 jsm 目录中




 推荐知识

 历史版本

修改日期 修改人 备注
2020-02-26 21:29:13[当前版本] 朱凡 创建版本

 附件

附件类型

GIFGIF

知识分享平台 -V 4.8.7 -wcp