方案二:CSS3D
threejs
等3d引擎太强大了,这些引擎的代码量都有大几百K,在今天的网速下显得无所谓,但在几年前我接到需求时仍然是重要的考量因素。既然我们只用到3D引擎的一点点功能,那么能否找到一个更加轻量的3D引擎呢。
有!css3d-engine,这个3d引擎只有14kb
,并且在多个大牌商业项目中应用
- adidas绝不凋谢 shrek.imdevsh.com/show/drose/
- adidas胜势全开 shrek.imdevsh.com/show/bbcny/
- adidas绝不跟随 shrek.imdevsh.com/show/crazyl…
使用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来搭建三维场景的。但这个库的作者几乎不维护,遇到问题必须得自己想办法解决,比如使用在电脑上会看到明显的面片边缘
但是在手机上浏览的话表现还是相当完美的
添加信息点
我们继续为它添加可交互的信息点
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,我们非常容易添加鼠标点击交互等效果
不过,bothsides
属性为true时,背面的信息点图片是反的。
所以我们这里要做一点处理,根据其与相机的夹角重置一下信息点的旋转角度。(如果是那种怎么旋转都无所谓的图片,比如圆点则无需处理
)
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();
需求升级了!
以上两个方案,我以为可以给客户交差了。但客户又提出了一些想法
- 全景图质量需要更高,但加载速度不允许更慢
- 每个场景的信息点挺多的,坐标编辑太麻烦了
当时我心里想,总共才收你万把块钱,难不成还得给你定制个引擎,再做个可视化编辑器?
直到客户发过来一个参考链接,我看完惊呆了
,全景图非常清晰,但首次加载速度极快,像百度地图一样,是一块块从模糊到清晰被加载出来的。
通过检查参考链接网页的代码,发现了方案三
方案三:pano2vr
pano2vr是一款所见即所得的全景VR制作软件(正版149欧元),功能挺强大的,可以直接输出成HTML5静态网页,体验非常不错。
而其核心库pano2vr_player.js
代码量也只有238kb
。
我们可以直接使用这个软件来可视化的添加信息点,输出成HTML5后,除了静态图片以外,所有配置信息都在这个pano.xml
文件里
修改信息点图片
整体的交互体验都非常好,但默认的信息点样式不喜欢,我们可以通过下面的代码来修改信息点图片
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 = 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
毕竟咱们老朋友了,我够意思吧
他豪爽的干掉手中的啤酒说:“好兄弟,我给你唱一首!”