前言

事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现更多信息(视频,图文等)...

image.png

我第一反应是用3D引擎,因为我不久前刚用three.js做过一个BMW的在线展厅,基本把three.js摸熟了。

2021-06-03 11_01_41.gif

下面我介绍三种前端实现VR全景看房的方案:

方案一:WebGL3D引擎

使用3D引擎先搭一个基本的3D场景,下面的演示使用three.js,同类的3D引擎我还调研过babylon.js,playcanvas,使用都差不太多,学会一个基本都通的

var scene, camera, renderer;function initThree(){//场景scene = new THREE.Scene();//镜头camera = new THREE.PerspectiveCamera(90, document.body.clientWidth / document.body.clientHeight, 0.1, 100);camera.position.set(0, 0, 0.01);//渲染器renderer = new THREE.WebGLRenderer();renderer.setSize(document.body.clientWidth, document.body.clientHeight);document.getElementById("container").appendChild(renderer.domElement);//镜头控制器var controls = new THREE.OrbitControls(camera, renderer.domElement);//一会儿在这里添加3D物体loop();
}//帧同步重绘
function loop() {requestAnimationFrame(loop);renderer.render(scene, camera);
}window.onload = initThree;

现在我们能看到一个黑乎乎的世界,因为现在scene里什么都没有,接着我们要把三维物体放进去了,使用3D引擎的实现方式无非都是以下几种

使用立方体(box)实现

这种方式最容易理解,我们在一个房间里,看向天花板,地面,正面,左右两面,背面共计六面。我们把所有六个视角拍成照片就得到下面六张图

image.png

现在我们直接使用立方体(box)搭出这样一个房间

var materials = [];
//根据左右上下前后的顺序构建六个面的材质集
var texture_left = new THREE.TextureLoader().load( './images/scene_left.jpeg' );
materials.push( new THREE.MeshBasicMaterial( { map: texture_left} ) );var texture_right = new THREE.TextureLoader().load( './images/scene_right.jpeg' );
materials.push( new THREE.MeshBasicMaterial( { map: texture_right} ) );var texture_top = new THREE.TextureLoader().load( './images/scene_top.jpeg' );
materials.push( new THREE.MeshBasicMaterial( { map: texture_top} ) );var texture_bottom = new THREE.TextureLoader().load( './images/scene_bottom.jpeg' );
materials.push( new THREE.MeshBasicMaterial( { map: texture_bottom} ) );var texture_front = new THREE.TextureLoader().load( './images/scene_front.jpeg' );
materials.push( new THREE.MeshBasicMaterial( { map: texture_front} ) );var texture_back = new THREE.TextureLoader().load( './images/scene_back.jpeg' );
materials.push( new THREE.MeshBasicMaterial( { map: texture_back} ) );var box = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), materials );
scene.add(box);

2021-06-14 19_51_17.gif

好,现在我们把镜头camera(也就是人的视角),放到box内,并且让所有贴图向内翻转后,VR全景就实现了。

box.geometry.scale( 1, 1, -1 );

现在我们进入了这个盒子!!

2021-06-14 19_41_37.gif

threejs官方立方体全景示例

使用球体(sphere)实现

我们将房间360度球形范围内所有的光捕捉到一个图片上,再将这张图片展开为矩形,就能得到这样一张全景图片

image.png

var sphereGeometry = new THREE.SphereGeometry(/*半径*/1, /*垂直节点数量*/50, /*水平节点数量*/50);//节点数量越大,需要计算的三角形就越多,影响性能var sphere = new THREE.Mesh(sphereGeometry);
sphere.material.wireframe  = true;//用线框模式大家可以看得清楚是个球体而不是圆形
scene.add(sphere);

image.png

现在我们把这个全景图片贴到这个球体上

var texture = new THREE.TextureLoader().load('./images/scene.jpeg');
var sphereMaterial = new THREE.MeshBasicMaterial({map: texture});var sphere = new THREE.Mesh(sphereGeometry,sphereMaterial);
// sphere.material.wireframe  = true;

2021-06-14 14_54_38.gif

和之前一样,我们把镜头camera(也就是人的视角),放到球体内,并且让所有贴图向内翻转后,VR全景就实现了

现在我们进入了这个球体!!

