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

Posted 大帅老猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三种前端实现VR全景看房的方案,收藏吧说不定哪天就用得上相关的知识,希望对你有一定的参考价值。

前言

=====

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

image.png

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

2021-06-03 11_01_41.gif

会另写一篇文章教大家用threejs做这个[BMW在线DIY],感兴趣的小伙伴请关注我吧~

方案一: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,我们非常容易添加鼠标点击交互等效果

![图片](https://mmbiz.qpic.cn/mmbiz_png/t1ynS50Irh3H6sn2Pc31b8LLcjL2Ht5ZoZiaHPARu2sZK6j80sU6cON6FlsmeicUVCT1MXH939IfolSwpXwIYZibQ/640?wx_fmt=png)

image.png

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

![图片](https://mmbiz.qpic.cn/mmbiz_png/t1ynS50Irh3H6sn2Pc31b8LLcjL2Ht5ZzSdsibZk0RFGWeeIAtkhBp0d7Vw5UZibSOQCKt4RymZOvj9U8NL56QoA/640?wx_fmt=png)

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();


需求升级了!
======

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

*   **全景图质量需要更高,但加载速度不允许更慢**
    
*   **每个场景的信息点挺多的,坐标编辑太麻烦了**
    

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

![图片](https://mmbiz.qpic.cn/mmbiz_png/t1ynS50Irh3H6sn2Pc31b8LLcjL2Ht5ZuvWUIWrbxbxPic6eENNodMP4WEicexf8FVPyJvE1uPTBZrPdjzUoPCZA/640?wx_fmt=png)

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

![图片](https://mmbiz.qpic.cn/mmbiz_gif/t1ynS50Irh3H6sn2Pc31b8LLcjL2Ht5Zic1oKjJhuYVpDBhPOWYiaXYmuo2IVV5U78CyKCTkibUlgnbMlRYQI8u8A/640?wx_fmt=gif)

2021-06-14 23\\_31\\_28.gif

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

方案三:pano2vr
===========

![图片](https://mmbiz.qpic.cn/mmbiz_png/t1ynS50Irh3H6sn2Pc31b8LLcjL2Ht5Z3WzDvhFfhGYnFsSk0De26v1icBO2RUmDXyh2hjR0FNPRhNr2vS8xhBw/640?wx_fmt=png)

image.png

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

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

![图片](https://mmbiz.qpic.cn/mmbiz_png/t1ynS50Irh3H6sn2Pc31b8LLcjL2Ht5Z3OhqPFq0TuMjjdv8QFdIzSqt10YAM4wWI2D366NBpY9YKw2vAauA9g/640?wx_fmt=png)

image.png

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

![图片](https://mmbiz.qpic.cn/mmbiz_png/t1ynS50Irh3H6sn2Pc31b8LLcjL2Ht5Zy0tBacniaJPXAbELib4DibId7wELeeDxOzGNyBTL32qVhkf51PObkNAkQ/640?wx_fmt=png)

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=“images/hot.png”;
            hotsopt.div.firstChild.style.width = 207hotScale+“px”;
            hotsopt.div.firstChild.style.height = 162
hotScale+“px”;
            hotsopt.div.onmouseover = null;
            hotsopt.div.setAttribute(“ids”,ids);
            hotsopt.div.οnclick=function() 
                   //在这里可以响应信息点的点击事件啦
                   console.log(this.getAttribute(“ids”));
            ;
    
);


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

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

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

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

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

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

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

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

![图片](https://img-blog.csdnimg.cn/img_convert/e10d17c70a0e55f074f88a6ebe4ecfd3.png)

image.png

* * *

本故事纯属虚构,文末配图如有侵权,请联系我跟老板大哥喝一杯

查看本文配套视频教程

源码
==

微信搜索并关注“`大帅老猿`”,回复“`webvr`”获得本文中三种方案的实现源码

> 如果觉得我是个有趣的程序员,请关注我;如果觉得本文还不错,记得点赞收藏哦,说不定哪天就用得上!

VR样板房_VR全景看房_VR房地产综合营销方案

南宁市祖龙acmallAR楼书VR楼书是聚象科技针对祖龙acmall项目销售展示所设计的楼书。该楼书将AR(增强实现)VR(虚拟现实)等技术与销售流程相结合,突破了传统的图、文、视频等的介绍,更全面和详细的介绍项目的优势和卖点。AR/VR楼书以ipad或程序方式呈现,既方便销售人员的销售过程讲解,又可让投资者对未来祖龙acmall的发展有更直观的认识,增强投资者的信心,更体现了未来祖龙acmall对潮流科技的应用能力。

 

AR楼书,VR楼书,VR样板间

AR楼书,VR楼书,VR样板间

   聚象科技AR/VR综合房地产/样板间项目内容 

   1、 项目介绍。

   结合销售人员的销售话术,对项目进行图文并茂的展示。文字主要是项目概述,图片以项目动态效果图页面为主。

   2、项目区位图展示。结合项目区位介绍话术进行互动展示

   1交通情况展示:点击后动态展示交通情况:路网、公交、地铁。

   2 商圈展示:点击后用不同色块动态展示周边商圈。

   3 周边楼盘及居民人口分布情况:点击后用动态效果展示周边楼盘及居民人口分布情况。

   4 周边配套设施:点击后用动态效果展示周边配套。

 

AR楼书,VR楼书,VR样板间

AR楼书,VR楼书,VR样板间

 AR样板间项目展示

使用聚象科技AR样板间AR扫描功能扫描对应宣传图片或实体楼书展示 相应的AR内容。内容包含以下几类:

   1 AR视频展示。楼盘宣传视频或由效果图合成的楼盘视频。

   2 AR沙盘展示。用3D-AR的方式展示整个项目的三维立体沙

盘。

   3 AR样板间户型展示。用3D-AR的方式逐层展示项目楼盘户型与商

铺分布以及停车场的车位规划。

   4 VR展示

用720°VR 全景的方式展示商场内部热闹的场景。扫描二维码,可通过H5的方式分享到公众号和朋友圈。

   5置业计划工具

使用聚象科技AR/VR楼书辅助置业顾问快速计算及展示商铺的总价、首付、月供、利息、还款期数等等,一目了然的形成置业计划表。提高置业顾问的工作效率,减少客户等待时间,提高成交率。

以上是关于三种前端实现VR全景看房的方案,收藏吧说不定哪天就用得上的主要内容,如果未能解决你的问题,请参考以下文章

Three.js 实现VR看房

2017年VR全景大热 虚拟看房技术成主流

VR全景线上展示通过VR展示方式各行各业体验

纯CSS实现720全景?不用Three.js 也可以

THREE.JS实现看房自由(VR看房)

硬核看房利器——Web 全景的实现