前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在微信小游戏中使用three.js显示3D图形

在微信小游戏中使用three.js显示3D图形

作者头像
bering
修改2019-12-02 15:58:07
4.7K0
修改2019-12-02 15:58:07
举报
文章被收录于专栏:游戏开发之旅游戏开发之旅

年前,微信发布了一个重磅消息:微信小程序的小游戏功能,千呼万唤始出来!

笔者之前从未接触过微信小程序和WebGL的开发,但是却一直有留意相关技术的发展,大概听说原来微信小程序是不支持WebGL 3D技术的。这次借着微信大力推广小游戏,看了一下API文档,发现小游戏是可以使用的WebGL进行开发的。而最近正好又有点时间,就随便搞搞,试试小游戏的效果。因为小游戏“跳一跳”是用three.js所制作的,所以我就选择了three.js所。那么开始吧。

微信小游戏教程地址:教程小游戏

开发环境搭建

下载了最新的微信开发工具,并按照教程建立了示例项目。示例游戏是2D游戏,和我期望的有点距离,找遍网络没有一个三维的微信小游戏示例,看来只能自己试试了。

新建了一个小程序项目,并且按照教程添加了game.js和game.json,但是程序一直报错:

后来发现是调试基础库没有默认为“游戏”,按照截图操作之后就正常了:

引入three.js所

到github上下载three.js所最新版本,笔者当时下载的是R89,用最新的应该也没有问题。前文介绍过,笔者并没有开发小程序的经验,所以一上来就在game.js里直接引用三人。 JS:

代码语言:javascript
复制
 import './js/libs/weapp-adapter.js'
 
 import './js/libs/symbol.js'
 
 import './js/three/three.js'
 
 var scene = new THREE.Scene();
 

程序直接报错:

耐心看了小程序开发的说明,再看了three.js所的写法,重新修改引用方式,game.js:

代码语言:javascript
复制
import './js/libs/weapp-adapter.js'
 import './js/libs/symbol.js'
 
 
 var THREE = require('./js/three/three.js');
 
 var scene = new THREE.Scene();
 
 
 var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
 
 var context = canvas.getContext('webgl');
 
 var renderer = new THREE.WebGLRenderer(context);
 
 
 renderer.setSize(window.innerWidth, window.innerHeight);
 
 
 canvas.appendChild(renderer.domElement);
 
 var geometry = new THREE.CubeGeometry(1, 1, 1);
 
 var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
 
 var cube = new THREE.Mesh(geometry, material); 
 
 scene.add(cube);
 
 camera.position.z = 5;
 
 function render() {
 
 requestAnimationFrame(render);
 
 cube.rotation.x += 0.1;
 
 cube.rotation.y += 0.1;
 
 renderer.render(scene, camera);
 
 }
 
 render();

一个旋转的立方体就在开发环境下显示出来了!

到目前为止,一切算是比较顺利,于是马上使用预览功能上传到手机微信进行测试:

这个时候发生问题了:手机微信看不到我的立方体!

还好微信环境下有提供控制台,笔者通过记录日志,最终定位了错误:

原来是three.js所里面有一段代码:

是判断当前环境WebGL版本的,而微信环境下是opengl es3.2,使用这句正则表达式明显不能匹配到。我们稍微改一下:

代码语言:javascript
复制
	var version = parseFloat( /^(WebGL|OpenGL ES)\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );

再次发布预览试试看!

成功!

网友eastecho 写了一篇文章,更加详细的阐述了这方面的内容:https://indienova.com/indie-game-development/run-threejs-on-wechat-game-platform/

在微信小游戏中载入模型

接下来再建立我们的微信小游戏项目,如果您不是很熟悉要做哪些准备工作,可以参考前文:《 利用 three.js 开发微信小游戏的尝试》。不过我们这次使用的 weapp-adapter.js 会有所不同,是基于 @大城小胖 修改过的,可以在 这里找到

接下来我们就尝试着用 three.js 自己的 JSONLoader 来载入。其实有了模型的 json 文件以后,载入方式就可以很多样了,比如可以 require 进去包了壳的 js 文件,或者直接使用 wx.request 加载远程文件等等,但是我们认为原生方式还是比较好的,至少有以下几个优点:

  1. 保持原始格式,便于后续修改模型;
  2. 最大限度保证代码兼容性,便于移植;
  3. 由于微信小程序/小游戏包体限制,将素材放到服务器上再载入进来比较合理。