var sphereGeometry = new THREE.SphereGeometry(/*半径*/1, 50, 50);
sphereGeometry.scale(1, 1, -1);

2021-06-14 15_15_28.gif

threejs官方球体全景示例

添加信息点

在VR全景中,我们需要放置一些信息点,用户点击之后做一些动作。

现在我们建立这样一个点的数组

var hotPoints=[{position:{x:0,y:0,z:-0.2},detail:{"title":"信息点1"}},{position:{x:-0.2,y:-0.05,z:0.2},detail:{"title":"信息点2"}}
];

遍历这个数组,并将信息点的指示图添加到3D场景中

var pointTexture = new THREE.TextureLoader().load('images/hot.png');
var material = new THREE.SpriteMaterial( { map: pointTexture} );for(var i=0;i<hotPoints.length;i++){var sprite = new THREE.Sprite( material );sprite.scale.set( 0.1, 0.1, 0.1 );sprite.position.set( hotPoints[i].position.x, hotPoints[i].position.y, hotPoints[i].position.z );scene.add( sprite );
}

看到HOT指示图了吗?

2021-06-14 20_22_12.gif

添加点击事件,首先将全部的sprite放到一个数组里

sprite.detail = hotPoints[i].detail;
poiObjects.push(sprite);

然后我们通过射线检测(raycast),就像是镜头中心向鼠标所点击的方向发射出一颗子弹,去检查这个子弹最终会打中哪些物体。

2021-06-15 01_35_14.gif

document.querySelector("#container").addEventListener("click",function(event){event.preventDefault();var raycaster = new THREE.Raycaster();var mouse = new THREE.Vector2();mouse.x = ( event.clientX / document.body.clientWidth ) * 2 - 1;mouse.y = - ( event.clientY / document.body.clientHeight ) * 2 + 1;raycaster.setFromCamera( mouse, camera );var intersects = raycaster.intersectObjects( poiObjects );if(intersects.length>0){alert("点击了热点"+intersects[0].object.detail.title);}
});

方案二:CSS3D

threejs等3d引擎太强大了,这些引擎的代码量都有大几百K,在今天的网速下显得无所谓,但在几年前我接到需求时仍然是重要的考量因素。既然我们只用到3D引擎的一点点功能,那么能否找到一个更加轻量的3D引擎呢。

有!css3d-engine,这个3d引擎只有14kb,并且在多个大牌商业项目中应用

  • 淘宝造物节 https://shrek.imdevsh.com/show/zwj/

  • adidas绝不凋谢 https://shrek.imdevsh.com/show/drose/

  • adidas胜势全开 https://shrek.imdevsh.com/show/bbcny/

  • adidas绝不跟随 https://shrek.imdevsh.com/show/crazylight/

使用skybox实现

window.onload=initCSS3D;function initCSS3D(){var s = new C3D.Stage();s.size(window.innerWidth, window.innerHeight).update();document.getElementById('container').appendChild(s.el);var box = new C3D.Skybox();box.size(954).position(0, 0, 0).material({front: {image: "images/scene_front.jpeg"},back: {image: "images/scene_back.jpeg"},left: {image: "images/scene_right.jpeg"},right: {image: "images/scene_left.jpeg"},up: {image: "images/scene_top.jpeg"},down: {image: "images/scene_bottom.jpeg"},}).update();s.addChild(box);function loop() {angleX += (curMouseX - lastMouseX + lastAngleX - angleX) * 0.3;angleY += (curMouseY - lastMouseY + lastAngleY - angleY) * 0.3;s.camera.rotation(angleY, -angleX, 0).updateT();requestAnimationFrame(loop);}loop();var lastMouseX = 0;var lastMouseY = 0;var curMouseX = 0;var curMouseY = 0;var lastAngleX = 0;var lastAngleY = 0;var angleX = 0;var angleY = 0;document.addEventListener("mousedown", mouseDownHandler);document.addEventListener("mouseup", mouseUpHandler);function mouseDownHandler(evt) {lastMouseX = curMouseX = evt.pageX;lastMouseY = curMouseY = evt.pageY;lastAngleX = angleX;lastAngleY = angleY;document.addEventListener("mousemove", mouseMoveHandler);}function mouseMoveHandler(evt) {curMouseX = evt.pageX;curMouseY = evt.pageY;}function mouseUpHandler(evt) {curMouseX = evt.pageX;curMouseY = evt.pageY;document.removeEventListener("mousemove", mouseMoveHandler);}
}

