- webgl绘制纹理,Android显示正常,IOS黑屏
想请教一个问题:我现在在做微信小游戏不依赖引擎绘制首屏,第一种方案:使用canvas2d绘制首屏,Android和IOS都能绘制出来,但是因为引擎(creator)使用webgl渲染模式导致合入游戏逻辑后引擎初始化失败,所以放弃了这种方案。第二种方案:使用webgl绘制首屏,引擎能正常初始化,游戏逻辑正常启动,但是有一个问题:webgl绘制的首屏在真机Android上正常显示,真机IOS显示不出,控制台也没有报错。 [图片][图片]
2020-06-19 - texImage2D API在iphone 7 plug 上显示不正确
- 当前 Bug 的表现(可附上截图) 在iphone plug机型上显示的颜色不正确,其它iphone机型都正确 - 预期表现 显示正确 - 复现路径 加载RGBA32格式的bmp数据,用texImage2D提交至显卡,即可复现 - 提供一个最简复现 Demo
2019-03-05 - 基于 WebGL实现自定义栅格图层踩坑实录
以下内容转载自totoro的文章《WebGL-Y轴翻转踩坑实录》 作者:totoro 链接:https://blog.totoroxiao.com/webgl-flipY/ 来源:https://blog.totoroxiao.com/ 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 前言 自定义栅格图层 是指用户可以通过特定软件,将自定义的图像按照上文所述的方式切割为瓦片,并生成图片,然后按照瓦片坐标拼接形成地图的图层。常用于手绘地图、卫星图、地形图等。 案例背景 基于 WebGL 的地图渲染API,实现自定义栅格图层(将地图切分为等大的正方形,并以图片进行拼接渲染)时,为了节省纹理上传的开销,将栅格瓦片集中绘制到一张纹理上,然后绘制时根据瓦片各自的纹理坐标取各自的纹理,大概示意图如下: [图片] 瓦片根据加载的先后顺序依次排列绘制到大纹理上,占位宽度一致,竖向排列。比如若瓦片大小为256px,那么瓦片1的位置为[代码]{x:0, y:0}[代码], 瓦片2的位置为[代码]{x:0, y:256}[代码]。 然后出现了一系列问题: 瓦片错乱:瓦片1的位置显示了瓦片4的内容; 瓦片内容倒置。 问题分析 根据调试定位,发现问题的根源在于Y轴翻转。 问题1: Y轴翻转是什么?为什么要翻转? 先看看没有任何处理的情况下如何绘制纹理,我们绘制瓦片的基本顶点模型是一个中心在原点的正方形,对于每个顶点坐标,需要映射到一个纹理坐标(下图左),传给片元着色器,再使用 [代码]texture2D()[代码] 取纹理像素,这种情况下左上角顶点[代码](-1,1)[代码]对应的纹理坐标为[代码](0,0)[代码]。 [图片] 纹理坐标系与顶点坐标系的Y轴方向不同,进行坐标映射的时候会不方便,所以如果将纹理坐标系的Y轴翻转则能使坐标映射更容易(上图右)。 WebGL 也提供了相应接口实现该功能, [代码]WebGLRenderingContext.pixelStorei()[代码] 是 WebGL 中用于描述像素存储模式的函数,其中 [代码]UNPACK_FLIP_Y_WEBGL[代码] 可以用于设置Y轴是否翻转: [代码]// 1表示翻转,0表示不翻转 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); [代码] 问题2: 为什么Y轴翻转会导致瓦片错乱呢? 如上文所述,首先需要通过 texImage2D 创建一个大纹理,然后使用 texSubImage2D 将瓦片绘制到大纹理上: [代码]// x, y 表示偏移量 gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, image); [代码] 这个接口用于改变纹理中指定子区域的数据,可以类比于 [代码]CanvasRenderingContext2D.drawImage()[代码] ,我们平常使用[代码]drawImage[代码] 时都是以左上角为原点进行偏移,所以想象中的大纹理是如下图所示的那样,瓦片1的左上角对应纹理坐标[代码](0, 1)[代码],左下角为[代码](0, 0.75)[代码],以此类推。 [图片] 但实际上Y轴翻转并不只作用在片元着色器的纹理中,使用 [代码]texImage2D[代码] 创建大纹理时其像素存储模式就已经确定了,当执行[代码]texSubImage2D[代码]时也会对[代码]image[代码]的像素存储位置进行反转,其执行过程是这样: [图片] 所以实际上大纹理应该长如下这样: [图片] 所以当使用纹理坐标左上角[代码](0, 1)[代码]+左下角[代码](0, 0.75)[代码]时,我们取到的是瓦片4的纹理,最终导致了瓦片错乱。 问题3: 为什么瓦片会倒置? 正确取得纹理坐标后,又出现了新的问题: [图片] 瓦片在屏幕上显示出来是上下颠倒的,且这种情况只出现在chrome/firefox里,因为在这两个浏览器中我们使用了 [代码]createImageBitmap[代码] 将blob格式的图片转为了位图,而在safari浏览器(不支持 [代码]createImageBitmap[代码])中我们将blob格式转为了[代码]Image[代码] 对象,最终导致了这种差异,所以我们从[代码]ImageBitmap[代码] 着手去定位问题原因。 [代码]ImageBitmap[代码]表示位图图像,用于在canvas中绘制图像,相比较于[代码]Image[代码] 其延迟较低,因为在执行[代码]texSubImage2D[代码] 将[代码]Image[代码] 绘制到纹理上时也会先将其转为[代码]ImageBitmap[代码]: 不论是在 canvas 里绘制2d图像,还是在 WebGL 中创建纹理,当使用图像时浏览器会把图像做一次解码(decode)处理。这个解码也就是把图像的原始格式(比如 jpeg、png 等)统一转换为位图,即每个像素使用 RGB 或 RGBA 来描述。当图片尺寸比较大的时候,解码也会有一定的消耗,而且这个耗时是同步的。——《高性能 WebGL —— 使用 ImageBitmap 提升纹理性能》(http://www.jiazhengblog.com/blog/2019/03/24/3407/) 同时 WebGL 规范里对 [代码]ImageBitmap[代码] 有一些特殊的描述,当介绍 pixelStorei 的三个参数:[代码]UNPACK_FLIP_Y_WEBGL[代码]、[代码]UNPACK_PREMULTIPLY_ALPHA_WEBGL、UNPACK_COLORSPACE_CONVERSION_WEBGL[代码]时,明确说明了其对[代码]ImageBitmap[代码] 无效,只能在创建 [代码]ImageBitmap[代码] 的时候就进行相应设置: If the TexImageSource is an ImageBitmap, then these three parameters will be ignored. Instead the equivalent ImageBitmapOptions should be used to create an ImageBitmap with the desired format. 所以可以大胆猜测,[代码]pixelStorei[代码] 所指定的像素存储模式其实作用于将图像解码转为位图的预处理过程。当我们直接将位图绘制到纹理上时就没有这个预处理过程了,所以[代码]UNPACK_FLIP_Y_WEBGL[代码] 参数失效了。 小结 [代码]UNPACK_FLIP_Y_WEBGL[代码] 参数用于设置纹理像素存储模式中是否将Y轴翻转,翻不翻取决于你的顶点模型的坐标系方向,适合自己就好。在我们的应用场景里,顶点模型和图像坐标系是反的,所以需要将该参数设为1。 使用 [代码]texSubImage2D[代码] 上传图片时同样受到[代码]UNPACK_FLIP_Y_WEBGL[代码] 参数的影响。 如果上传的图像是[代码]ImageBitmap[代码]对象,则在其创建时可通过 [代码]ImageBitmapOptions[代码]中的 [代码]imageOrientation[代码]、[代码]premultiplyAlpha[代码]、[代码]colorSpaceConversion[代码] 三个参数让其与[代码]pixelStorei[代码] 中所设置的参数保持一致。 最终使用自定义栅格图层实现手绘图叠加到地图上,完成效果如下: [图片] 产品推广 目前我们腾讯位置服务已经支持个性化图层使用,如需接入请查看:个性化图层编辑平台,更多示例与开发文档,您也可以官网搜索个性化图层查看!!!
2020-07-06 - 使用webgl开发微信小游戏绘制开放域解决方案
写在前面的话 在开发微信小游戏时,如果使用 [代码]webgl[代码] 的绘图方式,在绘制开放域画布 [代码]sharedCanvas[代码] 时,由于开放域只能绘制到上屏 [代码]canvas[代码] 中且主域无法得知开放域状态的限制,通常的做法是将 [代码]sharedCanvas[代码] 转成 [代码]texImage2D[代码] 绘制到上屏 [代码]canvas[代码] 中然后不停的绘制,然而 [代码]texImage2D[代码] 转换是通过CPU提交数据交由GPU进行计算,不停的提交会导致CPU过高,对于经验不足的人来说,性能会很差。 思路 我的做法是反其道而行,上屏 [代码]canvas[代码] 还是使用 [代码]2d[代码] 的方式进行绘制,游戏场景则使用离屏 [代码]canvas[代码] 绘制,这个离屏 [代码]canvas[代码] 使用 [代码]webgl[代码] 的方式,然后将这个离屏 [代码]canvas[代码] 绘制到上屏 [代码]canvas[代码] 中,[代码]canvas 2d[代码] 的 [代码]drawImage[代码] 方法可以直接将一个 [代码]canvas[代码] 当成图片进行绘制,[代码]sharedCanvas[代码] 也可以通过 [代码]drawImage[代码] 方法绘制到上屏 [代码]canvas[代码] 中去了。 这样可以免去很多复杂的转换,轻松的将开放域画布 [代码]sharedCanvas[代码] 绘制到上屏 [代码]canvas[代码] 中去了,还可以绘制游戏中用到的其他的 [代码]2d[代码] 元素。 小提示:目前这种做法在 [代码]Android[代码] 中存在BUG,无法正确的绘制,微信小游戏团队正在修复这个问题,目前已经内测通过,下一个 [代码]Android[代码] 版微信将会修复。 2019年2月20日更新 在 [代码]Android[代码] 版微信7.0.3客户端中已经修复了无法正确绘制的BUG,可以尽情玩耍了。
2019-02-20 - texImage2D接口在部分IOS机型上表现不正常
- 当前 Bug 的表现(可附上截图) 在iphone7 plus 或 iphone8 plus 上可复现,使用texImage2D接口中void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ArrayBufferView? pixels)接口时,贴图颜色会出现问题,只有R通道有值并且值不正确,format类型为RGBA,type为unsigned_byte。下图情况是贴图使用了全白的数据,但在iphone8 plus上贴图颜色表现错误。 [图片] [图片] - 预期表现 [图片][图片][图片][图片] [图片] - 提供一个最简复现 Demo layabox源码,3d示例项目,把laya.d3.js文件中37224行代码由递交Image贴图改成递交Unit8Array颜色数据,数据全部为255. 部分代码片段 var testData=new Uint8Array(16*4); for(var testI = 0; testI<16;++testI) { testData[testI*4]=255; testData[testI*4+1]=255; testData[testI*4+2]=255; testData[testI*4+3]=255; } gl.texImage2D(this._type,0,/*WebGLContext.RGBA*/0x1908,4,4,0,/*WebGLContext.RGBA*/0x1908,/*WebGLContext.UNSIGNED_BYTE*/0x1401,testData);
2019-03-05 - canvas type=webgl在iOS下使用canvas.toDataURL() 无法获取到图像
canvas type=webgl 在iOS 真机下使用canvas.toDataURL() 无法获取到图像。 Android 无问题。 请问官方何时能够解决? 在社区中也有看到反馈此问题,反馈此问题是9月份到现在都还无法修复?是否可以给一个具体修复时间,因为公司小程序急着上线。 也有查询到相关解决方案,使用 gl.readPixels 获取,但是不可取,获取到的内容太大,无法对内容进行处理。
2019-10-19 - webgl在iOS下使用canvas.toDataURL()获取URL不对?
我想保存canvas(type=webgl)上的内容为image并保存下来,使用canvas.toDataURL(),在模拟器和Android设备上都可以正常保存图片,在iOS设备上获取到的URL= ’data:‘,没有图片数据内容。 不知道这是系统原因还是使用时需要特别处理? 下面是我获取URL的代码: ``` gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }) let imgUrl = gl.canvas.toDataURL('image/jpeg', 0.5) // 压缩比只在模拟器上生效 ``` 请大神指点
2019-09-09 - webgl接口gl.readPixels获取的数据存在问题?
获取出来的数据和正常画面是上下颠倒的。 即使上一句代码执行了renderer.render(scene, camera),下一句代码立马进行gl.readPixels,有时候也会获取出纯透明无画面的数据。(后续测试情况:iOS上,当开启了抗锯齿antialias参数时,gl.readPixels读取的数据就100%是纯黑色透明。 当关闭了antialias参数时,gl.readPixels就没有问题,除了数据上下颠倒。Android完全没问题) 偶尔获取出来的数据有残缺。比如渲染了一张图,readPixels出来的数据显示,图的上半部分不见了,下半部分可见。【暂未找到100%复现的方法】
2019-12-17 - Canvas 在真机上 canvasPutImageData 的报错
- 当前 Bug 的表现(可附上截图) 在微信开发者工具中使用canvasPutImageData是能够正常使用的 到了真机模拟后就会报canvasPutImageData: invalid data format [图片] - 预期表现 [图片] - 复现路径 - 提供一个最简复现 Demo [图片]
2019-04-16 - 使用three.weapp.js加载全景天空盒并控制移动,在开发工具上没问题但是在真机上就报怎么办?
runtime.js?devtools_ignore=true:1 eval script evaluate_id #34 failed TypeError: Cannot set property 'ontouchstart' of undefined at eval ([publib]:1) at Array.forEach (<anonymous>) at eval ([publib]:1) at n ([publib]:1) at Object.m ([publib]:1) at Object.value [as subscribeHandler] (runtime.js?devtools_ignore=true:1) at eval (eval at c (runtime.js?devtools_ignore=true:1), <anonymous>:1:17) at eval (<anonymous>) at c (runtime.js?devtools_ignore=true:1) at w (runtime.js?devtools_ignore=true:1) 错误信息如上,不知道什么原因,求助各位大佬。
2019-12-02 - 怎么创建一个Offscreen的Image对象呢?
打算使用OffscreenCanvas做图片处理,但是不知道怎么创建Image对象。 比如我想把从相册里面选的图片拿出来做处理,要怎么样才能把图片转换成ArrayBuffer类型的pixels数据,或者转成ImageData类型? 求助!!!
2020-03-03 - Cannot set property 'ontouchstart' of undefined?
webgi 真机调试模式 Cannot set property 'ontouchstart' of undefined
2019-11-18 - OffscreenCanvas 如何生成 image,有createImage()方法吗
https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.createOffscreenCanvas.html ?
2020-08-18 - 小程序中Canvas和OffscreenCanvas理解?
Canvas对应的是Html中的 HTMLCanvasElement标签类型吗?OffscreenCanvas和Canvas 有什么区别?是什么关系?
2020-08-16 - [开盖即食]小程序图表插件 ECharts 实战
[图片] H5时代用来做图表的插件有很多比如:[代码]ECharts[代码]、[代码]Bizcharts[代码]、[代码]JSCharts[代码]等,而这次的小程序本人选用了 ECharts 作为图表组件。 1、选择原因主要有3点: 官方某度在持续维护这个插件 官方推出了直接适配小程序的版本,且有demo,开盖即食,不用迁移 简单实用,覆盖面广且可通过配置控制包的大小,小程序毕竟大小有限制~ eCharts来自BAT中的B前端团队,对应的小程序版本为:echarts-for-weixin 官网地址 https://echarts.apache.org/ github地址 https://github.com/ecomfe/echarts-for-weixin 小程序demo地址 https://github.com/ecomfe/echarts-examples 2、用法 (1)官方教程 [代码]index.json[代码] 配置如下: [代码]{ "usingComponents": { "ec-canvas": "../../ec-canvas/ec-canvas" } } [代码] 这一配置的作用是,允许我们在 [代码]pages/bar/index.wxml[代码] 中使用 [代码]<ec-canvas>[代码] 组件。注意路径的相对位置要写对,如果目录结构和本例相同,就应该像上面这样配置。 [代码]index.wxml[代码] 中创建了一个 [代码]<ec-canvas>[代码] 组件: [代码]<view class="container"> <ec-canvas id="mychart-dom-bar" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas> </view> [代码] 其中 [代码]ec[代码] 是一个我们在 [代码]index.js[代码] 中定义的对象,它使得图表能够在页面加载后被初始化并设置。 [代码]index.js[代码] 配置: [代码]function initChart(canvas, width, height, dpr) { const chart = echarts.init(canvas, null, { width: width, height: height, devicePixelRatio: dpr // 像素 }); canvas.setChart(chart); var option = { ... }; chart.setOption(option); return chart; } Page({ data: { ec: { onInit: initChart } } }); [代码] 这对于所有 ECharts 图表都是通用的,用户只需要修改上面 [代码]option[代码] 的内容,即可改变图表。[代码]option[代码] 的使用方法参见 ECharts 配置项文档。 官方demo里的一些用法指导: 如何延迟加载图表? 参见 [代码]pages/lazyLoad[代码] 的例子,可以在获取数据后再初始化数据。 如何在一个页面中加载多个图表? 参见 [代码]pages/multiCharts[代码] 的例子。 如何使用 Tooltip? 目前,本项目已支持 ECharts Tooltip,但是由于 ECharts 相关功能尚未发版,因此需要使用当前本项目中 [代码]ec-canvas/echarts.js[代码],这个文件包含了可以在微信中使用 Tooltip 的相关代码。目前在 ECharts 官网下载的 [代码]echarts.js[代码] 还不能直接替换使用,等 ECharts 正式发版后即可。 具体使用方法和 ECharts 相同,例子参见 [代码]pages/line/index.js[代码]。 如何保存为图片? 参见 [代码]pages/saveCanvas[代码] 的例子。 (2)本人实战操作 [图片] [代码]import * as echarts from '../ec-canvas/echarts'; const app = getApp(); let chart; function initChart(canvas, width, height, dpr) { chart = echarts.init(canvas, null, { width: width, height: height, devicePixelRatio: dpr // new }); canvas.setChart(chart); chart.setOption(option); return chart; } var option = { title: { text: '智酷君 echarts 切换效果测试', left: 'center' }, tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d}%)' }, legend: { orient: 'vertical', left: 10, data: ['AAA', 'BBB', 'CCC', 'DDD', 'EEE'] }, series: [ { name: '访问来源', type: 'pie', radius: ['50%', '70%'], avoidLabelOverlap: false, label: { show: false, position: 'center' }, emphasis: { label: { show: true, fontSize: '30', fontWeight: 'bold' } }, labelLine: { show: false }, data: [ {value: 335, name: 'AAA'}, {value: 310, name: 'BBB'}, {value: 234, name: 'CCC'}, {value: 135, name: 'DDD'}, {value: 1548, name: 'EEE'} ] } ] }; Page({ data: { ec: { onInit: initChart } }, onLoad: function () {}, //单曲线 line() { let option2 = { title: { text: '同一canvas更新成折线图', left: 'center' }, xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [{ data: [820, 932, 901, 934, 1290, 1330, 1320], type: 'line' }] }; chart.setOption(option2) }, //切换柱状图 bar(){ let option3 = { title: { text: '直接更新数据,减少性能消耗', left: 'center' }, xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: { type: 'value' }, series: [{ data: [120, 200, 150, 80, 70, 110, 130], type: 'bar', showBackground: true, backgroundStyle: { color: 'rgba(220, 220, 220, 0.8)' } }] }; chart.setOption(option3) } }) [代码] 建议大家尽量使用同一个canvas对象来切换不同的图表效果,而不是初始加载多个不同的,我们可以将 [代码]chart[代码] 对象设置为全局,然后通过 [代码]chart.setOption()[代码] 的方法来更新配置数据,可以减少性能消耗避免闪退等 (3)代码片段 代码段:https://developers.weixin.qq.com/s/OOTwnsms7Cin 建议将IDE工具升级到 1.02.18以上,避免一些BUG [图片] 3、Tips (1)包大小可以配置 在线定制地址: https://echarts.apache.org/zh/builder.html [图片] [图片] 通过选择和配置想要的功能,可以大大减少原本JS包的尺寸。 (2)Canvas 2d 版本要求 最新版的 ECharts 微信小程序支持微信 Canvas 2d,当用户的基础库版本 >= 2.9.0 且没有设置 [代码]force-use-old-canvas="true"[代码] 的情况下,使用新的 Canvas 2d(默认)。 使用新的 Canvas 2d 可以提升渲染性能,解决非同层渲染问题,强烈建议开启 如果仍需使用旧版 Canvas,使用方法如下: [代码]<ec-canvas id="xxx" canvas-id="xxx" ec="{{ ec }}" force-use-old-canvas="true"></ec-canvas> [代码] (3)数据点过多造成闪退和卡死 本人简单测试了下,iphone7p手机在[代码]1500个[代码]左右数据点的时候,出现了小程序闪退,iphoneX 测试下来大概在[代码]2500个[代码]左右,猜测可能由于微信本身给小程序的内存有限,所以建议大家控制数据点的个数 (4)单页面图表canvas加载过多卡死 建议单页面图表加载不要超过[代码]5个canvas[代码],尽可能共用一个图表Canvas对象,通过动态更新数据的方式来展示内容(还有帅气的特效),如果一定要加载多个canvas的话,建议控制数量,提供复用性~ 看完觉得有帮助记得点个赞哦~ 你的赞是我继续分享的最大动力!^-^
2020-06-29 - Worker中支持OffscreenCanvas吗
//Worker.js function testOffscreenCanvas(){ const canvas = new OffscreenCanvas(100, 100); const gl = canvas.getContext('webgl'); console.error(gl.texImage2D); const context = canvas.getContext('2d'); } Worker中支持OffscreenCanvas吗,或者能通过postMessage将wx.createCanvas()生成的离屏canvas传到worker中吗,又或者在主线程中支持canvas.transferControlToOffscreen()吗,最终目的就是将canvas的某些工作移到Worker中,有什么方案?
2020-03-19 - 小程序中如何动态创建动态创建canvas?
比如web中 this.canvas = document.createElement("canvas");
2020-08-15 - 在ios 13.4中,微信浏览器使用html2canvas无任何反馈
在ios 13.4系统微信浏览器中, npm html2canvas包有问题 html2canvas(shareContent as HTMLElement, opts).then(canvas => { // 无反馈 }).catch(_ => { // 无反馈 }) 在ios 非13.4系统微信浏览器中 html2canvas(shareContent as HTMLElement, opts).then(canvas => { // 有反馈 }).catch(_ => { // 有反馈 }) 因为有部分用户更新了ios 13.4, 我们定位到是这个问题。 希望ios 13.4微信浏览器中html2canvas正常运行
2020-03-26 - 小程序中使用three.js
小程序中使用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 目录中 欢迎提交PR和issue
2019-10-20 - 加急!小程序中,怎样动态创建标签
在原生的web开发中,我们可以通过操作dom在页面中创建一个html元素 那么在小程序的开发中,我们怎样动态在页面上创建标签呢? 目前的需求是,在点击的位置创建一个圆形标签。 请问具体如何实现? 尽量说详细一点,小弟是新手
2018-11-22 - OffscreenCanvas 什么时候可以用?
OffscreenCanvas 目前有部分文档接口,但是如何跟 Canvas 一起进行使用,并没有给出任何实例代码,并且接口部分并没有给出任何支持,这块不知道具体有什么规划?
2020-01-22