• 微信小程序之threejs全景


    最近在开发小程序,身心疲惫,原因是功能和app相同,我裂开了。

    各种封装组件,各种写页面,不过有个好处是以前写的h5拿来改一下标签,基本上还是ok的,就剩下最后几个功能,其中就有一个VR全景功能。

    移动端倒是好做,上次做了大概2天就搞定了,原理就是threejs用css3做图片的旋转,具体例子可以参照https://threejs.org/examples/css3d_panorama.html不过多描述,下面进入今天的主角:在微信小程序中使用threejs实现VR全景功能。

    刚开始想到这个功能,我是拒绝的,这简直就是要了我的头发啊,没办法,谁叫我走上开发这条不归路呢,自己选的路,秃头也要走完。。

    那就硬着头皮开始吧,先百度搜了一下在小程序中使用threejs,找到一篇比较干货的文章https://developers.weixin.qq.com/community/develop/article/doc/00066c4b230b085051592292f5bc13,这篇文章作者把threejs给提炼出来了一个小程序版本,

    照着他的demo先把canvas给搞出来先。然后再实现全景,怎么实现也是头疼的事情,怎么,我不会写,还不会改吗?

    先看看以前h5的实现方式,采用CSS3DRenderer来实现,问题来了,小程序里面不支持dom的createElement,那咋整嘛,只有换思路了,继续研究threejs的demo,第一个版本思路出来了,说了太多废话,直接来代码了:

    <view style="height: 100%;  100%;">
      <canvas type="webgl" id="c" style=" 100%; height:100%;" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd" bindtouchcancel="touchCancel" bindlongtap="longTap" bindtap="tap"></canvas>
    </view>
    import * as THREE from '../../lib/threejs/three.weapp.min.js'
    import { OrbitControls } from '../../lib/threejs/OrbitControls'
    
    Page({
      data: {},
      onLoad: function () {
        wx.createSelectorQuery()
          .select('#c')
          .node()
          .exec((res) => {
            // 创建canvas对象
            const canvas = THREE.global.registerCanvas(res[0].node)
            // 记录canvas的id,好在page销毁的时候释放canvas
            this.setData({ canvasId: canvas._canvasId })
    
            const camera = new THREE.PerspectiveCamera(75, canvas.width / canvas.height, 1, 2000);
            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);
     
            camera.position.set(200, 200, 500);
            controls.update();
            const geometry = new THREE.SphereBufferGeometry( 500, 60, 40 ).toNonIndexed();
            geometry.scale( - 1, 1, 1 );
    
            var texture = new THREE.TextureLoader().load( 'http://www.yanhuangxueyuan.com/threejs/examples/textures/2294472375_24a3b8ef46_o.jpg' ); // canvas中文文档作者的图,侵删
            texture.minFilter = THREE.LinearFilter;
            texture.format = THREE.RGBFormat;
            var material = new THREE.MeshBasicMaterial( { map: texture } );
            const mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);
          
          
            function onWindowResize() {
              camera.aspect = window.innerWidth / window.innerHeight;
              camera.updateProjectionMatrix();
              renderer.setSize(canvas.width, canvas.height);
            }
            function render() {
              canvas.requestAnimationFrame(render);
              controls.update();
              renderer.render(scene, camera);
            }
    
            render()
    
          })
      },
      onUnload: function () {
        //  释放canvas
        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)
      }
    })

    嗨呀,以上代码我是看都看不懂,那咋办嘛,你挑的嘛偶像。莫有办法,只有百度查具体每个关键字的意思,这里也就不多讲了,因为我也不知道。这种方法有个问题就是,图片只支持一张的图片,而且这个图片是要用全景相机照出来的,限制比较多,怎么办嘛,肯定不能用这个方法呀,不然这个成本就没法估算了。

    于是乎我开始探索第二种方法,还是采用6张图的方法,还是原来的配方,还是熟悉的味道。话不多少,上代码:

    import * as THREE from './three.weapp.min.js'
    import { OrbitControls } from './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(75, canvas.width / canvas.height, 1, 2000);
            const scene = new THREE.Scene();
            const renderer = new THREE.WebGLRenderer({ antialias: true });
          
            const controls = new OrbitControls(camera, renderer.domElement);
            // 控制镜头缩放,这里禁用了,因为是用正方体做的 除非能解决正方体的大小问题
            controls.enableZoom = false
            camera.position.set(-0.1, 2, -5);
            controls.update();
    
            var sides = ['右.jpg', '左.jpg','上.jpg', '下.jpg','前.jpg', '后.jpg']
            var materials = [];
            for (var i = 0; i < sides.length; i++) {
              var side = sides[i];
              var texture = new THREE.TextureLoader().load(side);
              materials.push( new THREE.MeshBasicMaterial( { map: texture } ) );
            }
         // 这里物体的长宽高,我始终不知道该是多少
            var mesh = new THREE.Mesh( new THREE.BoxBufferGeometry( canvas.height, canvas.height, canvas.height ), materials );
            mesh.geometry.scale( -1, 1, 1 );
    
            scene.add(mesh);
          
          
            function onWindowResize() {
              camera.aspect = window.innerWidth / window.innerHeight;
              camera.updateProjectionMatrix();
              renderer.setSize(canvas.width, canvas.height);
            }
            function render() {
              canvas.requestAnimationFrame(render);
              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)
      }
    })

    这两种方法的区别就是,第二种采用6张图片(右左上下前后),6个面表示一个正方体,然后将视角拉到正方体内,就是一个全景效果,完美。

    这里的写法也是参照的https://github.com/mrdoob/three.js/blob/master/examples/webgl_panorama_cube.html,具体其中的参数,我也不太清楚,反正编程全靠试(猜)。

    贴下今天的成果吧:

    这是最开始完成第二种方法时的初次效果,当我看到这个效果的时候,我就知道已经差不多快ok了。

    这是最终实现的效果,哈哈还不错吧(勉强符合功能需求)

    距离上一次写博客,又过去了4个月,这4个月感觉过得是真的快,然而文章依然是这么水...(这也太水了吧)

    感谢threejs和https://developers.weixin.qq.com/community/develop/article/doc/00066c4b230b085051592292f5bc13文章的作者

  • 相关阅读:
    Backtrader中文笔记之CSV Data Feed Development-General
    Backtrader中文笔记之CSV Data Feed Filters
    Backtrader中文笔记之CSV Data Feed Development
    Backtrader中文笔记之Extending a Datafeed
    Backtrader中文笔记之Data Feeds
    discuz功能列表
    phpcms功能列表
    empireCMS 帝国cms功能总结
    ecshop功能目录
    织梦所有功能导航列表介绍
  • 原文地址:https://www.cnblogs.com/xuejiangjun/p/11815650.html
Copyright © 2020-2023  润新知