Web全景图传统上用作街景视图,而< titlesplit >°全景图在带宽受限的条件下使用。它可以给用户一种身临其境的体验,通过简单的操作,他们可以自由地查看周围的物体。随着部分运营商王卡等免流量业务的推出,以及4G环境的普及,大流量应用逐渐得到推广。比如我们能不能把静态的、低流量的全景图片变成动态的直播全景视频?在一定的网速和带宽下是可以实现的。后面我们就来看看如何在web端实现全景视频。让我们先看一下示例gif:tl;dr;使用three.js实现全景技术UV贴图原理介绍3D坐标原理及移动控制Web陀螺仪介绍iv-panorama简单库介绍基于Three.js的全景视频是基于3D空间,而在Web中,可以实现的技术轻松触及3D空间的是WebGL。为了简单起见,这里直接使用Three.js库。具体工作原理是将正在播放的视频元素映射到纹理空间,通过UV贴图直接贴在一个球面上。简化代码为:letcamera=newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,1,1100);//添加相机camera.target=newTHREE.Vector3(0,0,0);//设置相机的观察位置通常在球体的中心scene=newTHREE.Scene();letgeometry=newTHREE.SphereBufferGeometry(400,60,60);//贴图时,让像素面向inward(非常重要)geometry.scale(-1,1,1);//传入视频VideoEle进行绘制vartexture=newTHREE.VideoTexture(videoElement);varmaterial=newTHREE.MeshBasicMaterial({map:texture});网格=新三。网格(几何、材质);场景。添加(网格);renderer=newTHREE.WebGLRenderer();renderer.setPixelRatio(window.devicePixelRatio);//画布比例renderer.setSize(window.innerWidth,window.innerHeight);container.appendChild(renderer.domElement);具体过程差不多就是上面的代码。上面代码中有两部分需要注意,一是相机的视野值,二是几何球体的相关参数设置。相机视野的具体代码为:letcamera=newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,1,1100);这里主要使用透视相机来模拟人眼的效果。要设置合适的视野效果,这里的范围也需要根据球体的直径来确定,一般是2*radius+100,反正只要大于球体的直径即可。几何球体的参数letgeometry=newTHREE.SphereBufferGeometry(400,60,60);//贴图时,让像素面向内(很重要)geometry.scale(-1,1,1);以上其实有两部分需要说明。sphere参数设置中有3个重要的属性值。API格式为:SphereBufferGeometry(radius,widthSegments,heightSegments,...)。raidus:设置球体的半径。半径越大,视频在画布上绘制的内容也会被放大。设置值合适。width/heightSegments:切片的个数,主要用于控制三角形切片在宽高两个维度上最多能细分为球体的个数。数字越大,纹理拼接的边角越清晰。但是也不是无限高,同时也有高性能损失。绘制几何体时,通过坐标变换使X轴的像素点朝内,这样用户就不会出现鼓胀放大的效果。具体代码为:geometry.scale(-1,1,1).上面的UV贴图只是对代码的简单介绍。如果只是为了应用,那么这就足够了。但是,如果后面遇到优化问题,不知道更底层或者更详细的内容,就会觉得别扭。在全景视频中,有两个非常重要的点:UVmapping3Dmovement这里主要探讨一下UVmapping的细节。UV映射的主要目的是将2D图像映射到3D对象。最经典的解释是:盒子是一个3D对象,就像添加到场景中的表面网络(“网格”)正方形。如果沿着边缝或折叠盒子可以通过切割标记在桌子上展开。当我们从上往下看桌子时,可以认为U是左右方向,V是上下方向。盒子上的图片是二维坐标。我们使用UV来代表“纹理坐标系”,而不是通常在三维空间中使用的XY。重新组装盒子时,纸板上的特定UV坐标会映射到盒子的空间(XYZ)位置。这就是2D图像包裹在3D对象上时计算机所做的事情。摘自浙江研报这里,我们将通过代码来详细解释。我们需要完成一个纹理,将下面的精灵粘贴到一个立方体上。从iefreer,我们首先将图像加载到纹理空间:varmaterial=newTHREE.MeshPhongMaterial({map:THREE.ImageUtils.loadTexture('images/texture-atlas.jpg')});所以,现在我们有了一个Thetexturespacearea:这个内容其实涉及到了WebGL的知识。纹理空间和物理空间不在一起。WebGL中的GLSL语法是通过相关规则将纹理内容映射到指定三角形区域的表面。这里需要注意的是,纹理空间中并没有所谓的最小三角形区域,这里只适配了物理空间中划分的三角形区域。为了简单起见,我们设置的boxGeometry只使用了单位为1的Segments,减少了需要划分的三角形数量。这样,需要粘贴的三角形区域就有12个。这里,我们需要使用Vector2来手动划分纹理空间的区域。其实在映射的时候,就是将物理空间的不动点和纹理空间的不动点一一映射,让纹理和物理空间相连。步骤走到一起。因为,Three.js中的geometry.faceVertexUvs在划分物理空间时,定义的面分解三角形的顺序是按照逆时针方向,按照序号划分的,如下图:上图中,我们可以得到每个几何对象的表面映射到纹理空间的坐标值,可以分为:left-bottom=[0,1,3]right-top=[1,2,3]所以,我们需要定义纹理坐标值:face1_left=[newTHREE.Vector2(0,0),newTHREE.Vector2(.5,0),newTHREE.Vector2(0,.333)]face1_right=[newTHREE.Vector2(.5,0),newTHREE.Vector2(.5,.333),newTHREE.Vector2(0,.333)]//...剩下的10个面都是定点UV贴图API。具体格式为:geometry.faceVertexUvs[0][faceIndex][vertexIndex],那么定义具体的面的映射为:geometry.faceVertexUvs[0][0]=face1_left;geometry.faceVertexUvs[0][0]=face1_right;//...还剩下10张脸。如果您编写过本机WebGL代码,则应该很容易理解UV映射的工作原理。3D移动原理这里需要注意的是Web全景不是WebVR。Panorama不具备VR的沉浸式体验。它只涉及三个维度的旋转,没有移动距离。上面的描述中提到了三维度和旋转角度这两个概念,很容易让我们联想到《高中数学》学习的一个坐标系——球坐标系(这里默认是右手坐标系)。φ为与z轴正方向的夹角<=180°?为与x轴正方向的夹角<=180°p为空间点到原点的直线距离计算公式为:现在,如果应用于Web全景图,我们可以知道几个已知条件:p:定义球体(SphereBufferGeometry)的半径Δφ:用户在y轴上移动的距离Δ?:用户在x轴上移动的距离p这是常数,Δφ和Δ?是由用户输入确定的尺寸值。这里需要一个算法来统一约定。算法控制的主要内容是:将用户手指在x/y平面轴上的Δx/Δy通过一定比例转换为Δφ/Δ?。如果考虑陀螺仪:用户的手指在x/y平面上轴上的Δx/Δy通过一定比例转换为Δφ/Δ?,旋转角度值Δφ'/Δ?'x/y轴上的用户结合视角计算结果。为了更广泛的兼容性,我们这里将根据第二种算法的描述进行说明。上面Δφ/Δ?的变化主要反映了我们视野的变化。在Threejs中,它用于控制相机的视野。那么我们在ThreeJS中如何控制视野呢?下面是最简单的代码:phi=THREE.Math.degToRad(90-lat);theta=THREE.Math.degToRad(-lon);camera.position.x=distance*Math.sin(phi)*Math.cos(theta);camera.position.y=distance*Math.cos(phi);camera.position.z=distance*Math.sin(phi)*Math.sin(theta);这里主要模拟地球坐标:lat代表维度(latitude):用户上下滑动改变的值,或者手机上下旋转改变的值lon代表经度(lontitude):用户左右滑动改变的值向右,或者手机左右旋转。一种是直接用手滑动,一种是根据陀螺仪旋转。简单来说就是监听touch和orientation事件,根据触发信息手动改变lat/lon的值。不过这里需要注意一点:纬度方向最多只能达到(-90,90),否则会造成屏幕翻转的效果,是非常糟糕的体验。下面通过代码来实践一下。添加touch来控制Web中Touch相关的事件,其实可以讲到崩溃为止,比如用户用几根手指触摸屏幕?用户在屏幕上的具体手势是什么(滑动、缩放)?这里,为了简单起见,我们仅使用手指滑动的距离作为摄像机视角移动的数据。具体代码为://为了增加博客的音量,完整版可以在我的博客上查看:https://www.villainhr.comiv-panorama介绍iv-panorama是IVWEB团队,专门为全景直播热点播放器。现在Web对VR支持不是特别友好。不过对于全景视频来说,在机器换代的前提下,全景视频的性能瓶颈已经逐渐消失。其主要特点是:依赖Three.js,需要预挂载到window对象灵活配置,内置陀螺仪和触控支持。支持使用兼容React、jQuery(简编)的ES6语法动态调整敏感度参数项目地址:iv-panorama。该项目使用非常简单,有两种全景模式,一种用于图片,一种用于视频:importVRPlayerfrom'iv-panorama';newVRPlayer({player:{url:'/test/003.mp4'},容器:document.getElementById('container')});//imageletpanorama=newVRPlayer({image:{url:'./banner.png'},container:document.getElementById('container')});所有全景图资源已经放在github仓库中,有兴趣的可以在实践中观察。