于是,我们的载入代码如下(非完整代码,仅为代码示例):

代码语言:javascript
复制
// 模型载入处理
let modelLoader = new THREE.JSONLoader()
modelLoader.load(modelURL,
  function(geometry, materials){
    mesh = new THREE.Mesh(geometry, materials[0])
    scene.add(mesh)
    console.log('模型载入完成')
  },
  // onProgress 回调
  function (xhr) {
    console.log( (xhr.loaded / xhr.total * 100) + '% 已载入' )
  },
  // onError 回调
  function(err) {
    console.log('载入出错', err.target.status)
  }
);

可能会遇到如下的错误:

代码语言:javascript
复制
TypeError: n.addEventListener is not a function
    at Ia.load (three.min.js:638)
    at ke.load (three.min.js:723)
    at new Main (main.js? [sm]:36)
    at game.js? [sm]:6
    at require (WAGame.js:11)
    at gamePage.html:84

不过对历经过实战的我们来说,应该马上会了解到,这是因为微信给出的 XMLHttpRequest 缺少 addEventListener 造成的。我们可以自行在 weapp-adapter.js 中添加它。

weapp-adapter.js 中找到 XMLHttpRequest 的定义部分,为其增加一个新的 key

代码语言:javascript
复制
{
  key: 'addEventListener',
  value: function addEventListener(type, listener) {
    if (typeof listener === 'function') {
      let event = { target: this }
      let that = this
      this['on' + type] = function () {
        listener.call(that, event)
      }
    }
  }
}

再跑一次,应该就可以正常载入了,开发环境和真机均无问题。

开发环境和真机截屏

至此,模型载入就实现了。

实现交互(临时方案)

本来是准备就此先罢手了,不过看到群中有人在尝试使用 OrbitControls 来实现简单交互,就顺便也试验了一下。OrbitControls three.js 提供的一个非常便于使用的让摄像机围绕目标对象旋转的交互功能,最简化的时候一行代码就可以搞定了,于是就将其加入到项目文件中。

我们直接将其引入:

代码语言:javascript
复制
require('libs/OrbitControls')

但是运行发现错误:

代码语言:javascript
复制
ReferenceError: THREE is not defined
    at OrbitControls.js? [sm]:18
    at require (WAGame.js:11)
    at WAGame.js:11
    at main.js? [sm]:2
    at require (WAGame.js:11)
    at WAGame.js:11
    at game.js? [sm]:4
    at require (WAGame.js:11)
    at gamePage.html:85

临时处理方法只要在 OrbitControls.js 第一行粗暴的添加这行代码引入即可:

代码语言:javascript
复制
var THREE = require('three.min');

注: 因为我没有对 three.js 做任何修改,所以直接引入了 minified 版本,如果您没有使用该版本,去掉 .min 即可。

然后代码中加入这一行就可以用了:

代码语言:javascript
复制
controls = new THREE.OrbitControls(camera);

至此没有出现什么问题,但是当想要交互的时候,一有动作就会发现屏幕被清空了。直觉告诉我是摄像机的座标或者旋转角度计算错了,经过跟踪,果然如此,在触摸屏幕并移动的时候,以下代码会出现问题:

代码语言:javascript
复制
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;

// rotating across whole screen goes 360 degrees around
rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );

// rotating up and down along whole screen attempts to go 360, but limited to 180
rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );

element.clientWidth 不存在,因此得到的值会是 NaN ,造成摄像机无法定位。我临时进行了如下修改:

代码语言:javascript
复制
rotateLeft( 2 * Math.PI * rotateDelta.x / window.innerWidth * scope.rotateSpeed );
rotateUp( 2 * Math.PI * rotateDelta.y / window.innerHeight * scope.rotateSpeed );

这只是临时的修改 ,后面有时间会尝试合理一些的解决方案。

不过呢,经过这样的修改以后,已经可以正常的通过手指对摄像机进行旋转,也可以用双指进行缩放了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开发环境搭建
    • 引入three.js所
    • 成功!
    相关产品与服务
    云开发 CloudBase
    云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档