之前的笔记
如果您是第一次阅读我们关于微信小游戏开发的笔记,那么您可能需要先通过之前的笔记快速了解一下:
继续 three.js 的探险
今天我们会继续基于 three.js
来做尝试。因为在各个群中,大家都在试图载入模型,不少人遇到了这样那样的问题,所以今天给大家介绍一种成功载入模型的方法。(方法很多,这里只介绍我们采用的方法)
我们今天使用的模型是通过 Blender 导出的。之所以使用 Blender,是因为它是免费且功能完善的 3D 软件,我们可以大大方方拿来使用。而正由于它是免费的,所以关于它的使用和开发技巧网络上随手可得,社区也非常活跃,很适合自学。
准备工作
输出模型
要从 Blender 输出符合 three.js
标准的模型,我们需要为 Blender 添加一个专用的输出插件。如果您在学习和使用 three.js
,那么这个插件您应该已经有了,它就在 three.js
的源码包中,位置如下:
three.js / utils / exporters / blender
github 上在这里。
假定您已经安装好了 Blender,我们需要将插件 addons / io_three
目录整个儿复制到 Blender 的插件目录。
在 Windows 下一般在这里:
{盘符}:\Program Files\Blender Foundation\Blender\2.7X\scripts\addons
而 Mac 下一般在这里:
~/Library/Application Support/Blender/2.7X/scripts/addons
如果没有 scripts/addons
目录也不要方,可以自行创建。
然后该目录看起来大概是这样:
... ── Blender └── 2.7X ├── config └── scripts └── addons └── io_three
准备完毕以后,就可以打开 Blender 了。我们需要进入 Blender 的用户设置面板,在“插件”中搜索“three”,找到后选定它,允许使用它作为输出选项:
然后记得保存用户设置,这样以后就可以一直使用。好,现在我们就可以打开自己的模型文件并输出了。
输出的选项还是蛮多,我们选用了如下的设置供参考,您也可以自己尝试调整。
保存输出的 json
文件,然后将其上传到自己的服务器,接下来就可以在微信小游戏中使用。
在微信小游戏中载入模型
接下来建立我们的微信小游戏项目,如果您不是很熟悉要做哪些准备工作,可以参考前文:《利用 three.js 开发微信小游戏的尝试》。不过我们这次使用的 weapp-adapter.js
会有所不同,是基于 @大城小胖 修改过的,可以在这里找到。
接下来我们就尝试着用 three.js
自己的 JSONLoader
来载入。其实有了模型的 json
文件以后,载入方式就可以很多样了,比如可以 require
进去包了壳的 js
文件,或者直接使用 wx.request
加载远程文件等等,但是我们认为原生方式还是比较好的,至少有以下几个优点:
- 保持原始格式,便于后续修改模型;
- 最大限度保证代码兼容性,便于移植;
- 由于微信小程序/小游戏包体限制,将素材放到服务器上再载入进来比较合理。
于是,我们的载入代码如下(非完整代码,仅为代码示例):
// 模型载入处理 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) } );
可能会遇到如下的错误:
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
:
{ 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
提供的一个非常便于使用的让摄像机围绕目标对象旋转的交互功能,最简化的时候一行代码就可以搞定了,于是就将其加入到项目文件中。
我们直接将其引入:
require('libs/OrbitControls')
但是运行发现错误:
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
第一行粗暴的添加这行代码引入即可:
var THREE = require('three.min');
注:因为我没有对 three.js
做任何修改,所以直接引入了 minified 版本,如果您没有使用该版本,去掉 .min
即可。
然后代码中加入这一行就可以用了:
controls = new THREE.OrbitControls(camera);
至此没有出现什么问题,但是当想要交互的时候,一有动作就会发现屏幕被清空了。直觉告诉我是摄像机的座标或者旋转角度计算错了,经过跟踪,果然如此,在触摸屏幕并移动的时候,以下代码会出现问题:
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
,造成摄像机无法定位。我临时进行了如下修改:
rotateLeft( 2 * Math.PI * rotateDelta.x / window.innerWidth * scope.rotateSpeed ); rotateUp( 2 * Math.PI * rotateDelta.y / window.innerHeight * scope.rotateSpeed );
这只是临时的修改,后面有时间会尝试合理一些的解决方案。
不过呢,经过这样的修改以后,已经可以正常的通过手指对摄像机进行旋转,也可以用双指进行缩放了。
结束语
好了,今天的内容就到这里了。这并不是一篇教程,只是在目前信息和资料不完善情况下的一种尝试,也希望大家一起参与到开发和研究中来,互相交流。
欢迎加入我们的小组:
微信小游戏小组
indienova 小组 参与也欢迎加入我们的微信讨论群,目前已经超过 100 人,无法提供二维码了,可以找 indienova 的工作人员或者其它开发者邀请加入,也可以到小组去找人邀请。
源代码
为了方便大家参考,特提供完整源代码。
Github
源代码下载 代码其它相关链接
请先阅读:微信小游戏官方文档
目前,Cocos、Egret、Laya 已经完成了自身引擎及其工具对小游戏的适配和支持,访问对应的官方文档可以更快地接入小游戏的开发
真机加载不出来,请问是什么原因?JSON的问题吗?
@哈哈哈:请查看调试信息,找到问题原因
@eastecho:您好 我刚才在真机上也加载不出来黑屏状态,真机预览运行怎么查看调试呢?
@eastecho:下载您的源码总是报这个错是什么原因:
gameThirdScriptError
Uncaught TypeError: Cannot set property 'width' of undefined
TypeError: Cannot set property 'width' of undefined
at WebGLRenderer.setSize (https://servicewechat.qq.com/game.js:22016:25)
at new d (https://servicewechat.qq.com/game.js:46924:955)
at https://servicewechat.qq.com/game.js:46927:77
at require (:3:8056)
at https://servicewechat.qq.com/game.js:46928:10
使用
import * as THREE from 'libs/three.min'
window.THREE = THREE;
require('libs/OrbitControls')
或者
window.THREE = require('libs/three.min.js')
require('libs/OrbitControls')
的方式来定义全局的THREE, 这样就不需要修改 OrbitControls 文件了.
@Shxuai: @hippogaga: @陈文强15248590676: @大城小胖:求问那个载入模型一直报错:fail invalid url这个问题怎么解决?如何才能成功的用threejs在小游戏编辑器里载入模型?谢谢
博主试过加入阴影吗?在ide中没问题,但是开发环境中出现了shadow acne,推测可能是实机的webgl版本导致
为什么加载本地的模型总是报错呢?
代码:const model = 'models/indienova-logo.json
报错:request:fail invalid url "models/indienova-logo.json"
@Shxuai:同问,解决了吗。我加载本地文件报request:fail invalid url "xx.json"
@hippogaga:同问,这个问题解决了吗?
json解析错误 是什以原因
有两个问题请教一下:谢谢!
最近由 zqcolor 修改于:2018-06-09 06:22:171. 真机加载不出来,请问是什么原因?
gameThirdScriptError
Uncaught TypeError: Cannot set property 'width' of undefined
TypeError: Cannot set property 'width' of undefined
at WebGLRenderer.setSize (https://servicewechat.qq.com/game.js:22016:25)
at new d (https://servicewechat.qq.com/game.js:46924:955)
at https://servicewechat.qq.com/game.js:46927:77
at require (:3:8056)
at https://servicewechat.qq.com/game.js:46928:10
2. 为什么加载本地的模型总是报错呢?
代码:const model = 'models/indienova-logo.json
报错:request:fail invalid url "models/indienova-logo.json"
@zqcolor:我也碰到你的问题,请问您解决了吗
为什么加载本地的模型总是报错呢?
代码:const model = 'models/indienova-logo.json
报错:request:fail invalid url "models/indienova-logo.json"
你好,我按照您的教程已经成功加载出了模型,也可以真机运行,但是
three.js / utils / exporters / blender 这个文件没有了,麻烦您再发一份
先mark