方案二的好处除了库很小以外,还是div+css来搭建三维场景的。但这个库的作者几乎不维护,遇到问题必须得自己想办法解决,比如使用在电脑上会看到明显的面片边缘

image.png

但是在手机上浏览的话表现还是相当完美的

2021-06-14 22_20_26.gif

添加信息点

我们继续为它添加可交互的信息点

var hotPoints=[{position:{x:0,y:0,z:-476},detail:{"title":"信息点1"}},{position:{x:0,y:0,z:476},detail:{"title":"信息点2"}}
];
function initPoints(){var poiObjects = [];for(var i=0;i<hotPoints.length;i++){var _p = new C3D.Plane();_p.size(207, 162).position(hotPoints[i].position.x,hotPoints[i].position.y,hotPoints[i].position.z).material({image: "images/hot.png",repeat: 'no-repeat',bothsides: true,//注意这个两面贴图的属性}).update();s.addChild(_p);_p.el.detail = hotPoints[i].detail;_p.on("click",function(e){console.log(e.target.detail.title);})}
}

这样就可以显示信息点了,并且由于是div,我们非常容易添加鼠标点击交互等效果

image.png

不过,bothsides属性为true时,背面的信息点图片是反的。

image.png

所以我们这里要做一点处理,根据其与相机的夹角重置一下信息点的旋转角度。(如果是那种怎么旋转都无所谓的图片,比如圆点则无需处理

var r = Math.atan2(hotPoints[i].position.z-0,0-0) * 180 / Math.PI+90;
_p.size(207, 162).position(hotPoints[i].position.x,hotPoints[i].position.y,hotPoints[i].position.z).material({image: "images/hot.png",repeat: 'no-repeat',bothsides: false,}).update();

需求升级了!

以上两个方案,我以为可以给客户交差了。但客户又提出了一些想法

  • 全景图质量需要更高,但加载速度不允许更慢

  • 每个场景的信息点挺多的,坐标编辑太麻烦了

当时我心里想,总共才收你万把块钱,难不成还得给你定制个引擎,再做个可视化编辑器?

直到客户发过来一个参考链接,我看完惊呆了,全景图非常清晰,但首次加载速度极快,像百度地图一样,是一块块从模糊到清晰被加载出来的。

2021-06-14 23_31_28.gif

通过检查参考链接网页的代码,发现了方案三

方案三:pano2vr

image.png

pano2vr是一款所见即所得的全景VR制作软件(正版149欧元),功能挺强大的,可以直接输出成HTML5静态网页,体验非常不错。

而其核心库pano2vr_player.js代码量也只有238kb

image.png

我们可以直接使用这个软件来可视化的添加信息点,输出成HTML5后,除了静态图片以外,所有配置信息都在这个pano.xml文件里

image.png

修改信息点图片

整体的交互体验都非常好,但默认的信息点样式不喜欢,我们可以通过下面的代码来修改信息点图片

pano.readConfigUrlAsync("pano.xml",()=>{var pois=pano.getPointHotspotIds();var hotScale = 0.2;for(var i=0;i<pois.length;i++){var ids=pois[i];var hotsopt=pano.getHotspot(ids);hotsopt.div.firstChild.src="data:images/hot.png";hotsopt.div.firstChild.style.width = 207*hotScale+"px";hotsopt.div.firstChild.style.height = 162*hotScale+"px";hotsopt.div.onmouseover = null;hotsopt.div.setAttribute("ids",ids);hotsopt.div.onclick=function() {//在这里可以响应信息点的点击事件啦console.log(this.getAttribute("ids"));};}
});

哈哈,没想到最终的方案不仅极其简单的就实现了体验良好的VR全景,还附送了非常方便的信息点编辑。除去第一次开发的耗时,以后再制作新的VR场景也就是花个10分钟即可搞定。

但想到外包工头经常压榨我的报价,压缩我的工期,无理变更需求

收到工程款的时候他请我去K歌,坐在KTV的包间里我没有告诉他使用pano2vr的事,而是对他说

每个VR场景的信息点都要花1天时间编辑

每制作一个新的VR场景,你收品牌方8k

我每个场景收你3k,你躺赚5k

毕竟咱们老朋友了,我够意思吧

他豪爽的干掉手中的啤酒说:“好兄弟,我给你唱一首!”

image.png


本故事纯属虚构,文末配图如有侵权,请联系我跟老板大哥喝一杯。(本人转载的文章哈)

三种前端实现VR全景看房的方案!说不定哪天就用得上!(收藏)相关推荐

  1. 三种前端实现VR全景看房的方案,收藏吧说不定哪天就用得上

    前言 ===== 事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现 ...

  2. 三种前端实现VR全景看房的方案!

    前言 事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现更多信息(视 ...

  3. 三种前端实现VR全景看房的方案!说不定哪天就用得上!

    前言 事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现更多信息(视 ...

  4. vr全景看房的方案 three.js

    WebGL3D引擎 http://www.webgl3d.cn/threejs/docs/#api/zh/core/Raycaster 一.客户端,加载六张图及按钮位置,点击按钮删除旧的图及按钮,加载 ...

  5. VR全景看房的具体优势有哪些

    "从西走到东.看房累断腿"."开车3小时,看房8分钟"......无论您是买房还是租房,都可能面临时间不够.交通不便.房源真实性等因素,让原本兴奋的看房行动,变 ...

  6. VR全景看房线上3D住宅商品房鉴赏

    VR全景看房又称:VR看房.360度/720度全景VR看房.全景3D数字沙盘.3D建模全景看房等等,其实都是全景看房."VR三维全景"是一种可以创建和体验虚拟VR三维空间的计算机3 ...

  7. VR全景说:VR全景看房新体验?如何玩儿转VR房产

    近年来,新型技术可谓是层出不穷(VR全景.AI.大数据等),其中最受人们期待,也大有发展前景的就数VR技术了,为什么这么说呢? 因为VR在经历了2016年的高热度后,VR种类更是层出不穷,如VR游戏. ...

  8. vr全景看房是怎么做的?vr全景看房平台有哪些?

    随着互联网时代的迅速发展,如今VR技术已经渗透到了各行各业,房地产行业也不例外.VR全景看房在房地产行业中普遍使用,VR技术的出现,帮助房产行业打开"新世界的大门",让购房者进入一 ...

  9. 3d怎么把两个面拼接在一起_vr全景看房用什么软件做的?3D看房是怎么拍摄的?...

    以往"看房跑断腿"的时代在vr全景看房出现后就得到了很大的解决,如今疫情和"宅经济"的双重影响下,各行各业不得不寻求线上转型:而vr全景对于房地产等行业便是一个 ...

最新文章

  1. html+css3实现二级下拉菜单
  2. Node.js开发环境的搭建
  3. python学习之subprocess模块
  4. SAP CRM one order三层内存模型
  5. centos编译mysql5.6_centos7上编译安装mysql5.6
  6. android 断点续录,android 录音的断点续传
  7. (28)Verilog HDL循环语句:for
  8. Vijos P1597 2的幂次方【进制+递归】
  9. linux标准输入/输出/错误
  10. 优先队列及BFS应用
  11. java sql 工具类_Java防SQL注入工具类
  12. baiduexporter+Aria在Chrome最新版上的尝试(2020.07)
  13. 使用计算机自带的wifi,电脑的自带无线网卡你知道怎么用吗?赶紧学习一下
  14. 从零开始免费搭建自己的博客(七)——迁移 CSDN 博客到个人博客站点
  15. idea中编译DataSphereStudio编译方法及问题排查
  16. 安装linux+windows双系统后无法进入Windows
  17. 股票交易原则与成交顺序
  18. Linux 如何查看内存使用情况
  19. Auto CAD使用快捷键
  20. 618还是购书才最实在

热门文章

  1. 居家办公竟比去公司上班还累?
  2. 【C语言】判断回文字符串
  3. idea 提示Cannot find declaration to go to的解决方法
  4. Android 添加中文medium字体
  5. BP神经网络如何用历史数据预测未来数据
  6. 计算机防勒索病毒之系统主机加固篇
  7. 中介者模式与观察者模式
  8. Kaggle座头鲸识别top5解决方案
  9. LeetCode1207.独一无二的出现次数(Java+两种方法)
  10. 常见的IO模型_晏无心_新浪博客